【问题标题】:How can I create new column in data frame by aggregating rows?如何通过聚合行在数据框中创建新列?
【发布时间】:2017-08-17 23:36:30
【问题描述】:

我有一个大型(约 20 万行)数据框,其结构如下:

df <-
 data.frame(c(1,1,1,1,1), c('blue','blue','blue','blue','blue'), c('m','m','m','m','m'), c(2016,2016,2016,2016,2016),c(3,4,5,6,7), c(10,20,30,40,50))

colnames(df) <- c('id', 'color', 'size', 'year', 'week','revenue')

假设现在是第 7 周,我想将过去 4 周的平均收入与当前一周的收入进行比较。我想做的是在所有标识符都匹配时为该平均值创建一个新列。

df_new <-
 data.frame(1, 'blue', 'm', 2016,7,50, 25 )

colnames(df_new) <- c('id', 'color', 'size', 'year', 'week','revenue', 't4ave')

我怎样才能有效地做到这一点?谢谢你的帮助

【问题讨论】:

  • 您的df_new 是否应该替换适当的行或附加它?似乎您需要对zoo::rollapply 使用分组功能(例如bydplyr::group_by)。您希望这个新列对于预先存在的行的值是多少?
  • 理想情况下它会附加现有的行。因此,如果 df$week 的值是 3、4、5、6 或 7,则会创建新列,并针对第 7 周(当前周)中特征的每个唯一排列以及周 = 3 中的每个值计算 t4ave, 4,5,6 会有 t4ave = 0。不过,任何完成类似事情的方法都会有所帮助
  • 我逻辑上理解你想要什么,分析上觉得很难处理。我的意思是它破坏了数据的理想性质:您现在不能再假设所有行都具有相同的含义:该行是每周总和,除非同一周有两个(等),在这种情况下其中一个是周数据,一个是4周的汇总,要知道我需要知道汇总列的非汇总值是什么......然后取另一个......你看到我在哪里'我同意这个吗?也许如果这仅用于输出/报告,那么可以,但是...
  • 我不确定我是否理解您的担忧。它主要用于报告目的,特别是查看本周与过去 4 周平均值(本周不包括在内)的比较,以确定本周飙升/下降的变量。感谢您迄今为止的帮助和思考。

标签: r dataframe aggregate


【解决方案1】:

好问题。 for 循环效率很低,但是由于您确实必须检查先前条目的条件,因此这是我能想到的唯一解决方案(请注意,我也是 R 的中间人):

for (i in 1:nrow(df))
{
    # condition for all entries to match up
    if ((i > 5) && (df$id[i] == df$id[i-1] == df$id[i-2] == df$id[i-3] == df$id[i-4])
    && (df$color[i] == df$color[i-1] == df$color[i-2] == df$color[i-3] == df$color[i-4])
    && (df$size[i] == df$size[i-1] == df$size[i-2] == df$size[i-3] == df$size[i-4])
    && (df$year[i] == df$year[i-1] == df$year[i-2] == df$year[i-3] == df$year[i-4])
    && (df$week[i] == df$week[i-1] == df$week[i-2] == df$week[i-3] == df$week[i-4]))

    # avg of last 4 entries' revenues
    avg <- mean(df$revenue[i-1] + df$revenue[i-2] + df$revenue[i-3] + df$revenue[i-4])

    # create new variable of difference between this entry and last 4's
    df$diff <- df$revenue[i] - avg
}

这段代码可能需要很长时间,但它应该可以工作。如果这是代码需要运行的一次性事情,那么应该没问题。否则,希望其他人能够提供建议。

【讨论】:

  • 我应该在帖子中提到我尝试了一个 for 循环 - 我在 df 的一部分中成功运行了它,但是当我尝试运行整个事情时,我在 30 分钟后变得不耐烦并决定在这里发帖。非常感谢您的帮助。
  • 啊,我明白了……如果找不到更有效的解决方案,也许可以通宵运行?
【解决方案2】:

使用dplyrzoo 的解决方案。想法是将相同的变量分组,例如idcolorsizeyear。之后,使用rollmean 计算收入的滚动平均值。使用na.pad = TRUEalign = "right" 确保计算涵盖最近几周。最后,使用lag 将计算结果“移位”以适应您的需求。

library(dplyr)
library(zoo)

df2 <- df %>%
  group_by(id, color, size, year) %>%
  mutate(t4ave = rollmean(revenue, 4, na.pad = TRUE, align = "right")) %>%
  mutate(t4ave = lag(t4ave))
df2
# A tibble: 5 x 7
# Groups:   id, color, size, year [1]
     id  color   size  year  week revenue t4ave
  <dbl> <fctr> <fctr> <dbl> <dbl>   <dbl> <dbl>
1     1   blue      m  2016     3      10    NA
2     1   blue      m  2016     4      20    NA
3     1   blue      m  2016     5      30    NA
4     1   blue      m  2016     6      40    NA
5     1   blue      m  2016     7      50    25

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-05
    • 2019-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多