【问题标题】:adding new variables to a data frame using dplyr select and mutate functions in a for loop在 for 循环中使用 dplyr select 和 mutate 函数向数据框添加新变量
【发布时间】:2018-05-11 21:31:06
【问题描述】:

如果这是重复的,请告诉我。我查看了 Stack 并发现了类似的问题,但并没有完全回答我的问题。我是初学者,所以我感谢任何人的帮助。

我正在尝试将年度汇总变量添加到每月数据的数据框中(即跨行求和)。这是一个包含有限月度数据的示例数据框。

df <- data.frame("Jan.2012" = c(1, 4, 5, 6), "Feb.2012" = c(3, 5, 7, 9),
 "Jan.2013" = c(6, 8, 9, 10), "Feb.2013" = c(7, 5, 11, 13), "Jan.2014" = c(6, 8, 9, 11), 
 "Feb.2014" = c(7, 3, 5, 9))

新变量将命名为 TotalYr2012、TotalYr2013 等。例如,TotalYr2012 = c(4, 9, 12, 15) 等。

我正在尝试遍历 for 循环(不是我知道的最佳实践)来生成这些变量。我知道我在 assign 语句中做错了一些事情,并且出现了错误。

for (i in 2012:2014) {
  varname <- paste("TotalYr", i, sep = "")
    assign(df$varname, df %>% select(contains("i")) %>% 
     mutate(varname = sum()))
}

感谢您的帮助!

【问题讨论】:

  • $ 不适用于变量,您需要使用[[[。 (但您还有其他几个问题)。

标签: r for-loop dplyr


【解决方案1】:

您可以通过使用tidyr::gatherzoo::yearmon 函数计算每年的汇总来避免for-loop

library(tidyverse)
library(zoo)

df %>% gather(Date, value) %>%
  mutate(Date = as.yearmon(Date,"%b.%Y")) %>%
  group_by(Year = year(Date)) %>%
  summarise(Total = sum(value)) %>%
  spread(Year, Total)

# # A tibble: 1 x 3
#     `2012` `2013` `2014`
# *   <dbl>  <dbl>  <dbl>
# 1   40.0   69.0   58.0  

【讨论】:

  • 我很感激。我一定没有清楚地解释自己。我想对 df 行求和,因为每条记录代表 2012 年 1 月的产品 X 销售额、2013 年 2 月的产品 Y 销售额等。所以我想查看 2012 年月份的所有产品 X 销售额等. 然而,看到这段代码确实帮助我理解了一个 dplyr 方法来得到我想要的答案,所以谢谢!
【解决方案2】:

你有很多问题。

  1. $ 不适用于变量。请改用[[[See this R-FAQ for additional info。你的缩进也很乱,让我们保持一致:

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      assign(df[[varname]], df %>% select(contains("i")) %>% 
        mutate(varname = sum()))
    }
    
  2. 不需要assign,只需使用&lt;-(或=)。你几乎不应该使用assign()

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      df[[varname]] <- df %>% select(contains("i")) %>% 
        mutate(varname = sum()))
    }
    
  3. "i" 是一个字符串,它的值总是字母"i",就像2 的值总是2。即使在contains() 中,您也想使用您分配给对象i(尽管该值 确实需要是字符串,即需要是character类):

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      df[[varname]] <- df %>% select(contains(as.character(i))) %>% 
        mutate(varname = sum()))
    }
    
  4. mutateselect 返回数据帧,这意味着您的代码正在尝试分配一个单列数据帧执行 df[[varname]]。我们只想分配一个列向量,而不是整个数据框。所以我们拉出列向量,用dplyr::pull

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      df[[varname]] <- df %>% select(contains(as.character(i))) %>% 
        mutate(varname = sum())) %>%
        pull()
    }
    
  5. 在您的控制台中输入sum() - 您会得到0。你需要给sum()一些东西。让我们完全摆脱mutate,只删除sum pulled 向量,这样我们就不用担心它的名字了:

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      df[[varname]] <- df %>% select(contains(as.character(i))) %>% 
        pull %>% sum
    }
    
  6. 好的,现在有点用了。但是您将这些新值添加到具有一堆行的旧数据框中。新值只是单个值,因此它们被“回收”,在数据框的每一行上重复。让我们创建一个新的result 数据框来代替我们的结果只有一行:

    result = list()
    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      result[[varname]] <- df %>% select(contains(as.character(i))) %>% 
        pull %>% sum
    }
    result = as.data.frame(result)
    result
    #   TotalYr2012 TotalYr2013 TotalYr2014
    # 1          24          36          24
    
  7. 现在它可以工作了,并提供了一个可行的解决方案。但是,它仍然很乱。 for 循环通常不是必需的。我们有更好的数据整理工具。

    # See MKR's answer. It's the way you should actually do this.
    

【讨论】:

  • 精彩的解释,几乎涵盖了所有内容。可能你的回答比我的对初学者更有帮助。
  • 我的回答涵盖了 OP 方法的问题,您的回答涵盖了正确的方法。我认为它们相得益彰。
  • 谢谢你们俩。通过阅读您分享的原则,我学到了很多未来项目的一般原则。
  • 但是,当我在 RStudio 中运行此代码时,结果返回一个包含 0 行和 0 列的数据框。如果我遗漏了什么,请告诉我。
  • 我忘记在 #6 中将最后一个 df 更改为 result。现已修复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-21
  • 2023-02-24
  • 2016-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多