我的数据框由%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_()
语句以符合新语法?
请不要硬编码列名。我的实际数据集中的列数比我提供的示例中的列数多,但我们的想法是每个月只有两年。
答案 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