2012-03-20 53 views
1

我想从整体中选择满足某些条件的元素子集。大约有20个元素,每个元素都有多个属性。我想从一个属性的固定标准中选择五个元素提供最少差异的元素,并为另一个属性提供最高的平均值。根据标准选择和标识元素的子集

最后,我想将这个函数应用于多组20个元素。

到目前为止,我已经能够“手工”识别子集,但我希望能够返回值的索引以及返回值本身。

目标:

  1. 我想找到X1属于至少从一个固定值(55)有差异的该组的五个值的,并提供平均X2的最大值。

  2. 我想这样做多套。


##### generating example data 
##### this has five groups, each with two variables x1 and x2 
set.seed(271828) 

grp <- gl(5,20) 
x1 <- round(rnorm(100,45, 12), digits=0) 
x2 <- round(rbeta(100,2,4), digits = 2) 
id <- seq(1,100,1) 

##### this is how the data would arrive for me to analyze 
dat <- as.data.frame(cbind(id,grp,x1,x2)) 

的数据将到达在这种格式中,与id作为各元素的唯一标识符。


##### pulling out the first group for demonstration 
dat.grp.1 <- dat[ which(grp == 1), ] 

crit <- 55 
x <- t(combn(dat.grp.1$x1, 5)) 
y <- t(combn(dat.grp.1$x2, 5)) 

mean.x <- rowMeans(x) 
mean.y <- rowMeans(y) 
k <- (mean.x - crit)^2 

out <- cbind(x, mean.x, k, y, mean.y) 

##### finding the sets with the least amount of discrepancy 
pick <- out[ which(k == min(k)), ] 
pick 

##### finding the sets with low discrepancy and high values of y (means of X2) by "hand" 
sorted <- out[order(k), ] 
head(sorted, n=20) 

随着pick对于值,我可以看到,X1的值是:

> pick 
        mean.x k       mean.y 
[1,] 55 47 48 48 52  50 25 0.62 0.08 0.31 0.18 0.54 0.346 
[2,] 55 48 48 47 52  50 25 0.62 0.31 0.18 0.48 0.54 0.426 

我想这些元素返回id值,所以我知道我挑选元素:3,8,10,11和18(选择集合2,因为与k的差异相同,但是y的平均值很高ER)。

> dat.grp.1 
    id grp x1 x2 
1 1 1 45 0.12 
2 2 1 27 0.34 
3 3 1 55 0.62 
4 4 1 39 0.32 
5 5 1 41 0.18 
6 6 1 29 0.47 
7 7 1 47 0.08 
8 8 1 48 0.31 
9 9 1 35 0.48 
10 10 1 48 0.18 
11 11 1 47 0.48 
12 12 1 31 0.29 
13 13 1 39 0.15 
14 14 1 36 0.54 
15 15 1 36 0.20 
16 16 1 38 0.40 
17 17 1 30 0.31 
18 18 1 52 0.54 
19 19 1 44 0.37 
20 20 1 31 0.20 

这样做“手工操作”现在可行,但最好将其作为“解除手脚”。

任何帮助,非常感谢。

+1

您需要定义一个将两个标准组合成一个数字的函数。然后你可以开始考虑如何找到最佳的。 – Thierry 2012-03-20 16:37:20

回答

2

你几乎在那里。您可以将您的sorted定义修改为

sorted <- out[order(k, -mean.y), ] 

然后sorted[1,](或者,如果你喜欢sorted[1,,drop=FALSE])是你的选择集。

如果你想要的索引而不是/除了点,那么你可以提前包括。替换:

x <- t(combn(dat.grp.1$x1, 5)) 
y <- t(combn(dat.grp.1$x2, 5)) 

idx <- t(combn(1:nrow(dat.grp.1), 5)) 
x <- t(apply(idx, 1, function(i) {dat.grp.1[i,"x1"]})) 
y <- t(apply(idx, 1, function(i) {dat.grp.1[i,"x2"]})) 

out包括idx以后。

把INT一起:

##### pulling out the first group for demonstration 
dat.grp.1 <- dat[ which(grp == 1), ] 

crit <- 55 
idx <- t(combn(1:nrow(dat.grp.1), 5)) 
x <- t(apply(idx, 1, function(i) {dat.grp.1[i,"x1"]})) 
y <- t(apply(idx, 1, function(i) {dat.grp.1[i,"x2"]})) 

mean.x <- rowMeans(x) 
mean.y <- rowMeans(y) 
k <- (mean.x - crit)^2 

out <- cbind(idx, x, mean.x, k, y, mean.y) 

##### finding the sets with the least amount of discrepancy and among 
##### those the largest second mean 
pick <- out[order(k, -mean.y)[1],,drop=FALSE] 
pick 

其给出

        mean.x k       mean.y 
[1,] 3 8 10 11 18 55 48 48 47 52  50 25 0.62 0.31 0.18 0.48 0.54 0.426 

编辑:施加超过idx请求的描述;我想要更多的选择,而不仅仅是我可以在评论中做什么,所以我将它添加到我的答案中。还将解决循环子集。

idx是一个矩阵(15504 x 5),它的每一行都是数据帧的一组(5)索引。 apply允许通过逐行(逐行为边距1)对每行进行操作。有些东西是取值并使用它们来索引dat.grp.1的所需行并提取相应的x1值。我本可以写dat.grp.1[i,"x1"]作为dat.grp.1$x1[i]idx的每一行都成为一列,并且索引到dat.grp.1的结果是行,因此整个事情需要转置。

如果你喜欢,你可以将循环拆开,看看每一步如何工作。使函数成为非匿名函数。

f <- function(i) {dat.grp.1[i,"x1"]} 

,并在idx给它的时间通一行。

> f(idx[1,]) 
[1] 45 27 55 39 41 
> f(idx[2,]) 
[1] 45 27 55 39 29 
> f(idx[3,]) 
[1] 45 27 55 39 47 
> f(idx[4,]) 
[1] 45 27 55 39 48 

这些是得到捆绑到x

> head(x,4) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 45 27 55 39 41 
[2,] 45 27 55 39 29 
[3,] 45 27 55 39 47 
[4,] 45 27 55 39 48 

至于遍历子集,该plyr库是这个非常方便。您设置它的方式(将感兴趣的子集分配给一个变量并使用它)使变换变得容易。您为一个子集创建答案所做的每件事都会以该部分作为参数进入函数。

find.best.set <- function(dat.grp.1) { 
    crit <- 55 
    idx <- t(combn(1:nrow(dat.grp.1), 5)) 
    x <- t(apply(idx, 1, function(i) {dat.grp.1[i,"x1"]})) 
    y <- t(apply(idx, 1, function(i) {dat.grp.1[i,"x2"]})) 

    mean.x <- rowMeans(x) 
    mean.y <- rowMeans(y) 
    k <- (mean.x - crit)^2 

    out <- cbind(idx, x, mean.x, k, y, mean.y) 

    out[order(k, -mean.y)[1],,drop=FALSE] 
} 

这基本上是你以前的东西,但摆脱了一些不必要的任务。

现在将其包装在plyr调用中。

library("plyr") 
ddply(dat, .(grp), find.best.set) 

这给

grp V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 
1 1 3 8 10 11 18 55 48 48 47 52 50 25 0.62 0.31 0.18 0.48 0.54 0.426 
2 2 8 10 12 15 16 53 35 55 76 56 55 0 0.71 0.20 0.43 0.50 0.70 0.508 
3 3 4 10 15 17 20 47 48 73 55 52 55 0 0.67 0.54 0.28 0.42 0.31 0.444 
4 4 2 11 13 17 19 47 46 70 62 50 55 0 0.35 0.47 0.18 0.13 0.47 0.320 
5 5 3 6 10 17 19 72 40 58 66 39 55 0 0.33 0.42 0.32 0.32 0.51 0.380 

我不知道这是你的结果最好的格式,但它反映你给的例子。

+0

@ BrianDiggs这个很好。你能否在'apply'中描述一下使用'idx'的方法。我有困难缠绕它。任何关于在'grp'级别执行这个操作的想法? – 2012-03-20 17:21:30

+1

@blueandgrey,编辑以解决这些意见。 – 2012-03-20 17:46:36

+0

你,先生,是一个摇滚明星。感谢您的详细解释。非常说教。我没有足够的代表赞成,但有一天... – 2012-03-20 18:11:25