【问题标题】:Counting occurrencies by row按行计算出现次数
【发布时间】:2017-04-28 05:02:31
【问题描述】:

想象一下,我有一个 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 解决方案怎么样?

【问题讨论】:

  • 当然有更好的方法,但也许sapply(-1:1,function(y){apply(test,1, function(x) sum(x==y))})可以帮助你

标签: r count apply


【解决方案1】:

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

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

或者在“test2”和cbind与原始数据集的转置上使用mtabulate

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

或者我们可以在使用来自dplyradd_rownames创建行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, .)

【讨论】:

  • 聪明的方法,可能有点复杂
  • @JuanJosePiñerodeArmas 谢谢,但代码只是单行代码。
  • 我用 tidyr gather 尝试过同样的方法,但它不会产生相同的输出,它不会生成“行”号。
  • @JuanJosePiñerodeArmas 在dplyr 中有一个?add_rownames 的选项。您可以在gather 之前从tidyr 执行此操作。
  • @Juanjo 我没有使用table(..for tidyr,因为它不遵循 dplyr/tidyr 语法。
【解决方案2】:

你可以使用rowSums():

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

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

【讨论】:

  • 这只是@etienne 评论的副本,并没有解决任意行内容的问题
  • 不完全是:etienne 的代码调用了 apply()。忽略这一点 - 你是对的。
  • c(-1, 0, 1) 相对于 unique(unlist(test)) 的优势在于后者不会考虑某些不出现的值,但是您仍然可以希望代码将其报告为零发生率。
  • @Juanjo :到目前为止有 3 个答案。您可以决定接受或编辑问题以描述不适合您的问题。
【解决方案3】:

这是使用基数 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

【讨论】:

    猜你喜欢
    • 2018-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多