我有一个大数据集我试图从中采样行。每行都有一个系列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和谷歌并发现与我的问题无关),所以任何帮助都将不胜感激!
tapply
和lapply
的上述代码无法正常运行。 Arthur提供了一个很好的答案,我也为sample
编了一个循环。我想知道为什么上面的代码行为不端。
答案 0 :(得分:2)
我会这样做:
library(data.table)
data.table(df)[,.SD[sample(.N,1)],by='f1']
...但实际上,如果您只想要一个索引而不是实际的子集表,那么使用tapply
的原始方法会更快;但是,您必须注意sample(n)
1:n
实际上length(n)==1
?sample
。见 s1 <- tapply(1:nrow(df), list(df$f1), function(v) v[sample(1:length(v), 1)])` is error prooff
。这个版本是防错的:
Sub Cmemo()
With Worksheets("Sheet4") '<~~ SET THIS WORKSHEET REFERENCE PROPERLY!!
If .AutoFilterMode Then .AutoFilterMode = False
With .Cells(1, 1).CurrentRegion
.AutoFilter Field:=1, Criteria1:="*RR*"
.AutoFilter Field:=3, Criteria1:="<>memo"
.AutoFilter Field:=5, Criteria1:="<>Air", _
Operator:=xlAnd, Criteria2:="<>Printed"
If CBool(Application.Subtotal(103, .Offset(1, 0).Cells)) Then
With .Resize(.Rows.Count - 1, 1).Offset(1, 11)
.SpecialCells(xlCellTypeVisible) = 0
End With
End If
.AutoFilter Field:=5, Criteria1:="Air", _
Operator:=xlOr, Criteria2:="Printed"
If CBool(Application.Subtotal(103, .Offset(1, 0).Cells)) Then
With .Resize(.Rows.Count - 1, 1).Offset(1, 11)
.SpecialCells(xlCellTypeVisible).FormulaR1C1 = "=rc[-4]/10"
End With
End If
End With
If .AutoFilterMode Then .AutoFilterMode = False
End With
End Sub