R:在一个步骤中聚合具有不同函数的数据表

R:在一个步骤中聚合具有不同函数的数据表,r,data.table,aggregate,R,Data.table,Aggregate,我有一个数据表my_table,包含数字、字符和日期(POSIXct)列。现在我需要按日期聚合它,其中对于每个日期,数字列应按平均值聚合,字符和日期列应仅具有一个可用值(假设第一次出现)。我喜欢这样: name date value "test" 2018-04-04 1 "test" 2018-04-04 2 "test" 2018-04-05 8 "test" 2018-04-06 3

我有一个数据表
my_table
,包含数字、字符和日期(
POSIXct
)列。现在我需要
按日期聚合它,其中对于每个日期,数字列应按
平均值聚合,字符和日期列应仅具有一个可用值(假设第一次出现)。我喜欢这样:

  name          date    value
"test"    2018-04-04        1
"test"    2018-04-04        2
"test"    2018-04-05        8
"test"    2018-04-06        3
我想要这个:

  name          date    value
"test"    2018-04-04      1.5
"test"    2018-04-05      8.0
"test"    2018-04-06      3.0
我的做法是:

new_table <- aggregate(my_table, by=list(my_table$date), FUN=mean)
还有一堆警告,因为
name
不是数字。我如何告诉函数只使用一个(或第一个,我不介意)出现的
“test”
而不是
NA


让事情变得更难一些:在我的实际情况中,实际上有很多列需要使用mean(如果它们是数字)或第一次出现(如果它们是
character
POSIXct
)进行聚合

方法1 使用聚合的基本R解决方案

df <- transform(df, date = as.POSIXct(date))
aggregate(value ~ date + name, data = df, FUN = mean);
#date name value
#1 2018-04-04 test   1.5
#2 2018-04-05 test   8.0
#3 2018-04-06 test   3.0
表示
df
中除
以外的所有列

方法2
tidyverse
使用
groupby
summary
解决方案:

library(tidyverse)
df %>%
    mutate(date = as.POSIXct(date)) %>%
    group_by(date, name) %>%
    summarise(value = mean(value))
## A tibble: 3 x 3
## Groups:   date [?]
#  date                name  value
#  <dttm>              <fct> <dbl>
#1 2018-04-04 00:00:00 test   1.50
#2 2018-04-05 00:00:00 test   8.00
#3 2018-04-06 00:00:00 test   3.00

样本数据
df如果您实际上使用的是
data.table
,那么下面是聚合列的简单方法。从具有多个字符和数字列的数据集开始:

library(data.table)

my_table <- data.table(
  name1  = letters[1:4],
  name2  = LETTERS[23:26],
  date   = as.POSIXct(c("2018-04-04", "2018-04-04", "2018-04-05", "2018-04-06")),
  value1 = c(1, 2, 8, 3),
  value2 = c(9, 4, 2, 5)
)

my_table
#    name1 name2       date value1 value2
# 1:     a     W 2018-04-04      1      9
# 2:     b     X 2018-04-04      2      4
# 3:     c     Y 2018-04-05      8      2
# 4:     d     Z 2018-04-06      3      5
如果你担心这对大数据来说是低效的,不要。这里没有实际复制的数据

address(my_table$name1)
# [1] "0000000004601058"
address(character_data$name1)
# [1] "0000000004601058"
然后,我们将根据
date
列的值汇总字符和数值。
数据的
j
部分。表
可以有任何常规的R代码,在每个分组内部执行。
.SD
变量是by组作为
data.table
的子集,因此我们可以使用它来获取数字或字符列

numeric_data <- Filter(is.numeric, my_table)
numeric_columns <- names(numeric_data)
numeric_columns
# [1] "value1" "value2"

character_data <- Filter(is.character, my_table)
character_columns <- names(character_data)
character_columns
# [1] "name1" "name2"
my_table[
  ,
  {
    means <- lapply(
      X   = .SD[, numeric_columns, with = FALSE],
      FUN = mean
    )
    firsts <- .SD[1, character_columns, with = FALSE]
    append(firsts, means)
  },
  by = "date"
]
#          date name1 name2 value1 value2
# 1: 2018-04-04     a     W    1.5    6.5
# 2: 2018-04-05     c     Y    8.0    2.0
# 3: 2018-04-06     d     Z    3.0    5.0
my_表[
,
{

意思是您可以根据变量的类定义自己的摘要函数来执行您想要的操作

my_table <- read.table(text =
                       "  name          date    value
                         test    2018-04-04        1
                         test    2018-04-04        2
                         test    2018-04-05        8
                         test    2018-04-06        3", 
                       header = T)

my_summarise <- function(x){
  if(is.numeric(x)) mean(x)
  else if(is.character(x)) x[1]
  else if(is.factor(x)) x[1]
  else if('POSIXct' %in% class(x)) x[1]
}

setDT(my_table)

my_table[, lapply(.SD, my_summarise), by = date]

#          date name value
# 1: 2018-04-04 test   1.5
# 2: 2018-04-05 test   8.0
# 3: 2018-04-06 test   3.0

我真的很喜欢使用Base R的那一个,但是如果我不能命名所有的列,在这种情况下,
date
name
?如果我有60多个列,其中我不知道它们的确切数据类型和顺序怎么办?那么我就不能像
value~date+name+col1+col2+…
那样列出它们。有什么办法吗?@s6hebern你呢可以使用
value~。
,其中点
表示除
value
之外的所有列
聚合
使用
公式
方法非常通用。我编辑了我的答案以给出一个示例。这都是非常棒的东西(喜欢
value~。
),但目前还不是我所需要的。编辑了这个问题,希望能让它更清楚一点。聚合做了它应该做的事情,我只需要去掉
NA
s。我可以用
NA.action
来解决这个问题吗?@s6hebern我看不到你的问题有任何变化。你可能忘记更新样本数据了吗?我建议你再做一次不要像你那样使用
aggregate
;使用公式方法,你不会得到
name
NA
s。我基本上需要另一种方法,也许这是误导性的。我需要聚合除
date
之外的所有列,因为这是聚合的基础。我想我就是不能用这种方法应该这样做,并且必须坚持@Renu的解决方案,但是您的示例让我对
聚合
有了深刻的了解,所以非常感谢这一点,因为它工作得很顺利,但是您必须首先执行
库(lubridate)
我在is.POSIXct(x)中得到了错误消息
error in is.POSIXct(x):找不到函数“is.POSIXct”
,所以我就这样做了,发现我必须使用
lubridate
软件包。这很好,当然在我的现实世界中,使用函数的解决方案实际上是必要的。对于这个非常基本的示例,可能不是,但我有一大堆不同的列,我无法一直键入
numeric_data <- Filter(is.numeric, my_table)
numeric_columns <- names(numeric_data)
numeric_columns
# [1] "value1" "value2"

character_data <- Filter(is.character, my_table)
character_columns <- names(character_data)
character_columns
# [1] "name1" "name2"
address(my_table$name1)
# [1] "0000000004601058"
address(character_data$name1)
# [1] "0000000004601058"
my_table[
  ,
  {
    means <- lapply(
      X   = .SD[, numeric_columns, with = FALSE],
      FUN = mean
    )
    firsts <- .SD[1, character_columns, with = FALSE]
    append(firsts, means)
  },
  by = "date"
]
#          date name1 name2 value1 value2
# 1: 2018-04-04     a     W    1.5    6.5
# 2: 2018-04-05     c     Y    8.0    2.0
# 3: 2018-04-06     d     Z    3.0    5.0
my_table <- read.table(text =
                       "  name          date    value
                         test    2018-04-04        1
                         test    2018-04-04        2
                         test    2018-04-05        8
                         test    2018-04-06        3", 
                       header = T)

my_summarise <- function(x){
  if(is.numeric(x)) mean(x)
  else if(is.character(x)) x[1]
  else if(is.factor(x)) x[1]
  else if('POSIXct' %in% class(x)) x[1]
}

setDT(my_table)

my_table[, lapply(.SD, my_summarise), by = date]

#          date name value
# 1: 2018-04-04 test   1.5
# 2: 2018-04-05 test   8.0
# 3: 2018-04-06 test   3.0
my_table[, .(name, mean(value)), by = date]