我有一个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
谢谢!
答案 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 }
根据x
:seq(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