2

我有一个如下所示形式的数据框。这些病例已预先分为不同人群的亚组,包括单身人士。我正在尝试编写一些代码,这些代码将从数据帧中采样(不替换)任何指定数量的行,但在集群中尽可能均匀地分布。

> testdata
   Cluster Name
1        1    A
2        1    B
3        1    C
4        2    D
5        3    E
6        3    F
7        3    G
8        3    H
9        4    I
10       5    J
11       5    K
12       5    L
13       5    M
14       5    N
15       6    O
16       7    P
17       7    Q

例如,如果我要求一个 3 行的样本,我想从随机的 3 个集群中抽取一个随机行(即不是每次第 1-3 行集群,尽管这是一个有效的结果)。

可接受的例子:

> testdata_subset
   Cluster Name
1        1    A
5        3    E
12       5    L 

> testdata_subset
   Cluster Name
6        3    F
14       5    N
15       6    O

不正确的例子:

> testdata_subset
   Cluster Name
6        3    F
8        3    H
13       5    M

同样的想法适用于示例数据中的样本大小为 7(每个集群 1 个)。对于更高的样本量,我想尽可能均匀地从每个集群中抽取,然后均匀地跨越具有未采样行的剩余集群,依此类推,直到指定的行数被采样。

我知道如何不加选择地对 N 行进行采样:

testdata[sample(nrow(testdata), N),]

但这不考虑集群。我还曾经plyr对每个集群随机抽样 N 行:

ddply(testdata,"Cluster", function(z) z[sample(nrow(z), N),])

但是,只要您要求的行数超过集群中的行数(即如果 N > 1),就会失败。然后我添加了一个 if/else 语句来开始处理它:

numsamp_per_cluster <- 2

ddply(testdata,"Cluster", function(z) if (numsamp_per_cluster > nrow(z)){z[sample(nrow(z), nrow(z)),]} else {z[sample(nrow(z), numsamp_per_cluster),]})

这有效地将要求的样本大小限制为每个集群的大小。但在这样做的过程中,它失去了对整体样本量的控制。我希望(但开始怀疑)有一种优雅的方法使用dplyr或类似的包可以进行这种半随机抽样。无论哪种方式,我都在努力将这些元素联系在一起并解决问题。

4

3 回答 3

1

策略:首先,您随机分配每个cluster. 该值存储在下面的inside变量中。接下来,您随机选择每个集群的第一个选择的顺序,依此类推(outside变量)。最后,您订购数据框,选择第一个选项,然后是每个集群的第二个选项,以此类推,打破与outside变量的联系。像这样的东西:

set.seed(1)
inside<-ave(seq_along(testdata$Cluster),testdata$Cluster,FUN=function(x) sample(length(x)))
outside<-ave(inside,inside,FUN=function(x) sample(seq_along(x)))
testdata[order(inside,outside),]   
#   Cluster Name
#10       5    J
#15       6    O
#4        2    D
#5        3    E
#9        4    I
#16       7    P
#1        1    A
#13       5    M
#3        1    C
#17       7    Q
#7        3    G
#6        3    F
#14       5    N
#2        1    B
#12       5    L
#8        3    H
#11       5    K

现在,选择结果 data.frame 的第一n行,您将获得您正在寻找的样本。

于 2016-10-21T15:22:02.037 回答
0

Base R 选项:您可以从集群的唯一值中随机抽样,然后使用这些值随机抽样名称?不是很优雅,但可以在函数中定义。N 是您要从“集群”中抽取的样本数。

sampler <- function(df,n){
  s <- sample(unique(df[,1]),n)
  n <- sapply(s, function(x) sample(df[which(df[,1]==x),2],1,replace=F))
  data.frame(cluster = s, name = n)
}

> sampler(testdata,6)
  cluster name
1       4    I
2       2    D
3       6    O
4       1    A
5       7    Q
6       5    K
于 2016-10-21T15:35:19.417 回答
0

这是一个将为您进行采样的函数。首先,我创建列表中唯一元素的索引,然后将它们打乱。然后我按其中元素的数量对列表进行排序,以便我可以均匀地分布在所有类中。我必须从中制作一个长向量并选择我想要的尽可能多的元素。

   sample_df=function(df,iter){
    l=unique(df$Cluster)
    cluster_pos=lapply(l, function(x) which(df$Cluster==x))
    random_cluster_pos=lapply(cluster_pos, function(x) if(length(x) > 1) { sample(x) } else x)
    ## index=random_cluster_pos[rev(order(sapply(random_cluster_pos, length)))]
    index=sample(random_cluster_pos)
    inde_pos=c(t(sapply(index, "[", 1:length(index))))
    inde_pos=inde_pos[!is.na(inde_pos)]
    return(df[inde_pos[1:iter],])
}
sample_df(testdata, 3)
于 2016-10-21T16:50:25.257 回答