在一段时间内按组查找平均值并检索同一时期的最后日期

ves*_*and 2 r dataframe dplyr data.table

下面是一个可重现的数据表,其中包含四列:

  1. 日期
  2. 类别
  3. 值1
  4. 值2

正如标题所示,我想计算每个类别的value1value2的平均值,并在结果数据框中保留这些类别的最后观察日期.

这是输入:

# Libraries
library(dplyr)
library(data.table)

# Reproducible data table
set.seed(1234)
date <- seq(as.Date("2017-01-01"), by = "month", length.out = 10)
category <- (c('A','A','B','B','C','C','C','C','C', 'C'))
value1 <- sample(seq(from = 91, to = 100, by = 1))
value2 <- sample(seq(from = 51, to = 60, by = 1))
dt <- data.table(date, category, value1, value2)
print(dt)

          date category value1 value2
 1: 2017-01-01        A     92     57
 2: 2017-02-01        A     96     55
 3: 2017-03-01        B     95     53
 4: 2017-04-01        B     98     60
 5: 2017-05-01        C     99     52
 6: 2017-06-01        C     94     59
 7: 2017-07-01        C     91     56
 8: 2017-08-01        C     97     51
 9: 2017-09-01        C    100     58
10: 2017-10-01        C     93     54
Run Code Online (Sandbox Code Playgroud)

这是我到目前为止:

dt2 <- dt %>% group_by(category) %>% summarise_each(funs(mean))
print(dt2)

# A tibble: 3 x 4
  category       date   value1 value2
     <chr>     <date>    <dbl>  <dbl>
1        A 2017-01-16 94.00000   56.0
2        B 2017-03-16 96.50000   56.5
3        C 2017-07-16 95.66667   55.0
Run Code Online (Sandbox Code Playgroud)

这是所需的输出:

  category       date   value1 value2
1        A 2017-02-01 94.00000   56.0
2        B 2017-04-01 96.50000   56.5
3        C 2017-10-01 95.66667   55.0
Run Code Online (Sandbox Code Playgroud)

谢谢你的任何建议!

www*_*www 6

这是data.table方法.我们可以.()使用j参数执行计算,并在参数中设置分组by.

dt[, .(date = last(date), value1 = mean(value1), value2 = mean(value2)), by = category]
Run Code Online (Sandbox Code Playgroud)

这是弗兰克开发的一种更有效的方式,作为对这篇文章的评论.这种方法只需要编写mean一次函数,使用.SD.SDcols指定要汇总的列.

dt[, c(.(date = last(date)), lapply(.SD, mean)), by = category, .SDcols = value1:value2]
Run Code Online (Sandbox Code Playgroud)

如果你想使用dplyr,你可以使用Z.Lin的方法.但是,如果有很多值列,例如value1to value10,则可以执行以下操作.

dt %>%
  group_by(category) %>%
  summarise_all(funs(if_else(is.numeric(.), mean(.), last(.))))
Run Code Online (Sandbox Code Playgroud)

如果列是数字,此代码将仅计算平均值,否则,它将报告组的最后一行.

最后提醒一下,summarise_each已被弃用.请使用summarise_all,summarise_ifsummarise_at.

  • @Frank感谢您分享您的解决方案并报告错误.这里需要`if_else`,因为`ifelse`会将日期列强制为数字. (2认同)
  • @Frank我注意到如果我将你的代码从`by = date`更改为`by = category`,这似乎会导致所需的输出没有警告或错误消息.经过您的许可,我想将您的解决方案添加到我的帖子中作为补充. (2认同)