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

时间:2016-09-26 11:50:12

标签: r count aggregate plyr r-factor

我们有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

如何实现上述输出?

3 个答案:

答案 0 :(得分:2)

您也可以使用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。因此,它是data.table的{​​{1}}版本。 参数expand.grid是在unique = TRUElevel()中包装每个参数的便捷替代方法。

按小组计算是使用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]列中的所有NA替换为N

答案 1 :(得分:1)

你也可以这样做:

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合并{1}}。

答案 2 :(得分:0)

这是一个想法。您可以根据freq变量复制行。如果freq为2,则复制的行将具有唯一的rowname,我们可以将其定位并将其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

如果你想重置你的rownames那么, row.names(df2) <- NULL