【问题标题】:How to convert an output of "by" function to a data frame in R?如何将“by”函数的输出转换为R中的数据框?
【发布时间】:2018-09-21 17:06:41
【问题描述】:

这是我想做的事情: 我有一个数据框 df 定义为:

col1 <- c("a","a","a","a","a","a","b","b","b","b","b","b")
col2 <- c("z","z","x","x","z","x", "z","z","x","x","z","x")
col3 <- c(1,2,3,4,5,6,7,8,9,10,11,12)
df <- data.frame(col1,col2,col3)

和一个计算平均值的函数 pred 定义为:

pred <- function(subset_df){return(mean(subset_df$col3))}

我想要一个通过 by 函数的数据框,格式如下:

col1 col2 col3_mean
a     x    4.33
a     z    2.66
b     x    10.33
b     z    8.66

我目前正在使用 by() 函数将这些数据划分为其层,并应用 pred() 函数来计算平均值

by_keys <- c("col1","col2")
data_sub <- by(df, data_sub[,by_keys], pred)  
data_sub <- do.call(rbind, data_sub)

我在这里收到一个错误,说“do.call(rbind, data_sub) 中的错误:第二个参数必须是一个列表”

我尝试了类似胎面的解决方案,但我没有得到所需格式的 col1 和 col2

as.data.frame(vapply(data_sub,unlist,unlist(data_sub[[1]])))

不胜感激。

【问题讨论】:

  • aggregate(col3~.,df,mean) 很容易做到这一点

标签: r apply


【解决方案1】:

使用dplyr:

library(dplyr)

df %>% group_by(col1, col2) %>% 
  summarize(col3_mean = mean(col3)) %>%
  as.data.frame


  col1 col2 col3_mean
1    a    x     4.333
2    a    z     2.667
3    b    x    10.333
4    b    z     8.667

【讨论】:

    【解决方案2】:

    确实,by 在您设置时不会返回一个列表,而是一个简化的结构,因为您的输出会返回数字向量。调整您的 pred 函数以返回数据帧,这些非简化结构将强制 by 返回一个列表,然后可以传递给 do.call

    pred <- function(subset_df){    
      df <- data.frame(col1 = subset_df$col1[[1]], 
                       col2 = subset_df$col2[[1]],
                       col3_mean = mean(subset_df$col3)
                      )                      
      return(df)
    }
    
    data_sub_list <- by(df, df[,by_keys], pred)  
    data_sub <- do.call(rbind, data_sub_list)
    data_sub
    
    #   col1 col2 col3_mean
    # 1    a    x  4.333333
    # 2    b    x 10.333333
    # 3    a    z  2.666667
    # 4    b    z  8.666667
    

    但是,正如@Onyambu 所评论的,这种类型的分组聚合可以使用aggregate 完成,这将返回数据帧。

    # FORMULA VERSION
    aggregate(col3 ~ col1 + col2, df, mean)
    #   col1 col2 col3_mean
    # 1    a    x  4.333333
    # 2    b    x 10.333333
    # 3    a    z  2.666667
    # 4    b    z  8.666667
    
    # NON-FORMULA VERSION
    aggregate(df$col3, by=list(col1=df$col1, col2=df$col2), mean)
    #   col1 col2         x
    # 1    a    x  4.333333
    # 2    b    x 10.333333
    # 3    a    z  2.666667
    # 4    b    z  8.666667
    

    通常,by(作为tapply 的面向对象的包装器)最适合运行需要通过迭代运行子集的更大、更广泛的数据框操作。事实上,如果你需要多个聚合,by 就变得很有用了:

    pred <- function(subset_df){      
      df <- data.frame(col1 = subset_df$col1[[1]], 
                       col2 = subset_df$col2[[1]],
                       col3_mean = mean(subset_df$col3),
                       col3_sd = sd(subset_df$col3),
                       col3_median = median(subset_df$col3),
                       col3_min = min(subset_df$col3),
                       col3_max = max(subset_df$col3),
                       col3_sum = sum(subset_df$col3),
                       col3_25pct = quantile(subset_df$col3)[[2]],
                       col3_75pct = quantile(subset_df$col3)[[4]],
                       col3_IQR = IQR(subset_df$col3)
                      )      
      return(df)
    }
    
    data_sub_list <- by(df, df[,by_keys], pred)  
    data_sub <- do.call(rbind, data_sub_list)
    
    #   col1 col2 col3_mean  col3_sd col3_median col3_min col3_max col3_sum col3_25pct col3_75pct col3_IQR
    # 1    a    x  4.333333 1.527525           4        3        6       13        3.5        5.0      1.5
    # 2    b    x 10.333333 1.527525          10        9       12       31        9.5       11.0      1.5
    # 3    a    z  2.666667 2.081666           2        1        5        8        1.5        3.5      2.0
    # 4    b    z  8.666667 2.081666           8        7       11       26        7.5        9.5      2.0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-03
      • 1970-01-01
      • 2022-01-23
      • 2013-06-27
      • 1970-01-01
      • 2015-01-05
      • 1970-01-01
      • 2021-12-19
      相关资源
      最近更新 更多