【问题标题】:Mutate within a for loop在 for 循环中改变
【发布时间】:2021-03-06 02:51:36
【问题描述】:

我有一个这样的数据框

structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4, 
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4, 
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4, 
2, 2, 7, 5, 2)), .Names = c("Love_ABC", "Love_CNN", "Hate_ABC", "Hate_CNN", "Love_CNBC", "Hate_CNBC"), row.names = c(NA, 
8L), class = "data.frame")

我做了以下for循环

channels = c("ABC", "CNN", "CNBC")

for (channel in channels) { 
dataframe <- dataframe %>%
  mutate(ALL_channel = Love_channel + Hate_channel)
  }

但是当我运行 for 循环时,R 告诉我找不到“对象 Love_channel”。我在 for 循环中做错了吗?

【问题讨论】:

  • 你的预期输出是什么?
  • 三个新列“ALL_CNN”、“ALL_ABC”、“ALL_CNBC”,其中每一行对应于对应的love_channel+hate_channel之和。例如,ALL_CNN = Love_CNN+Hate_CNN
  • 您的数据中有Love_channelHate_channel 列吗?我没有看到他们。
  • 不,我有 Love_ABC 和 Hate_ABC,但我在 channels = c("ABC", "CNN", "CNBC") 上做了一个 for 循环,并指出:for channel in channels

标签: r for-loop if-statement dplyr tidyverse


【解决方案1】:

这是rlang 的一种方式。请注意,重塑数据可能更直接。非标准评估(NSE)是一个复杂的话题。

for (channel in channels) { 
  DF <- DF %>%
    mutate(!!sym(paste0("ALL_", channel)) := !!sym(paste0("Love_", channel)) + !!sym(paste0("Hate_", channel)))
}
DF

##   Love_ABC Love_CNN Hate_ABC Hate_CNN Love_CNBC Hate_CNBC ALL_ABC ALL_CNN ALL_CNBC
## 1        1        1        6        6         1         2       7       7        3
## 2        3        3        3        2         2         3       6       5        5
## 3        4        4        6        4         4         4      10       8        8
## 4        6        2        5        5         5         2      11       7        7
## 5        3        6        3        3         6         2       6       9        8
## 6        2        7        6        7         7         7       8      14       14
## 7        5        2        5        2         6         5      10       4       11
## 8        1        6        3        6         3         2       4      12        5

【讨论】:

    【解决方案2】:

    这是dplyrtidyr 的解决方案:

    library(tidyr)
    library(dplyr)
    
    dataframe <- dataframe %>%
      tibble::rowid_to_column()
    
    dataframe %>% 
      pivot_longer(-rowid, names_to = c(NA, "channel"), names_sep = "_") %>% 
      pivot_wider(names_from = channel, names_prefix = "ALL_", values_from = value, values_fn = sum) %>% 
      right_join(dataframe, by = "rowid") %>% 
      select(-rowid)
    #> # A tibble: 8 x 9
    #>   ALL_ABC ALL_CNN ALL_CNBC Love_ABC Love_CNN Hate_ABC Hate_CNN Love_CNBC Hate_CNBC
    #>     <dbl>   <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>     <dbl>     <dbl>
    #> 1       7       7        3        1        1        6        6         1         2
    #> 2       6       5        5        3        3        3        2         2         3
    #> 3      10       8        8        4        4        6        4         4         4
    #> 4      11       7        7        6        2        5        5         5         2
    #> 5       6       9        8        3        6        3        3         6         2
    #> 6       8      14       14        2        7        6        7         7         7
    #> 7      10       4       11        5        2        5        2         6         5
    #> 8       4      12        5        1        6        3        6         3         2
    

    我们的想法是重塑它以使总和更容易。然后您可以将最终结果连接回初始数据帧。

    • 首先使用rowid 唯一标识每一行。
    • pivot_longer 重塑,以便将所有值整齐地放在一列中。在此步骤中,您还将名称 Love/Hate_channel 分成两部分,并删除 Love/Hate 部分(您只对频道感兴趣)[这是 NA 所做的!]。
    • 再次重塑:这次您希望为每个通道获取一列。在此步骤中,您还将为每个 rowid 和频道总结之前的 LoveHate(这就是 values_fn=sum 所做的!)。您还可以为每个新列名称添加一个前缀 (names_prefix = "ALL_"),以使名称符合您预期的最终结果。
    • 使用right_join 将值添加回原始数据帧。你现在不需要rowid,所以你可以删除它。

    【讨论】:

    • 嘿江户,非常感谢!理论上这正是我想要的,但我需要用不均匀的系数和其他新列来做,所以我希望能够自己写求和的公式,而不仅仅是求和......
    • “不均匀系数”是什么意思?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    相关资源
    最近更新 更多