将向量返回函数应用于按几个因子分组的data.frame

时间:2015-07-12 14:40:24

标签: r aggregate apply

以下是我数据框的示例

charact_fraction    pure_charact    sample  replicate   identity
0.08348135  clean   An006   1   70
0.078947368 clean   An006   1   70
0.090277778 clean   An006   1   70
0.044399596 clean   An006   2   70
0   clean   An006   2   70
0.049348869 clean   An006   2   70
0.218818381 mixed   An011   1   70
0.112068966 mixed   An011   1   70
1   pure    An011   1   70
0   clean   An011   2   70
0.214285714 mixed   An011   2   70
0.2180937   mixed   An011   2   70

我想要对charact_fraction进行分区并计算按多个因素分组的bin频率。生成的数据框应该看起来像这样

bin_frequency   bin sample  replicate   identity
…   0-0.1   An006   1   70
…   …   …   …   …
…   0.9-1.0 An006   1   70
…   0-0.1   An011   1   70
…   …   …   …   …
…   0.9-1.0 An011   1   70
…   …   …   …   …

我有返回bin频率的功能。

get_freqs <- function(dat_vector, breaks) {
    hist(dat_vector, breaks=breaks, include.lowest=TRUE, plot=FALSE)$counts
}

我可以生成垃圾箱。

breaks=seq(0,1,by=0.1)
bins = paste(breaks, breaks[-1], sep="-")
bins = bins[-length(ranges)]

我相信这是我到目前为止最接近的镜头,但显然远远不是预期的输出:

with(df, tapply(charact_part, list(sample, replicate, identity), get_freqs, breaks=breaks))

我有非常丑陋的Python代码可以做到这一点,但我希望在R中有更清洁和更实用的功能。先谢谢你。

3 个答案:

答案 0 :(得分:1)

cut可能是要走的路:

x <- gsub("\\[|\\]|\\(", "", cut(df$charact_fraction, seq(0,1, .1), include.lowest=T))
df$range <- gsub(",", "-", x)
df
#    charact_fraction pure_charact sample replicate identity   range
# 1        0.08348135        clean  An006         1       70   0-0.1
# 2        0.07894737        clean  An006         1       70   0-0.1
# 3        0.09027778        clean  An006         1       70   0-0.1
# 4        0.04439960        clean  An006         2       70   0-0.1
# 5        0.00000000        clean  An006         2       70   0-0.1
# 6        0.04934887        clean  An006         2       70   0-0.1
# 7        0.21881838        mixed  An011         1       70 0.2-0.3
# 8        0.11206897        mixed  An011         1       70 0.1-0.2
# 9        1.00000000         pure  An011         1       70   0.9-1
# 10       0.00000000        clean  An011         2       70   0-0.1
# 11       0.21428571        mixed  An011         2       70 0.2-0.3
# 12       0.21809370        mixed  An011         2       70 0.2-0.3

如果您还想要计数,可以添加:

lst <- lapply(split(df, df$sample), function(x) {
  within(x, count <- table(range)[match(range, names(table(range)))])
}) 
`rownames<-`(do.call(rbind, lst), NULL)
#    charact_fraction pure_charact sample replicate identity   range count
# 1        0.08348135        clean  An006         1       70   0-0.1     6
# 2        0.07894737        clean  An006         1       70   0-0.1     6
# 3        0.09027778        clean  An006         1       70   0-0.1     6
# 4        0.04439960        clean  An006         2       70   0-0.1     6
# 5        0.00000000        clean  An006         2       70   0-0.1     6
# 6        0.04934887        clean  An006         2       70   0-0.1     6
# 7        0.21881838        mixed  An011         1       70 0.2-0.3     3
# 8        0.11206897        mixed  An011         1       70 0.1-0.2     1
# 9        1.00000000         pure  An011         1       70   0.9-1     1
# 10       0.00000000        clean  An011         2       70   0-0.1     1
# 11       0.21428571        mixed  An011         2       70 0.2-0.3     3
# 12       0.21809370        mixed  An011         2       70 0.2-0.3     3

答案 1 :(得分:1)

来自'plyr'的cut()ddply()的组合应该为您提供一个数据框,其中包含您感兴趣因子的各个子集的频率。如下所示:

library(plyr)
df$bin <- cut(df$charact_fraction, seq(0, 1, 0.1), include.lowest=TRUE)
df$obs <- 1  # Makes counting easy in next step
xtabs <- ddply(df, .(bin, sample, replicate, identity), summarise,
    frequency = sum(obs))

这里使用ddply的一个潜在缺点是结果数据帧不包含零观测值的子集。如果这是一个问题,你可以创建一个完整的矩阵,合并观察到的频率,然后用这样的0替换NA:

xtabs.grid <- with(df, expand.grid(bin = unique(bins), sample = unique(sample),
  replicate = unique(replicate), identity = unique(identity)))
xtabs.full <- merge(xtabs.grid, xtabs, all.x = TRUE)
xtabs.full[is.na(xtabs.full)] <- 0

请注意,为了使合并顺利进行,提供给expand.grid()的变量名称需要与前一步骤中ddply()生成的变量名称相匹配。

附录:这是一个使用'dplyr'功能和管道来一次完成所有这些的版本:

df2 <- df %>%
  mutate(bin = cut(charact_fraction, seq(0, 1, 0.1), include.lowest=TRUE)) %>%
  count(bin, sample, replicate, identity) %>%
  left_join(with(df, expand.grid(bin=levels(cut(charact_fraction, seq(0, 1, 0.1), include.lowest=TRUE)), sample=unique(sample), replicate=unique(replicate), identity=unique(identity))), .) %>%
  mutate(n = ifelse(is.na(n)==FALSE, n, 0))

答案 2 :(得分:0)

只需使用table

with( dfrm, table( cut( charact_function, breaks=10, include.lowest=TRUE),
       sample, replicate, identity) )

您也可以使用breaks=breaks,但我只想展示该参数的不同用法...稍微更紧凑。

这是一种4路分类,虽然你可能想要三种双向分类,在这种情况下它是:

cat_char_func <- cut( charact_function, breaks=10, include.lowest=TRUE)
sapply( dfrm[ , c('sample', 'replicate', 'identity')], 
                    function(cat) { table( cat_char_func, cat) }
        )