【问题标题】:How to use a for loop to use ddply on multiple columns?如何使用 for 循环在多列上使用 ddply?
【发布时间】:2018-01-09 19:14:36
【问题描述】:

我发现一些 stackoverflow 问题非常相似,但答案不是我想要的(Loop through columns and apply ddplyAggregate / summarize multiple variables per group (i.e. sum, mean, etc)

主要区别在于答案以不使用 for 循环(也不应用)而是使用聚合(或类似)的方式简化了他们的问题。但是,我有大量代码可以顺利地进行各种摘要、统计和绘图,所以我真正想做的是让循环或函数正常工作。我目前面临的问题是从在循环中存储为 q 的列名到实际列(get() 对我不起作用)。见下文。

我的数据集与下面类似,但有 40 个特征:

Subject <- c(rep(1, times = 6), rep(2, times = 6))
GroupOfInterest <- c(letters[rep(1:3, times = 4)])
Feature1 <- sample(1:20, 12, replace = T)
Feature2 <- sample(400:500, 12, replace = T)
Feature3 <- sample(1:5, 12, replace = T)
df.main <- data.frame(Subject,GroupOfInterest, Feature1, Feature2, 
Feature3, stringsAsFactors = FALSE)

到目前为止,我的尝试使用了 for 循环:

Feat <- c(colnames(df.main[3:5]))    
for (q in Feat){
df_sum = ddply(df.main, ~GroupOfInterest + Subject,
            summarise, q =mean(get(q)))
  }

我希望提供如下输出(尽管我意识到现在需要一个单独的合并函数):

但是,根据我的操作方式,我要么得到一个错误(“get(q) 中的错误:第一个参数无效”),要么它平均一个特征的所有值,而不是按主题和 GroupOfInterest 分组。

我也尝试过使用列表和 lapply,但遇到了类似的困难。

从我收集的信息来看,我的问题在于 ddply 期待 Feature1。但是,如果我循环遍历,我要么为它提供“Feature1”(字符串)或(1,14,14,16,17 ...),它不再是主题和组分组所需的数据框的一部分.

非常感谢您在解决这个问题和教我这个过程的工作原理方面提供的任何帮助。

【问题讨论】:

  • 好问题。它迫使学习许多基本的东西

标签: r for-loop get apply plyr


【解决方案1】:

OP 提到使用简单的for-loop 进行数据转换。我知道还有许多其他优化的方法可以解决这个问题,但为了尊重OP 的期望,我尝试使用基于for-loop 的解决方案。我使用了dplyr,因为plyr 现在已经旧了。

library(dplyr)
Subject <- c(rep(1, times = 6), rep(2, times = 6))
GroupOfInterest <- c(letters[rep(1:3, times = 4)])
Feature1 <- sample(1:20, 12, replace = T)
Feature2 <- sample(400:500, 12, replace = T)
Feature3 <- sample(1:5, 12, replace = T)
#small change in the way data.frame is created 
df.main <- data.frame(Subject,GroupOfInterest, Feature1, Feature2, 
 Feature3, stringsAsFactors = FALSE)

Feat <- c(colnames(df.main[3:5])) 

# Ready with Key columns on which grouping is done
resultdf <- unique(select(df.main, Subject, GroupOfInterest))
#> resultdf
#  Subject GroupOfInterest
#1       1               a
#2       1               b
#3       1               c
#7       2               a
#8       2               b
#9       2               c


#For loop for each column
for(q in Feat){
  summean <- paste0('mean(', q, ')')
  summ_name <- paste0(q) #Name of the column to store sum
  df_sum <- df.main %>% 
     group_by(Subject, GroupOfInterest) %>%
    summarise_(.dots = setNames(summean, summ_name)) 
  #merge the result of new sum column in resultdf
  resultdf <- merge(resultdf, df_sum, by = c("Subject", "GroupOfInterest"))
}

# Final result
#> resultdf
#  Subject GroupOfInterest Feature1 Feature2 Feature3
#1       1               a      6.5    473.0      3.5
#2       1               b      4.5    437.0      2.0
#3       1               c     12.0    415.5      3.5
#4       2               a     10.0    437.5      3.0
#5       2               b      3.0    447.0      4.5
#6       2               c      6.0    462.0      2.5

【讨论】:

  • 非常感谢您的回答!是的,我同意有更好的方法来做到这一点,但是以这种方式学习很好,所以我不必对现有代码进行太多修改。
  • 我编辑了我的帖子以包含您制作 df (stringsasfactors = F) 的方式。只是添加我需要更改的内容以使我的代码为未来的读者工作:1. summarise_ 是我应该使用的 dplyr 函数 2. .dots= 是告诉 dplyr 你正在提供新争论的方式 3. 拥有连接成新变量的函数是绕过函数不接受变量 (q) 的一种方法。 *请随时纠正或澄清
【解决方案2】:

根据评论编辑;需要包含 as.character(.)

你能用summarise_at吗?还有辅助函数vars(contains(...))?

df.main %>% 
    group_by(Subject, GroupOfInterest) %>% 
    summarise_at(vars(contains("Feature")), funs(mean(as.numeric(as.character(.)))))

【讨论】:

  • plyr 是一个较旧的包,其后继者 (imo) 更易于使用且更直观。 @CPak 的解决方案使用了dplyr,这让这个问题变得非常简单。
  • stackoverflow.com/questions/10178203/…,显然summarise in plyr 很难做到这一点。
  • 您的解决方案在这里不起作用,您需要在转换为数字之前转换为字符:df.main %&gt;% group_by(Subject, GroupOfInterest) %&gt;% summarise_at(vars(contains("Feature")), funs(mean(as.numeric(as.character(.)))))
【解决方案3】:

上面给出了dlyr的解决方案,但公平地说,这里是data.table一个

DT <- setDT(df.main)
DT[,lapply(.SD,function(x){mean(as.numeric(as.character(x)))}),
.SDcols = names(DT)[grepl("Feature",names(DT))], by = .(Subject,GroupOfInterest)]

   Subject GroupOfInterest Feature1 Feature2 Feature3
1:       1               a      6.5    459.5      2.0
2:       1               b     11.0    480.5      4.0
3:       1               c      9.5    453.0      4.5
4:       2               a      3.5    483.0      1.5
5:       2               b      8.0    449.0      3.5
6:       2               c     11.5    424.0      1.0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-26
    • 2013-09-08
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 2023-03-11
    相关资源
    最近更新 更多