我刚接触R,遇到以下问题。
我有一个这样的数据框:
A | B | C | E | F |G
1 02 XXX XXX XXX 1
1 02 XXX XXX XXX 1
2 02 XXX XXX XXX NA
2 02 XXX XXX XXX NA
3 02 XXX XXX XXX 1
3 Z1 XXX XXX XXX 1
4 02 XXX XXX XXX 2
....
M 02 XXX XXX XXX 1
问题是该数据帧可能有15万行或更多,因此我需要按A
(以ID为代表)生成另一个数据帧分组,并计算以下次数:
当B为02并且G为1时<-V
当B为02而G为NA <-W
当B为Z1而G为1 <-X
当B是Z1而G是NA <-Y
任何其他类型的出现<-Z
对于这个简单的示例,结果应该看起来像这样
A | V | W | X | Y | Z
1 2 0 0 0 0
2 0 2 0 0 0
3 1 1 0 0 0
4 0 0 0 0 1
...
M 1 0 0 0 0
此时,我设法使用for循环获取结果:
get_counters <- function(df){
counters <- data.frame(matrix(ncol = 6, nrow = length(unique(df$A))))
colnames(counters) <- c("A", "V", "W", "X", "Y", "Z")
counters$A<- unique(df$A)
for (i in 1:nrow(counters)) {
counters$V[i] <- sum(df$A == counters$A[i] & df$B == "02" & df$G == 1, na.rm = TRUE)
counters$W[i] <- sum(df$A == counters$A[i] & df$B == "02" & is.na(df$G), na.rm = TRUE)
counters$X[i] <- sum(df$A == counters$A[i] & df$B == "Z1" & df$G== 1, na.rm = TRUE)
counters$Y[i] <- sum(df$A == counters$A[i] & df$B == "Z1" & is.na(df$G), na.rm = TRUE)
counters$Z[i] <- sum(df$A == counters$A[i] & (df$B == "Z1" | df$B == "02") & df$G!= 1, na.rm = TRUE)
}
return(counters)
}
尝试在较小的测试数据帧上返回所有正确的结果,但是使用真实数据非常慢。我不确定如何使用apply
函数,这似乎是一个简单的问题,但是我没有找到答案。到目前为止,我已经假定如果可以在for循环中将apply
与sum
语句一起使用(也许使用group_by(A)
),我可以做到,但是我会收到各种错误。
counters$V <- df%>%
group_by(A)%>%
sum(df$A == counters$A& df$B == "02" &df$G == 1, na.rm = TRUE)
Error in FUN(X[[i]], ...) : only defined on a data frame with all numeric variables In addition: Warning message: In df$A== counters$A: longer object length is not a multiple of shorter object length
如果我将函数更改为不使用for循环并且不使用$
(我得到一个错误,引用了"$ operator is invalid for atomic vectors"
),我将得到更多错误或奇怪的不可读结果(包含更多内容的大列表)原始数据框的值,巨大的空矩阵等)
是否有一种简单的方法(也许不是简单的但快速有效的)来解决这个问题?预先感谢。
答案 0 :(得分:0)
您可以使用data.table快速完成此操作。
创建虚拟数据:
set.seed(123)
counters <- data.frame(A = rep(1:100000, each = 3), B = sample(c("02","Z1"), size = 300000, replace = T), G = sample(c(1,NA), size = 300000, replace = T))
我要做的只是计算组合的实例,然后reshaping以您需要的格式计算数据:
library(data.table)
setDT(counters)
counters[,comb := paste0(B,"_",G)]
dcast(counters, A ~ comb, fun.aggregate = length, value.var = "A")
A 02_1 02_NA Z1_1 Z1_NA
1: 1 0 2 1 0
2: 2 1 0 1 1
3: 3 0 0 2 1
4: 4 1 1 0 1
5: 5 0 1 2 0
---
99996: 99996 0 1 1 1
99997: 99997 0 2 1 0
99998: 99998 2 0 1 0
99999: 99999 1 0 1 1
100000: 100000 0 2 0 1
我采用了一个可扩展的命名约定(新列指示要计算的组合),但是如果要覆盖,请用以下四行替换comb :=
行:>
counters[B == "02" & is.na(G), comb := "V"]
counters[B == "02" & !is.na(G), comb := "X"]
....
但是我认为以上内容更加灵活。