R-如何使用sum和group_by内部应用?

时间:2018-12-13 13:49:30

标签: r loops dataframe apply

我刚接触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循环中将applysum语句一起使用(也许使用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"),我将得到更多错误或奇怪的不可读结果(包含更多内容的大列表)原始数据框的值,巨大的空矩阵等)

是否有一种简单的方法(也许不是简单的但快速有效的)来解决这个问题?预先感谢。

1 个答案:

答案 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"]
....

但是我认为以上内容更加灵活。