R 在 M 个集群中尽可能均匀地采样数据帧的 N 行(但在其中随机)
R sample N rows of a dataframe as evenly as possible across M clusters (but randomly within)
我有一个如下所示形式的数据框。这些病例已预先分为不同人群的亚组,包括单身人士。我正在尝试编写一些代码,这些代码将从数据框中采样(不替换)任何指定数量的行,但尽可能均匀地分布在集群中。
> 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
或类似包的优雅方法可以进行这种半随机抽样。无论哪种方式,我都在努力将这些元素联系在一起并解决问题。
策略:首先,您随机分配每个 cluster
中的顺序。该值存储在下面的 inside
变量中。接下来,您随机 select 每个集群的第一个选择的顺序,依此类推(outside
变量)。最后,您将数据框 select 排序为每个集群的第一个选择,然后是第二个,依此类推,打破与 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
现在,select搜索结果的前 n
行 data.frame 您将得到您正在寻找的样本。
Base R 选项:您可以从集群的唯一值中随机抽取样本,然后使用这些值随机抽取名称?不是很优雅,但可以在函数中定义。 N 是您要从 "cluster".
中抽取的样本数
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
这是一个可以为您进行采样的函数。首先,我创建了列表中唯一元素的索引,然后将它们打乱。然后我按其中的元素数量对列表进行排序,以便我可以为所有 类 均匀地间隔开。我必须用它制作一个长向量并选择我想要的元素。
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)
我有一个如下所示形式的数据框。这些病例已预先分为不同人群的亚组,包括单身人士。我正在尝试编写一些代码,这些代码将从数据框中采样(不替换)任何指定数量的行,但尽可能均匀地分布在集群中。
> 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
或类似包的优雅方法可以进行这种半随机抽样。无论哪种方式,我都在努力将这些元素联系在一起并解决问题。
策略:首先,您随机分配每个 cluster
中的顺序。该值存储在下面的 inside
变量中。接下来,您随机 select 每个集群的第一个选择的顺序,依此类推(outside
变量)。最后,您将数据框 select 排序为每个集群的第一个选择,然后是第二个,依此类推,打破与 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
现在,select搜索结果的前 n
行 data.frame 您将得到您正在寻找的样本。
Base R 选项:您可以从集群的唯一值中随机抽取样本,然后使用这些值随机抽取名称?不是很优雅,但可以在函数中定义。 N 是您要从 "cluster".
中抽取的样本数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
这是一个可以为您进行采样的函数。首先,我创建了列表中唯一元素的索引,然后将它们打乱。然后我按其中的元素数量对列表进行排序,以便我可以为所有 类 均匀地间隔开。我必须用它制作一个长向量并选择我想要的元素。
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)