按行计算出现次数
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
后的长格式,使用 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))))
或者我们可以在使用 add_rownames
from dplyr
创建行 ID 后使用 tidyr
的 gather/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
假设我有一个 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
后的长格式,使用 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))))
或者我们可以在使用 add_rownames
from dplyr
tidyr
的 gather/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