计算所有观察到的因子水平,包括未观察到的因子水平

Count all observed factor levels, also those that aren't observed

我们有DF

df <- data.frame(group=as.factor(rep(c("UP","DOWN"),6)),variables=(rep(c("sex","smoke","sport"),each=4))
             ,values=as.factor(c(1,1,1,0  ,1,1,0,0, 1,1,1,1)))

   group variables values
1     UP       sex      1
2   DOWN       sex      1
3     UP       sex      1
4   DOWN       sex      0
5     UP     smoke      1
6   DOWN     smoke      1
7     UP     smoke      0
8   DOWN     smoke      0
9     UP     sport      1
10  DOWN     sport      1
11    UP     sport      1
12  DOWN     sport      1
> 

现在我想知道所有级别的所有计数

library(plyr)

这个命令几乎完美地完成了我想要的

count(df, c("variables", "group", "values"))

 variables group values freq
1      sex  DOWN     0    1
2      sex  DOWN     1    1
3      sex    UP     1    2
4    smoke  DOWN     0    1
5    smoke  DOWN     1    1
6    smoke    UP     0    1
7    smoke    UP     1    1
8    sport  DOWN     1    2
9    sport    UP     1    2

我还想计算未观察到的因素水平。就像我在以下输出中每手所做的那样。

 variables group values freq
1      sex  DOWN     0    1
2      sex  DOWN     1    1
3      sex    UP     0    0  <-- 
4      sex    UP     1    2
5    smoke  DOWN     0    1
6    smoke  DOWN     1    1
7    smoke    UP     0    1  
8    smoke    UP     1    1
9    sport  DOWN     0    0  <--
10   sport  DOWN     1    2
11   sport    UP     0    0  <--
12   sport    UP     1    2

如何实现上面的输出?

这是一个想法。您可以根据 freq 变量复制行。如果频率为 2,那么复制的行将有一个唯一的行名,我们可以将其作为目标并将其 freqvalues 更改为 0.

df1 <- plyr::count(df, c("variables", "group", "values"))
df2 <- df1[rep(row.names(df1), df1$freq),]
df2$freq[grep('.', row.names(df2), fixed = TRUE)] <- 0
df2$values[df2$freq == 0] <- 0

df2
#     variables group values freq
#1         sex  DOWN      0    1
#2         sex  DOWN      1    1
#3         sex    UP      1    2
#3.1       sex    UP      0    0
#4       smoke  DOWN      0    1
#5       smoke  DOWN      1    1
#6       smoke    UP      0    1
#7       smoke    UP      1    1
#8       sport  DOWN      1    2
#8.1     sport  DOWN      0    0
#9       sport    UP      1    2
#9.1     sport    UP      0    0

如果你想重置你的行名, row.names(df2) <- NULL

你也可以这样做:

library(plyr)
d1 <- count(df, c("variables", "group", "values"))
d2 <- expand.grid(list(levels(df$variables), levels(df$group), levels(df$values)))
d2$freq <- 0
colnames(d2) <- colnames(d1)
m <- merge(d1, d2, by = c("variables", "group", "values"), all.y  = T)[,-5]
m[is.na(m)] <- 0

   # variables group values freq.x
# 1        sex  DOWN      0      1
# 2        sex  DOWN      1      1
# 3        sex    UP      0      0
# 4        sex    UP      1      2
# 5      smoke  DOWN      0      1
# 6      smoke  DOWN      1      1
# 7      smoke    UP      0      1
# 8      smoke    UP      1      1
# 9      sport  DOWN      0      0
# 10     sport  DOWN      1      2
# 11     sport    UP      0      0
# 12     sport    UP      1      2

想法是制作一个数据框(名为d2),其中生成variablesgroupvalues的所有可能组合,然后合并它d1.

您也可以使用 data.table 使用更少的代码行来做到这一点:

library(data.table)
dt <- setDT(df)
cj <- CJ(dt$variables, dt$group, dt$values, unique = TRUE)
dt[, .N, keyby = c("variables", "group", "values")][cj][is.na(N), N := 0]

print(dt)    
    variables group values N
 1:       sex  DOWN      0 1
 2:       sex  DOWN      1 1
 3:       sex    UP      0 0
 4:       sex    UP      1 2
 5:     smoke  DOWN      0 1
 6:     smoke  DOWN      1 1
 7:     smoke    UP      0 1
 8:     smoke    UP      1 1
 9:     sport  DOWN      0 0
10:     sport  DOWN      1 2
11:     sport    UP      0 0
12:     sport    UP      1 2

说明

setDT() 通过引用 将 data.frame 转换为 data.table ,即不进行复制。

CJ() 是交叉连接。它根据向量的叉积形成 data.table。因此,它是 expand.griddata.table 版本。 参数 unique = TRUE 是将每个参数包装在 level()unique().

中的一种方便的替代方法

分组计数是用dt[, .N, keyby = c("variables", "group", "values")]:

完成的
   variables group values N
1:       sex  DOWN      0 1
2:       sex  DOWN      1 1
3:       sex    UP      1 2
4:     smoke  DOWN      0 1
5:     smoke  DOWN      1 1
6:     smoke    UP      0 1
7:     smoke    UP      1 1
8:     sport  DOWN      1 2
9:     sport    UP      1 2

现在,dt[, .N, keyby = c("variables", "group", "values")][cj](右)将 CJ() 结果与所有可能的组合相结合。

最后,[is.na(N), N := 0]N 列中的所有 NA 替换为 0