我有以下数据框,称之为“p”:
Q1 Q2 Q3
X Product 4.986184956 5.083868356 5.109861156
Y Product 2.86990877 2.834816682 2.904347607
Z Product 6.58413545 6.238497279 6.40142101
我想计算p中每个列之间的百分比变化,并将每列的输出放入一个名为“pchange”的新数据框中。
我尝试过使用lag()函数,但是我还没有成功。 (我对这门语言还很陌生。)
我真的很感激如何最好地解决这个问题。谢谢!
答案 0 :(得分:1)
以下是一些不同的方法。没有包使用。
1)除了前两列以外的所有列除了第一列和最后一列,减去1并乘以100.将其与原始第一列和原始第二列的NA相结合。
data.frame(DF[1], NA * DF[2], 100 * (DF[-(1:2)] / DF[-c(1, ncol(DF))] - 1))
,并提供:
Product Q1 Q2 Q3
1 X Product NA 1.959081 0.511280
2 Y Product NA -1.222760 2.452749
3 Z Product NA -5.249560 2.611586
1a)(1)的变体甚至更短是基于在日志域中工作然后转换回来:
data.frame(DF[1], NA * DF[2], 100 * t(exp(diff(t(log(DF[-1]))))-1))
,并提供:
Product Q1 Q2 Q3
1 X Product NA 1.959081 0.511280
2 Y Product NA -1.222760 2.452749
3 Z Product NA -5.249560 2.611586
2)定义一个函数percent
,根据向量x
计算百分比,返回与填充第一个元素的x
长度相同的向量NA,因为没有先验值来计算其百分比。然后将其应用于每一行,注意apply
将返回我们想要的转置,以便将其转置回来。
percent <- function(x) 100 * c(NA * x[1], diff(x) / head(x, -1))
data.frame(DF[1], t(apply(DF[-1], 1, percent)))
,并提供:
Product Q1 Q2 Q3
1 X Product NA 1.959081 0.511280
2 Y Product NA -1.222760 2.452749
3 Z Product NA -5.249560 2.611586
注意:可重复形式的输入DF
被假定为:
DF <- structure(list(Product = structure(1:3, .Label = c("X Product",
"Y Product", "Z Product"), class = "factor"), Q1 = c(4.986184956,
2.86990877, 6.58413545), Q2 = c(5.083868356, 2.834816682, 6.238497279
), Q3 = c(5.109861156, 2.904347607, 6.40142101)), .Names = c("Product",
"Q1", "Q2", "Q3"), class = "data.frame", row.names = c(NA, -3L
))
答案 1 :(得分:0)
通过整理数据框架可以最轻松地实现干净且易于扩展的解决方案。主题可能变得复杂,但实际上只需要使每行成为一个观察,每列是一个变量。
虽然在列之间构建直接引用可能会让您快速获胜,但如果您开始添加更多列,则会被迫编写更多代码。有了整洁的数据,你就不会。整洁的解决方案将处理更新数据,而不会进一步打嗝。
使用您的数据框视图的重建:p
library(tidyverse)
id <- c("X", "Y", "Z")
object <- "Product"
Q1 <- c(4.986184956, 2.86990877, 6.58413545)
Q2 <- c(5.083868356, 2.834816682, 6.238497279)
Q3 <- c(5.109861156, 2.904347607, 6.40142101)
p <- tibble(id, object, Q1, Q2, Q3)
> p # A tibble: 3 x 5 id object Q1 Q2 Q3 <chr> <chr> <dbl> <dbl> <dbl> 1 X Product 4.986185 5.083868 5.109861 2 Y Product 2.869909 2.834817 2.904348 3 Z Product 6.584135 6.238497 6.401421
然后您可以在 tidyverse 中执行转换,如下所示:
tidy_p_change <-
p %>%
gather(qrtr, perf, c(Q1:Q3)) %>% # tidy the data
arrange(id, qrtr) %>% # prep for lag (and easy auditing)
group_by(id) %>% # keep the lags within products
mutate(prev_q = lag(perf), # bring data together into same row
pct_chng = (perf/prev_q - 1)*100
) %>%
select(-c(perf, prev_q)) %>% # stop showing the work
spread(qrtr, pct_chng) # spread the data back out into a `pivot table`
这将为您提供此输出:
> tidy_p_change # A tibble: 3 x 5 # Groups: id [3] id object Q1 Q2 Q3 * <chr> <chr> <dbl> <dbl> <dbl> 1 X Product NA 1.959081 0.511280 2 Y Product NA -1.222760 2.452749 3 Z Product NA -5.249560 2.611586
我以冗长的形式离开了争吵。我可以将电线更紧凑,但最好显示所有步骤。如果您希望看到更加糟糕的版本,请告诉我们。
另外,在Hadley Wickham的R for Data Science
中可以找到一个关于处理整洁数据(以及在tidyverse中工作)的非常好的处理方法。答案 2 :(得分:0)
从我的上述评论中复制。使用dplyr::transmute:
pchange <- df %>%
transmute(
change_Q1_Q2 = ((Q2 - Q1)/Q1)*100,
change_Q2_Q3 = ((Q3 - Q2)/Q2)*100
)
给出
# A tibble: 3 x 2
change_Q1_Q2 change_Q2_Q3
<dbl> <dbl>
1 1.959081 0.511280
2 -1.222760 2.452749
3 -5.249560 2.611586
如果您想保留“产品”列,则可以使用mutate
代替transmute
。我赞同Jens Leerssen对R for Data Science的支持。
(假设您的数据结构如此)
df <- tibble::tribble(
~Product, ~Q1, ~Q2, ~Q3,
"X Product", 4.986184956, 5.083868356, 5.109861156,
"Y Product", 2.86990877, 2.834816682, 2.904347607,
"Z Product", 6.58413545, 6.238497279, 6.40142101)