想象一下,我有一个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计数的内容,但我不知道如何做到这一点。 任何人都可以提供dplyr或tidyr的解决方案吗?
PD:data.table解决方案怎么样?
答案 0 :(得分:3)
转换为melt
后,我们可以matrix
数据集进行长格式化,使用原始数据集使用table
和cbind
获取频率。
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))))
我们可以在gather/spread
tidyr
的行ID后,使用add_rownames
中的dplyr
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, .)
答案 1 :(得分:1)
您可以使用rowSums()
:
test2 <- cbind(test2, sapply(c(-1, 0, 1), function(x) rowSums(test==x)))
类似于etienne的评论中的代码,但未调用apply()
答案 2 :(得分:1)
以下是使用基础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