按行计算出现次数

Counting occurrencies by row

假设我有一个 data.frame(或矩阵),其中包含几个不同的值,例如

test <- data.frame(replicate(10,sample(c(-1,0,1),20, replace=T, prob=c(0.2,0.2,0.6))))   
test2 <- test

如果我想添加带有计数的额外列,我可以这样做:

test2$good <-  apply(test,1, function(x) sum(x==1))   
test2$bad <-  apply(test,1, function(x) sum(x==-1)) 
test2$neutral <-  apply(test,1, function(x) sum(x==0))  

但是如果我有很多可能的值而不是我将不得不创建很多行,它不会很优雅。

我试过 table(),但输出不容易使用

apply(test,1, function(x) table(x)) 

并且有一个大问题,如果任何行不包含某些因素的任何出现,则 table() 生成的结果不具有相同的长度并且无法绑定。

有没有办法强制 table() 考虑该值,告诉它出现次数为零?

然后我想到了用do.call或者lapply合并但是对我来说太难了

我也读过有关 dplyr count 的内容,但我不知道该怎么做。 谁能用 dplyr 或 tidyr 提供解决方案?

PD:data.table 解决方案怎么样?

你可以使用 rowSums():

test2 <- cbind(test2, sapply(c(-1, 0, 1), function(x) rowSums(test==x)))

类似于 etienne 评论中的代码,但没有调用 apply()

我们可以 melt 将数据集转换为 matrix 后的长格式,使用 tablecbind 与原始数据集一起获取频率。

library(reshape2)
cbind(test2, as.data.frame.matrix(table(melt(as.matrix(test2))[-2]))) 

或使用 mtabulate 对 'test2' 和 cbind 与原始数据集进行转置。

library(qdapTools)
cbind(test2, mtabulate(as.data.frame(t(test2))))

或者我们可以在使用 add_rownames from dplyr

创建行 ID 后使用 tidyrgather/spread
library(dplyr)
library(tidyr)
add_rownames(test2) %>%
     gather(Var, Val, -rowname) %>%\
     group_by(rn= as.numeric(rowname), Val) %>% 
     summarise(N=n()) %>%
     spread(Val, N, fill=0) %>%
     bind_cols(test2, .)

这是使用 base R 的答案。

test <- data.frame(replicate(10,sample(c(-1,0,1),20, replace=T, prob=c(0.2,0.2,0.6))))   
testCopy <- test

# find all unique values, note that data frame is a list
uniqVal <- unique(unlist(test))

# the new column names start with Y
for (val in uniqVal) {
    test[paste0("Y",val)] <- apply(testCopy, 1, function(x) sum(x == val))
}

head(test)
#   X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 Y-1 Y1 Y0
# 1 -1  0  1  1  1  0 -1 -1  1   1   3  5  2
# 2  1 -1  0  1  1 -1 -1  0  0   1   3  4  3
# 3 -1  0  1  0  1  1  1  1 -1   1   2  6  2
# 4  1  1  1  1  0  1  1  0  1   0   0  7  3
# 5  0 -1  1 -1 -1  0  0  1  0   0   3  2  5
# 6  1  1  0  1  1  1  1  1  1   1   0  9  1