R data.table - 按列分组包括列表
R data.table - group by column includes list
我尝试使用 R 中 data.table 包的功能分组。
start <- as.Date('2014-1-1')
end <- as.Date('2014-1-6')
time.span <- seq(start, end, "days")
a <- data.table(date = time.span, value=c(1,2,3,4,5,6), group=c('a','a','b','b','a','b'))
date value group
1 2014-01-01 1 a
2 2014-01-02 2 a
3 2014-01-03 3 b
4 2014-01-04 4 b
5 2014-01-05 5 a
6 2014-01-06 6 b
a[,mean(value),by=group]
> group V1
1: a 2.6667
2: b 4.3333
这很好用。
由于我使用的是日期,所以一个特殊的日期可能不仅有一组,还有两组。
a <- data.table(date = time.span, value=c(1,2,3,4,5,6), group=list('a',c('a','b'),'b','b','a','b'))
date value group
1 2014-01-01 1 a
2 2014-01-02 2 c("a", "b")
3 2014-01-03 3 b
4 2014-01-04 4 b
5 2014-01-05 5 a
6 2014-01-06 6 b
a[,mean(value),by=group]
> Error in `[.data.table`(a, , mean(value), by = group) :
The items in the 'by' or 'keyby' list are length (1,2,1,1,1,1). Each must be same length as rows in x or number of rows returned by i (6).
我希望使用两个组的组日期来计算 a 组和 b 组的平均值。
预期结果:
mean a: 2.6667
mean b: 3.75
data.table 包可以吗?
更新
谢谢 akrun 我最初的问题已经解决了。在 "splitting" 之后 data.table 并且在我的例子中计算不同的因素(基于组)我需要 data.table 回到它的 "original" 形式,具有基于日期的唯一行。到目前为止我的解决方案:
a <- data.table(date = time.span, value=c(1,2,3,4,5,6), group=list('a',c('a','b'),'b','b','a','b'))
b <- a[rep(1:nrow(a), lengths(group))][, group:=unlist(a$group)]
date value group
1 2014-01-01 1 a
2 2014-01-02 2 a
3 2014-01-02 2 b
4 2014-01-03 3 b
5 2014-01-04 4 b
6 2014-01-05 5 a
7 2014-01-06 6 b
# creates new column with mean based on group
b[,factor := mean(value), by=group]
#creates new data.table c without duplicate rows (based on date) + if a row has group a & b it creates the product of their factors
c <- b[,.(value = unique(value), group = list(group), factor = prod(factor)),by=date]
date value group factor
01/01/14 1 a 2.666666667
02/01/14 2 c("a", "b") 10
03/01/14 3 b 3.75
04/01/14 4 b 3.75
05/01/14 5 a 2.666666667
06/01/14 6 b 3.75
我想这不是完美的方法,但它确实有效。有什么建议我可以做得更好吗?
备选方案(真的很慢!!!):
d <- a[rep(1:nrow(a), lengths(group))][,group:=unlist(a$group)][, mean(value), by = group]
for(i in 1:NROW(a)){
y1 <- 1
for(j in a[i,group][[1]]){
y1 <- y1 * d[group==j, V1]
}
a[i, factor := y1]
}
我目前最快的解决方案:
# split rows that more than one group
b <- a[rep(1:nrow(a), lengths(group))][, group:=unlist(a$group)]
# calculate mean of different groups
b <- b[,factor := mean(value), by=group]
# only keep date + factor columns
b <- b[,.(date, factor)]
# summarise rows by date
b <- b[,lapply(.SD,prod), by=date]
# add summarised factor column to initial data.table
c <- merge(a,b,by='date')
有机会让它更快吗?
一个选项是按行顺序分组,我们 unlist
list
列 ('group'),paste
list
元素放在一起(toString(..)
),用splitstackshape
中的cSplit
和direction='long'
重塑成'long'格式,然后得到[=的mean
46=] 列使用 'grp' 作为分组变量。
library(data.table)
library(splitstackshape)
a[, grp:= toString(unlist(group)), 1:nrow(a)]
cSplit(a, 'grp', ', ', 'long')[, mean(value), grp]
# grp V1
#1: a 2.666667
#2: b 3.750000
刚刚意识到使用 splitstackshape
的另一个选项是 listCol_l
,其中 unlist
是一个 list
列的长格式。由于输出是 data.table
,我们可以使用 data.table
方法来计算 mean
。得到 mean
.
要紧凑得多
listCol_l(a, 'group')[, mean(value), group_ul]
# group_ul V1
#1: a 2.666667
#2: b 3.750000
或者不使用 splitstackshape
的另一种选择是通过 list
元素的 length
复制数据集的行。 lengths
是 sapply(group, length)
的方便包装器,而且速度更快。然后,我们通过 unlist
ing 来自 'a' 数据集的原始 'group' 来更改 'group' 列,并得到 'value' 的 mean
,按 'group'.
a[rep(1:nrow(a), lengths(group))][,
group:=unlist(a$group)][, mean(value), by = group]
# group V1
#1: a 2.666667
#2: b 3.750000
@mike-h 在 中发布的更短的解决方案也使用 unlist()
但按其余列分组:
require(data.table)
a = data.table(date = time.span,
value = c(1,2,3,4,5,6),
group = list('a',c('a','b'),'b','b','a','b'))
a[ , .(group = unlist(group)), .(date, value)][ , mean(value), group ]
我尝试使用 R 中 data.table 包的功能分组。
start <- as.Date('2014-1-1')
end <- as.Date('2014-1-6')
time.span <- seq(start, end, "days")
a <- data.table(date = time.span, value=c(1,2,3,4,5,6), group=c('a','a','b','b','a','b'))
date value group
1 2014-01-01 1 a
2 2014-01-02 2 a
3 2014-01-03 3 b
4 2014-01-04 4 b
5 2014-01-05 5 a
6 2014-01-06 6 b
a[,mean(value),by=group]
> group V1
1: a 2.6667
2: b 4.3333
这很好用。
由于我使用的是日期,所以一个特殊的日期可能不仅有一组,还有两组。
a <- data.table(date = time.span, value=c(1,2,3,4,5,6), group=list('a',c('a','b'),'b','b','a','b'))
date value group
1 2014-01-01 1 a
2 2014-01-02 2 c("a", "b")
3 2014-01-03 3 b
4 2014-01-04 4 b
5 2014-01-05 5 a
6 2014-01-06 6 b
a[,mean(value),by=group]
> Error in `[.data.table`(a, , mean(value), by = group) :
The items in the 'by' or 'keyby' list are length (1,2,1,1,1,1). Each must be same length as rows in x or number of rows returned by i (6).
我希望使用两个组的组日期来计算 a 组和 b 组的平均值。
预期结果:
mean a: 2.6667
mean b: 3.75
data.table 包可以吗?
更新
谢谢 akrun 我最初的问题已经解决了。在 "splitting" 之后 data.table 并且在我的例子中计算不同的因素(基于组)我需要 data.table 回到它的 "original" 形式,具有基于日期的唯一行。到目前为止我的解决方案:
a <- data.table(date = time.span, value=c(1,2,3,4,5,6), group=list('a',c('a','b'),'b','b','a','b'))
b <- a[rep(1:nrow(a), lengths(group))][, group:=unlist(a$group)]
date value group
1 2014-01-01 1 a
2 2014-01-02 2 a
3 2014-01-02 2 b
4 2014-01-03 3 b
5 2014-01-04 4 b
6 2014-01-05 5 a
7 2014-01-06 6 b
# creates new column with mean based on group
b[,factor := mean(value), by=group]
#creates new data.table c without duplicate rows (based on date) + if a row has group a & b it creates the product of their factors
c <- b[,.(value = unique(value), group = list(group), factor = prod(factor)),by=date]
date value group factor
01/01/14 1 a 2.666666667
02/01/14 2 c("a", "b") 10
03/01/14 3 b 3.75
04/01/14 4 b 3.75
05/01/14 5 a 2.666666667
06/01/14 6 b 3.75
我想这不是完美的方法,但它确实有效。有什么建议我可以做得更好吗?
备选方案(真的很慢!!!):
d <- a[rep(1:nrow(a), lengths(group))][,group:=unlist(a$group)][, mean(value), by = group]
for(i in 1:NROW(a)){
y1 <- 1
for(j in a[i,group][[1]]){
y1 <- y1 * d[group==j, V1]
}
a[i, factor := y1]
}
我目前最快的解决方案:
# split rows that more than one group
b <- a[rep(1:nrow(a), lengths(group))][, group:=unlist(a$group)]
# calculate mean of different groups
b <- b[,factor := mean(value), by=group]
# only keep date + factor columns
b <- b[,.(date, factor)]
# summarise rows by date
b <- b[,lapply(.SD,prod), by=date]
# add summarised factor column to initial data.table
c <- merge(a,b,by='date')
有机会让它更快吗?
一个选项是按行顺序分组,我们 unlist
list
列 ('group'),paste
list
元素放在一起(toString(..)
),用splitstackshape
中的cSplit
和direction='long'
重塑成'long'格式,然后得到[=的mean
46=] 列使用 'grp' 作为分组变量。
library(data.table)
library(splitstackshape)
a[, grp:= toString(unlist(group)), 1:nrow(a)]
cSplit(a, 'grp', ', ', 'long')[, mean(value), grp]
# grp V1
#1: a 2.666667
#2: b 3.750000
刚刚意识到使用 splitstackshape
的另一个选项是 listCol_l
,其中 unlist
是一个 list
列的长格式。由于输出是 data.table
,我们可以使用 data.table
方法来计算 mean
。得到 mean
.
listCol_l(a, 'group')[, mean(value), group_ul]
# group_ul V1
#1: a 2.666667
#2: b 3.750000
或者不使用 splitstackshape
的另一种选择是通过 list
元素的 length
复制数据集的行。 lengths
是 sapply(group, length)
的方便包装器,而且速度更快。然后,我们通过 unlist
ing 来自 'a' 数据集的原始 'group' 来更改 'group' 列,并得到 'value' 的 mean
,按 'group'.
a[rep(1:nrow(a), lengths(group))][,
group:=unlist(a$group)][, mean(value), by = group]
# group V1
#1: a 2.666667
#2: b 3.750000
@mike-h 在 unlist()
但按其余列分组:
require(data.table)
a = data.table(date = time.span,
value = c(1,2,3,4,5,6),
group = list('a',c('a','b'),'b','b','a','b'))
a[ , .(group = unlist(group)), .(date, value)][ , mean(value), group ]