在 r 中生成大量样本
Generating the large number of samples in r
我有一个 50 行 4 列的数据框。我想获得许多 12 行的样本数据帧可能是一百万个,我不希望我的两个样本数据帧相同。我使用了下面的代码
df_l <- list()
for(i in 1:6000000) {
set.seed(100+i)
a <- df[sample(nrow(df),12,replace=T),]
df_l[[i]] <- a
rownames(df_l[[i]]) <- 1:12
}
但我的困惑是这可能不是执行此操作的有效方法,我不知道两个样本数据帧是否相同。
您可以试试下面的代码:
- 采样时不放回
n <- nrow(df)
df_1 <- replicate(6000000,df[sample(n,12),],simplify = FALSE)
- 采样时有替换
n <- nrow(df)
df_1 <- replicate(6000000,df[sample(n,12,replace = TRUE),],simplify = FALSE)
关于相同数据帧的关注,这取决于您从中采样的 space 的大小。对于你的情况,
如果您不允许更换,您的 space 尺码是 choose(50,12)*factorial(12)
,比 6000000
大很多。因此,碰撞的可能性很小。
如果允许替换,你的space大小是50**12*factorial(12)
,比没有替换的场景还要大。这样碰撞的概率就会小很多。
是的,这不是很有效。
1) 您只需设置一次种子。
2) R 是一种解释型语言,在使用基本的分支函数(例如 if、for、while ...)或变量操作(例如 a <- a+1)时非常慢。对于只需要很短时间的功能,口译尤其要花费时间。
所以,你想调用一个同时做很多事情的函数,因为当声明时,它很快,因为它可能以更快的方式实现(它们通常是编译的)。
只需将 1:6000000 替换为 1:12 并采用 6000000 的样本向量,这将使您的程序 运行 更快。你只需要安排你如何安排数据。
3) 尝试 replicate
由于几个原因(如下所述),您正在尝试的方法相当慢,而且它还涉及大量数据重复,这通常效率不高。
首先,您正在使用循环来执行采样,这在 R 中通常很慢。尝试 'vectorize' 您的计算几乎总是更好,这意味着尝试使用相同的方法进行所有计算基本 R 命令。在这种情况下,我们可以同时对你所有的子样本进行行采样,然后将采样的行分配给每个子样本。
其次,您正在创建一个列表 - df_l
,其中包含大量重复的原始 df
数据。这很浪费(您不需要多次存储相同的数据),并且需要做很多工作。再次使用索引访问原始数据几乎总是更好。
因此,将这些放在一起,我们可以创建一种更快的方法,而且不会重复数据:
首先,一些测试数据:
df=data.frame(matrix(sample(1:200),ncol=4))
现在,我们不再复制大量新数据帧列表中的数据,而是创建一个采样索引矩阵:
make_index_samples=function(df,n) {
return(matrix(sample(nrow(df),12*n,replace=T),nrow=n))
}
random_indices=make_index_samples(df,1000)
所以,现在,我们不再使用 df_l[[n]]
访问随机采样的 df n
(如在原始示例中那样),而是使用:
my_random_df=df[random_indices[n,],]
我们可以使用 microbenchmark
来查看速度有多快:
# (almost) original sampling
make_samples_original=function(df,n) {
df_l=list()
set.seed(123)
for(i in seq_len(n)) {
df_l[[i]]=df[sample(nrow(df),12,replace=T),]
}
return(df_l)
}
# compare making list of new dfs to making matrix of indices:
library(microbenchmark)
microbenchmark(make_samples_original(df,1000),make_index_samples(df,1000))
# Unit: microseconds
# expr min lq mean median uq max neval
# make_samples_original(df, 1000) 103515.198 111525.9985 116499.0323 115045.9485 118883.329 200982.370 100
# make_index_samples(df, 1000) 234.193 246.0805 307.6667 249.3815 300.382 755.873 100
因此对索引进行采样大约快 300 倍。
现在,关于 'repeated' 个相同的样本:正如@ThomasIsCoding 所指出的,完全相同的样本 12 的数量非常大 (2e20),所以你不太可能得到任何完美的 'collisions'.
但是,如果您认为 'the same' 也包括具有相同行集但顺序不同的两个样本,则存在 only 50^12/factorial(12)
组合,或者5e11。这可能看起来很多,但是 'birthday paradox' (https://en.wikipedia.org/wiki/Birthday_problem) 表明您 仅 需要采样大约 7e5 次才可能至少有一个 'collision'。
因此,对于 100 万次随机化,您可能会有一个或两个样本具有相同的行集。对于许多应用程序,这不太可能是一个大问题。如果它适合你,你可以检查每个随机化以确保它以前没有发生过,但这可能会抵消大部分或所有更快采样的好处......
无论如何,这是一种方法:
首先,我们制作了一些比我们实际需要的多的随机样本,这样我们就可以丢弃任何重复的样本并且仍然有足够的样本:
set.seed(123)
random_indices=make_index_samples(df,1000100) # 1 million +100 extra
然后,我们为每个随机样本构造一个名称,以唯一标识其中的样本行,但(在这种情况下)无需担心行的顺序:
random_index_names=apply(random_indices,1,function(row) paste(sort(row),collapse="_"))
我们可以检查是否有任何冲突(将通过重名显示),并丢弃这些:
sum(duplicated(random_index_names)) # I got 1 duplicate!
random_indices.no_duplicates=random_indices[-duplicated(random_index_names),][1:1000000,]
我有一个 50 行 4 列的数据框。我想获得许多 12 行的样本数据帧可能是一百万个,我不希望我的两个样本数据帧相同。我使用了下面的代码
df_l <- list()
for(i in 1:6000000) {
set.seed(100+i)
a <- df[sample(nrow(df),12,replace=T),]
df_l[[i]] <- a
rownames(df_l[[i]]) <- 1:12
}
但我的困惑是这可能不是执行此操作的有效方法,我不知道两个样本数据帧是否相同。
您可以试试下面的代码:
- 采样时不放回
n <- nrow(df)
df_1 <- replicate(6000000,df[sample(n,12),],simplify = FALSE)
- 采样时有替换
n <- nrow(df)
df_1 <- replicate(6000000,df[sample(n,12,replace = TRUE),],simplify = FALSE)
关于相同数据帧的关注,这取决于您从中采样的 space 的大小。对于你的情况,
如果您不允许更换,您的 space 尺码是
choose(50,12)*factorial(12)
,比6000000
大很多。因此,碰撞的可能性很小。如果允许替换,你的space大小是
50**12*factorial(12)
,比没有替换的场景还要大。这样碰撞的概率就会小很多。
是的,这不是很有效。
1) 您只需设置一次种子。
2) R 是一种解释型语言,在使用基本的分支函数(例如 if、for、while ...)或变量操作(例如 a <- a+1)时非常慢。对于只需要很短时间的功能,口译尤其要花费时间。 所以,你想调用一个同时做很多事情的函数,因为当声明时,它很快,因为它可能以更快的方式实现(它们通常是编译的)。
只需将 1:6000000 替换为 1:12 并采用 6000000 的样本向量,这将使您的程序 运行 更快。你只需要安排你如何安排数据。
3) 尝试 replicate
由于几个原因(如下所述),您正在尝试的方法相当慢,而且它还涉及大量数据重复,这通常效率不高。
首先,您正在使用循环来执行采样,这在 R 中通常很慢。尝试 'vectorize' 您的计算几乎总是更好,这意味着尝试使用相同的方法进行所有计算基本 R 命令。在这种情况下,我们可以同时对你所有的子样本进行行采样,然后将采样的行分配给每个子样本。
其次,您正在创建一个列表 - df_l
,其中包含大量重复的原始 df
数据。这很浪费(您不需要多次存储相同的数据),并且需要做很多工作。再次使用索引访问原始数据几乎总是更好。
因此,将这些放在一起,我们可以创建一种更快的方法,而且不会重复数据:
首先,一些测试数据:
df=data.frame(matrix(sample(1:200),ncol=4))
现在,我们不再复制大量新数据帧列表中的数据,而是创建一个采样索引矩阵:
make_index_samples=function(df,n) {
return(matrix(sample(nrow(df),12*n,replace=T),nrow=n))
}
random_indices=make_index_samples(df,1000)
所以,现在,我们不再使用 df_l[[n]]
访问随机采样的 df n
(如在原始示例中那样),而是使用:
my_random_df=df[random_indices[n,],]
我们可以使用 microbenchmark
来查看速度有多快:
# (almost) original sampling
make_samples_original=function(df,n) {
df_l=list()
set.seed(123)
for(i in seq_len(n)) {
df_l[[i]]=df[sample(nrow(df),12,replace=T),]
}
return(df_l)
}
# compare making list of new dfs to making matrix of indices:
library(microbenchmark)
microbenchmark(make_samples_original(df,1000),make_index_samples(df,1000))
# Unit: microseconds
# expr min lq mean median uq max neval
# make_samples_original(df, 1000) 103515.198 111525.9985 116499.0323 115045.9485 118883.329 200982.370 100
# make_index_samples(df, 1000) 234.193 246.0805 307.6667 249.3815 300.382 755.873 100
因此对索引进行采样大约快 300 倍。
现在,关于 'repeated' 个相同的样本:正如@ThomasIsCoding 所指出的,完全相同的样本 12 的数量非常大 (2e20),所以你不太可能得到任何完美的 'collisions'.
但是,如果您认为 'the same' 也包括具有相同行集但顺序不同的两个样本,则存在 only 50^12/factorial(12)
组合,或者5e11。这可能看起来很多,但是 'birthday paradox' (https://en.wikipedia.org/wiki/Birthday_problem) 表明您 仅 需要采样大约 7e5 次才可能至少有一个 'collision'。
因此,对于 100 万次随机化,您可能会有一个或两个样本具有相同的行集。对于许多应用程序,这不太可能是一个大问题。如果它适合你,你可以检查每个随机化以确保它以前没有发生过,但这可能会抵消大部分或所有更快采样的好处......
无论如何,这是一种方法:
首先,我们制作了一些比我们实际需要的多的随机样本,这样我们就可以丢弃任何重复的样本并且仍然有足够的样本:
set.seed(123)
random_indices=make_index_samples(df,1000100) # 1 million +100 extra
然后,我们为每个随机样本构造一个名称,以唯一标识其中的样本行,但(在这种情况下)无需担心行的顺序:
random_index_names=apply(random_indices,1,function(row) paste(sort(row),collapse="_"))
我们可以检查是否有任何冲突(将通过重名显示),并丢弃这些:
sum(duplicated(random_index_names)) # I got 1 duplicate!
random_indices.no_duplicates=random_indices[-duplicated(random_index_names),][1:1000000,]