R:使用 tapply 按因素抽样观察
R: Sampling observations by factors using tapply
我有一个大数据集,我正试图从中抽样行。每行都有一个家庭 ID,每个家庭 ID 可能有一行或多行。我想通过为每个家庭 ID 随机抽取一行来解析数据集。我试图通过使用 tapply()
和 split()
+ lapply()
函数来完成此操作,但无济于事。下面是重现我的问题的代码 - 因子级别和数据条目的大小和范围反映了我正在使用的数据集。
set.seed(63)
f1 <- factor(c(rep(30000:32000, times=1),
rep(30500:31700, times = 2),
rep(30900:31900, times = 3)))
f2 <- factor(rep(sample(1:7, replace = TRUE), times = length(f1)/7))
x1 <- round(matrix(rnorm(length(f1)*300), nrow = length(f1), ncol = 300),3)
df <- data.frame(f1, f2, x1)
接下来,我使用 tapply
从 f1
中对每个因子采样一行,然后检查重复项。 (f2
是索引观察的另一个方面的次要因素,但 [希望] 与此无关;我将其包含在内只是为了完全公开我的数据集的结构)。
s1 <- tapply(1:nrow(df), df$f1, sample, size=1)
any(duplicated(s1))
使用duplicated
的第二行代码的输出是TRUE
,这意味着有重复。难住了,我尝试 split
看看是否是问题所在。
df.split <- split(1:nrow(df), df$f1)
any(duplicated(df.split))
这里 duplicated
的输出是 FALSE
,所以问题不是 split
。然后我将输出 df.split
与 lapply
和 sample
一起使用,看看问题是否出在 tapply
.
df.unique <- unlist(lapply(df.split, sample, size = 1, replace = FALSE,
prob = NULL))
any(duplicated(df.unique))
在第一行中,我从输出列表的df.split
的每个元素中采样了一个值,然后我使用unlist
转换为一个向量。这里 duplicated
的输出也是 TRUE
.
sample
和 lapply
中的某处发生了奇怪的事情(因为 tapply
只是调用 lapply
)。我不确定如何解决这个问题(我搜索了 SO 和 Google 并没有发现与我的问题相关的任何内容),所以非常感谢任何帮助!
编辑:我希望有人能告诉我为什么上面使用 tapply
和 lapply
的代码没有按预期工作。 Arthur 提供了一个很好的答案,我也为 sample
编写了一个循环。我想知道为什么上面的代码运行不正常。
我会这样做:
library(data.table)
data.table(df)[,.SD[sample(.N,1)],by='f1']
... 但实际上,如果您只想要一个索引而不是实际的子集 table ,那么您使用 tapply
的原始方法会更快;但是,您必须注意到 sample(n)
实际上在 length(n)==1
时在 1:n
中采样。参见 ?sample
。这个版本是防错的:
s1 <- tapply(1:nrow(df), list(df$f1), function(v) v[sample(1:length(v), 1)])` is error prooff
我有一个大数据集,我正试图从中抽样行。每行都有一个家庭 ID,每个家庭 ID 可能有一行或多行。我想通过为每个家庭 ID 随机抽取一行来解析数据集。我试图通过使用 tapply()
和 split()
+ lapply()
函数来完成此操作,但无济于事。下面是重现我的问题的代码 - 因子级别和数据条目的大小和范围反映了我正在使用的数据集。
set.seed(63)
f1 <- factor(c(rep(30000:32000, times=1),
rep(30500:31700, times = 2),
rep(30900:31900, times = 3)))
f2 <- factor(rep(sample(1:7, replace = TRUE), times = length(f1)/7))
x1 <- round(matrix(rnorm(length(f1)*300), nrow = length(f1), ncol = 300),3)
df <- data.frame(f1, f2, x1)
接下来,我使用 tapply
从 f1
中对每个因子采样一行,然后检查重复项。 (f2
是索引观察的另一个方面的次要因素,但 [希望] 与此无关;我将其包含在内只是为了完全公开我的数据集的结构)。
s1 <- tapply(1:nrow(df), df$f1, sample, size=1)
any(duplicated(s1))
使用duplicated
的第二行代码的输出是TRUE
,这意味着有重复。难住了,我尝试 split
看看是否是问题所在。
df.split <- split(1:nrow(df), df$f1)
any(duplicated(df.split))
这里 duplicated
的输出是 FALSE
,所以问题不是 split
。然后我将输出 df.split
与 lapply
和 sample
一起使用,看看问题是否出在 tapply
.
df.unique <- unlist(lapply(df.split, sample, size = 1, replace = FALSE,
prob = NULL))
any(duplicated(df.unique))
在第一行中,我从输出列表的df.split
的每个元素中采样了一个值,然后我使用unlist
转换为一个向量。这里 duplicated
的输出也是 TRUE
.
sample
和 lapply
中的某处发生了奇怪的事情(因为 tapply
只是调用 lapply
)。我不确定如何解决这个问题(我搜索了 SO 和 Google 并没有发现与我的问题相关的任何内容),所以非常感谢任何帮助!
编辑:我希望有人能告诉我为什么上面使用 tapply
和 lapply
的代码没有按预期工作。 Arthur 提供了一个很好的答案,我也为 sample
编写了一个循环。我想知道为什么上面的代码运行不正常。
我会这样做:
library(data.table)
data.table(df)[,.SD[sample(.N,1)],by='f1']
... 但实际上,如果您只想要一个索引而不是实际的子集 table ,那么您使用 tapply
的原始方法会更快;但是,您必须注意到 sample(n)
实际上在 length(n)==1
时在 1:n
中采样。参见 ?sample
。这个版本是防错的:
s1 <- tapply(1:nrow(df), list(df$f1), function(v) v[sample(1:length(v), 1)])` is error prooff