如何计算数据框列的变化百分比,然后是下一个,依此类推?

时间:2017-11-02 01:43:18

标签: r

我有以下数据框,称之为“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()函数,但是我还没有成功。 (我对这门语言还很陌生。)

我真的很感激如何最好地解决这个问题。谢谢!

3 个答案:

答案 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)