【问题标题】:Apply a vector-returning function to a data.frame grouping by several factors将向量返回函数应用于按多个因素分组的 data.frame
【发布时间】:2015-07-12 14:40:23
【问题描述】:

这是我的数据框示例

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_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 中拥有一些更清洁和实用的东西。提前谢谢你。

【问题讨论】:

  • 我猜你正在寻找 cut 虽然我不确定你想要的输出是否真的。

标签: r aggregate apply


【解决方案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 的一个潜在缺点是生成的数据帧将不包含观测值为零的子集。如果这是一个问题,您可以创建一个完整的矩阵,合并观察到的频率,然后将 NA 替换为 0,如下所示:

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】:

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

【讨论】:

    【解决方案3】:

    只需使用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) }
            )          
    

    【讨论】:

    • 我不知道如何将其转换为data.frame,如我的问题所示。
    猜你喜欢
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-13
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多