求和在r中逐行标注

时间:2013-10-28 21:35:36

标签: r for-loop vectorization which

我有一个34,000行x 24列的大型数据框,每个列都包含一个类别标签。我想有效地浏览数据框并计算部分中列出每个标签的次数次,包括0 。 (我使用for循环驱动一个非常有效的长度(哪个)语句

示例:

  

df.test< -as.data.frame(rbind(c(“A”,“B”,“C”,“B”,“A”,“A”),c(“C”,“ C“,”C“,”C“,”C“,”C“),c(”A“,”B“,”B“,”A“,”A“,”A“)))

     

df.res< -as.data.frame(matrix(ncol = 6,nrow = 3))

假设df.test中的第1:3列来自一个数据集,另一个数据集为4:6。生成df.res以显示此内容的最有效方法是什么:

  

A B C A B C

     

1 1 1 2 1 0

     

0 0 3 0 0 3

     

1 2 0 3 0 0

谢谢!

1 个答案:

答案 0 :(得分:1)

使用很多 _apply s-的方式如下:

#list with the different data frames
df_ls <- sapply(seq(1, ncol(df.test), 3), function(x) df.test[,x:(x+2)], simplify = F)

#count each category
df.res <- do.call(cbind,
   lapply(df_ls, function(df.) { t(apply(df., 1, 
      function(x) { table(factor(unlist(x), levels = c("A", "B", "C"))) })) }))

#> df.res
#     A B C A B C
#[1,] 1 1 1 2 1 0
#[2,] 0 0 3 0 0 3
#[3,] 1 2 0 3 0 0

模拟您所描述的数据框:

DF <- data.frame(replicate(24, sample(LETTERS[1:3], 34000, T)), stringsAsFactors = F)
#> head(DF)
#  X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24
#1  B  C  C  C  B  A  C  B  B   A   C   C   B   C   B   B   B   C   B   C   C   B   B   C
#2  C  B  C  A  B  C  B  C  A   B   A   C   B   B   A   A   C   A   B   B   B   C   A   B
#3  B  C  C  A  A  A  C  A  C   A   A   A   B   B   A   A   A   C   B   B   A   C   C   C
#4  C  C  A  B  A  B  B  B  A   A   A   C   C   A   B   A   C   C   A   C   C   C   B   A
#5  B  B  A  A  A  A  C  A  B   B   A   B   B   A   C   A   A   A   C   A   A   C   B   C
#6  C  A  C  C  A  B  B  C  C   C   B   C   A   B   B   B   B   B   A   C   A   A   B   A
#> dim(DF)
#[1] 34000    24

DF_ls <- sapply(seq(1, ncol(DF), 3), function(x) DF[,x:(x+2)], simplify = F)

system.time(
DF.res <- do.call(cbind,
       lapply(DF_ls, function(df.) { t(apply(df., 1, 
          function(x) { table(factor(unlist(x), levels = c("A", "B", "C"))) })) })))
#user  system elapsed 
#59.84    0.07   60.73 

#> head(DF.res)
#     A B C A B C A B C A B C A B C A B C A B C A B C
#[1,] 0 1 2 1 1 1 0 2 1 1 0 2 0 2 1 0 2 1 0 1 2 0 2 1
#[2,] 0 1 2 1 1 1 1 1 1 1 1 1 1 2 0 2 0 1 0 3 0 1 1 1
#[3,] 0 1 2 3 0 0 1 0 2 3 0 0 1 2 0 2 0 1 1 2 0 0 0 3
#[4,] 1 0 2 1 2 0 1 2 0 2 0 1 1 1 1 1 0 2 1 0 2 1 1 1
#[5,] 1 2 0 3 0 0 1 1 1 1 2 0 1 1 1 3 0 0 2 0 1 0 1 2
#[6,] 1 0 2 1 1 1 0 1 2 0 1 2 1 2 0 0 3 0 2 0 1 2 1 0

编辑关于该方法的更多评论。

我将逐步完成上述步骤。

第一步是将绑定在一起的不同数据帧进行子集化;每个数据帧都放在一个列表中。函数function(x) { df.test[,x:(x+2)], simplify = F }根据xseq(1, ncol(df.test), 3)的值对整个数据框进行子集。如果您在上面的序列中使用3更改了4列距离4的不同数据框,则可以对此进行扩展。

#> df_ls <- sapply(seq(1, ncol(df.test), 3), function(x) df.test[,x:(x+2)], simplify = F)
#> df_ls
#[[1]]
#  V1 V2 V3
#1  A  B  C
#2  C  C  C
#3  A  B  B

#[[2]]
#  V4 V5 V6
#1  B  A  A
#2  C  C  C
#3  A  A  A

下一步是lapply向先前列出的一个函数,该函数计算一个数据帧的每一行中的每个类别(即列表的元素)。功能如下:t(apply(df., 1, function(x) { table(factor(unlist(x), levels = c("A", "B", "C"))) }))。内部函数(function(x))将{em>一行行转换为levels因子中的所有类别和计数(table)每个类别在该行中出现的数字。 apply将此函数应用于数据框的每一行(MARGIN = 1)。那么,现在,我们已经计算了一个数据帧的每一行中每个类别的频率。

#> table(factor(unlist(df_ls[[1]][3,]), levels = c("A", "B", "C")))
     #df_ls[[1]][3,] is the third row of the first dataframe of df_ls 
                                  #(i.e. _one_ row of _one_ dataframe)
#A B C 
#1 2 0

#> apply(df_ls[[1]], 1, 
#+       function(x) { table(factor(unlist(x), levels = c("A", "B", "C"))) })
#  [,1] [,2] [,3]   #df_ls[[1]] is the first dataframe of df_ls (i.e. _one_ dataframe)
#A    1    0    1
#B    1    0    2
#C    1    3    0

因为apply的返回不是想要的形式,我们使用t来交换行和列。

下一步是lapply以上所有数据帧(即列表中的元素)。

#> lapply(df_ls, function(df.) { t(apply(df., 1, 
#+       function(x) { table(factor(unlist(x), levels = c("A", "B", "C"))) })) })
#[[1]]
#     A B C
#[1,] 1 1 1
#[2,] 0 0 3
#[3,] 1 2 0

#[[2]]
#     A B C
#[1,] 2 1 0
#[2,] 0 0 3
#[3,] 3 0 0

最后一步是将cbind所有这些元素放在一起。按列绑定列表中所有元素的方法是在该列表中do.call cbind

#NOT the expected, using only cbind
#> cbind(lapply(df_ls, function(df.) { t(apply(df., 1, 
#+       function(x) { table(factor(unlist(x), levels = c("A", "B", "C"))) })) }))
#     [,1]     
#[1,] Integer,9
#[2,] Integer,9

#Correct!
#> do.call(cbind, lapply(df_ls, function(df.) { t(apply(df., 1, 
#+       function(x) { table(factor(unlist(x), levels = c("A", "B", "C"))) })) }))
#     A B C A B C
#[1,] 1 1 1 2 1 0
#[2,] 0 0 3 0 0 3
#[3,] 1 2 0 3 0 0