使用dplyr 0.7.0使用字符串执行mutate()

时间:2018-03-02 15:21:31

标签: r dplyr

我的数据框由%Y_%m形式的列组成,每个%Y有两个值%m,如下所示:

library(dplyr)

df <- data.frame(cat = c("cat1", "cat2", "cat3", "cat4"),
                 `2017_1` = c(25, 48, 34, 72),
                 `2018_1` = c(50, 34, 32, 18),
                 `2017_2` = c(30, 23, 84, 29),
                 `2018_2` = c(28, 48, 21, 15))

colnames(df) <- sub("X", "", colnames(df))

> df
   cat 2017_1 2018_1 2017_2 2018_2
1 cat1     25     50     30     28
2 cat2     48     34     23     48
3 cat3     34     32     84     21
4 cat4     72     18     29     15

我想按月计算同比(YOY)百分比变化,YOY(month) = value(month[most current])/value(month[least current])

mth <- sub(".*_", "", colnames(df))
mth <- mth[mth != "cat"]
mth <- unique(mth)

for (i in 1:length(mth)){
  temp <- df %>%
    select(cat, ends_with(paste0("_", mth[i])))
  yrs <- regmatches(colnames(df), regexpr("^.*?(?=_)", colnames(df), perl = TRUE)) 
  mutate_str <- paste0("YOY_", mth[i], " = `", yrs[2], "_", 
                       mth[i], "`/`", yrs[1], "_", mth[i], "`-1")
  rm(yrs)

  temp <- temp %>%
    mutate_(mutate_str)
  rm(mutate_str)

  temp <- temp %>%
    select(cat, contains("YOY"))
  if (i == 1){
    output <- temp
    rm(temp)
  } else {
    output <- inner_join(output, temp, by = "cat")
    rm(temp)
  }
}
rm(i, mth)

colnames(output) <- sub(" =.*", "", colnames(output))

正在吐出的所需输出如下:

> output
   cat       YOY_1       YOY_2
1 cat1  1.00000000 -0.06666667
2 cat2 -0.29166667  1.08695652
3 cat3 -0.05882353 -0.75000000
4 cat4 -0.75000000 -0.48275862

我理解,鉴于dplyr的最新更新,mutate_()将被淘汰。特别是如何重写mutate_()语句以符合新语法?

请不要硬编码列名。我的实际数据集中的列数比我提供的示例中的列数多,但我们的想法是每个月只有两年。

1 个答案:

答案 0 :(得分:1)

您的数据格式不整齐,这就是dplyr代码在这里如此挣扎的原因。更容易做的事情是将数据转换为整齐的格式(使用tidyr),然后进行处理。没有任何循环或动态表达式构建,这将做同样的事情。

library(dplyr)
library(tidyr)

df %>% gather(x, value, -cat) %>%
  separate(x, c("year","index")) %>% 
  group_by(cat, index) %>% 
  arrange(year) %>%
  summarize(yoy=last(value)/first(value)-1) %>%
  mutate(index=paste("YOY", index, sep="_")) %>% 
  spread(index, yoy)

#      cat       yoy_1       yoy_2
# * <fctr>       <dbl>       <dbl>
# 1   cat1  1.00000000 -0.06666667
# 2   cat2 -0.29166667  1.08695652
# 3   cat3 -0.05882353 -0.75000000
# 4   cat4 -0.75000000 -0.48275862