按组统计完整案例数量。

3
我有一个大数据集(大约10000行),想要创建一个函数来计算每个组的完整案例数量(不包括NAs)。我尝试了各种函数(aggregate,table,sum(complete.cases),group_by等),但是我似乎错过了一个 - 可能很小的 - 技巧。感谢任何帮助!
这里是一个小样本数据集,用于解释我需要的结果。
x <- data.frame(group = c(1:4), 
                age = c(4:1, c(11, NA,13, NA)), 
                speed = c(12, NA,15,NA))
print(x)
#  group age speed
#1     1   4    12
#2     2   3    NA
#3     3   2    15
#4     4   1    NA
#5     1  11    12
#6     2  NA    NA
#7     3  13    15
#8     4  NA    NA

我写的一个函数如下:

CountPerGroup <- function(group) {
    data.set <- subset(x,group %in% group)

    vect <- vector()
    for (i in 1:length(group)) {
        vect[i] <- sum(complete.cases(data.set))
    }
    output <- data.frame(cbind(group,count=vect))   
    return(output)

}

执行

的结果是:

CountPerGroup(2:1)

is

  group count
1     2     4
2     1     4

不幸的是,这是错误的。相反,结果应该看起来像这样。
  group count
1     2     1
2     1     4

我错过了什么?我该如何告诉R按组计算complete.cases的数量? 非常感谢您对此的任何帮助!


抱歉,它没有给我正确的结果...也许我没有正确使用你的代码 - 你会如何在函数中实现它? - user2006697
你如何计算第一组4个完整案例和第二组1个完整案例?请注意,完整案例与非丢失值的数量不同。 - Anders Ellern Bilgrau
如果您有大量的数据,您也可以使用data.table,这个包通常是为此目的而制作的! - Colonel Beauvel
4个回答

3

如果你想保持功能,那么类似下面这样的代码就可以实现:

x <- data.frame(group = c(1:4), 
                age = c(4:1, c(11, NA,13, NA)), 
                speed = c(12, NA,15,NA))

CountPerGroup <- function(x, groups) {
  data.set <- subset(x, group %in% groups)
  ans <- sapply(split(data.set, data.set$group), 
                function(y) sum(complete.cases(y)))
  return(data.frame(group = names(ans), count = unname(ans)))
}


CountPerGroup(x, 1:2)
#  group count
#1     1     2
#2     2     0

从我目前所能计算的结果来看,第一个结果是正确的。但它与你建议的结果不符。
编辑:
看起来你想要非NA的数量并正确排序。请使用这个函数代替。
CountPerGroup2 <- function(x, groups) {
   data.set <- subset(x, group %in% groups)
   ans <- sapply(split(data.set, data.set$group), 
                 function(y) sum(!is.na(y[, !grepl("group", names(y))])))[groups]
   return(data.frame(group = names(ans), count = unname(ans)))
}

CountPerGroup2(x, 2:1)
#  group count
#1     2     1
#2     1     4

数据集有两行属于第一组,和两行属于第二组。第一组有四个值,分别是4(年龄)、11(年龄)、12(速度)和12(速度)。第二组只有一个值,即年龄为2,但第6行的年龄是NA,速度有两个NA。因此,我对第一组进行了4次观察,对第二组进行了1次观察。 - user2006697
@user2006697 哦,所以你想要观测值的数量(即非缺失值)。我明白了,我会修改答案。请注意,这与完整案例的数量相同。完整案例是指没有NA的整行数据。 - Anders Ellern Bilgrau
啊啊啊... 谢谢您的解释... 我显然误解了 complete.cases 函数。感谢您的帮助,并感谢您修改后的答案! - user2006697
太棒了!非常感谢你的帮助和耐心! - user2006697
还有一个问题:这段代码忽略了函数中组的顺序。也就是说,无论我使用CountPerGroup2(x, 1:2)还是CountPerGroup2(x, 2:1),结果都是一样的。我该如何修改您的代码,使其考虑到函数输入的顺序? - user2006697
通过在函数中将 ans 对象在 groups 之后进行排序,我已修改了答案中的 CountPerGroup2 函数。 - Anders Ellern Bilgrau

2

如果您只是想找到每个组中非NA值的完整计数方法,可以使用以下方式:

library(plyr)
x <- data.frame(group = c(1:4), 
                age = c(4:1, c(11, NA,13, NA)), 
                speed = c(12, NA,15,NA))

counts <- ddply(x, "group", summarize, count=sum(!is.na(c(age, speed))))

##   group count
## 1     1     4
## 2     2     1
## 3     3     4
## 4     4     1

你可能错过了一个允许你查询子集的函数,但是你可以通过一行代码计算出完整的解决方案。

0

这里有一种使用 data.table 的方法

library(data.table)
library(functional)

countPerGroup = function(x, vec)
{
    dt = data.table(x) 
    d1 = setkey(dt, group)[group %in% vec]
    d2 = d1[,lapply(.SD, Compose(Negate(is.na), sum)),by=group]
    transform(d2, count=age+speed, speed=NULL, age=NULL)
}


countPerGroup(x, 1:2)
#   group count
#1:     1     4
#2:     2     1

countPerGroup(x, c(1,2))
#   group count
#1:     1     4
#2:     2     1

如果您的data.table中有大量行,它尤其高效!


谢谢您。目前对我来说有点太高级了,但我会保存它以备将来使用! - user2006697
Compose和Negate是函数式包中非常直观的函数,你应该看一下! - Colonel Beauvel

0

我刚遇到同样的问题,找到了一个更简单的解决方案

library(data.table)

x <- data.table(group = c(1:4), 
                age = c(4:1, c(11, NA,13, NA)), 
                speed = c(12, NA,15,NA))
x[,sum(complete.cases(.SD)), by=group]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接