我有一个data.table
的月度数据和另一个data.table
的年度数据,现在我想将年度数据与月度数据中的相应观察值进行匹配。
我的方法如下:复制每个月的年度数据,然后加入月度和年度数据。现在我有一个关于行重复的问题。我知道怎么做,但我不确定这是不是最好的方法,所以有些意见会很棒。
以下是我年度数据的示例data.table DT
以及我目前的复制方式:
library(data.table)
DT <- data.table(ID = paste(rep(c("a", "b"), each=3), c(1:3, 1:3), sep="_"),
values = 10:15,
startMonth = seq(from=1, by=2, length=6),
endMonth = seq(from=3, by=3, length=6))
DT
ID values startMonth endMonth
[1,] a_1 10 1 3
[2,] a_2 11 3 6
[3,] a_3 12 5 9
[4,] b_1 13 7 12
[5,] b_2 14 9 15
[6,] b_3 15 11 18
#1. Alternative
DT1 <- DT[, list(MONTH=startMonth:endMonth), by="ID"]
setkey(DT, ID)
setkey(DT1, ID)
DT1[DT]
ID MONTH values startMonth endMonth
a_1 1 10 1 3
a_1 2 10 1 3
a_1 3 10 1 3
a_2 3 11 3 6
[...]
最后一次加入正是我想要的。但是,DT[, list(MONTH=startMonth:endMonth), by="ID"]
已经做了我想做的一切,除了将其他列添加到DT
,所以我想知道我是否可以摆脱代码中的最后三行,即setkey
和join
次操作。事实证明,您可以,只需执行以下操作:
#2. Alternative: More intuitiv and just one line of code
DT[, list(MONTH=startMonth:endMonth, values, startMonth, endMonth), by="ID"]
ID MONTH values startMonth endMonth
a_1 1 10 1 3
a_1 2 10 1 3
a_1 3 10 1 3
a_2 3 11 3 6
...
然而,这只能起作用,因为我将列名硬编码到list
表达式中。在我的真实数据中,我事先并不知道所有列的名称,所以我想知道我是否可以告诉data.table
返回我计算的列MONTH
如上所示以及所有其他列DT
的列。 .SD
似乎能够做到这一点,但是:
DT[, list(MONTH=startMonth:endMonth, .SD), by="ID"]
Error in `[.data.table`(DT, , list(YEAR = startMonth:endMonth, .SD), by = "ID") :
maxn (4) is not exact multiple of this j column's length (3)
总而言之,我知道它是如何完成的,但我只是想知道这是否是最好的方法,因为我仍然在使用data.table
的语法稍微挣扎并经常阅读帖子和维基上有好的和坏的做事方式。另外,我不明白为什么在使用.SD
时出现错误。我认为只是告诉data.table
你想要所有列的任何简单方法。我错过了什么?
答案 0 :(得分:13)
好问题。你尝试的是非常合理的。假设您正在使用v1.7.1,现在可以更轻松地创建list
列。在这种情况下,它试图在list
(3项)中与第2组的MONTH列(4项)一起制作一个.SD
列。我会把它作为一个错误[编辑:现在在v1.7.5中修复],谢谢。
在此期间,请尝试:
DT[, cbind(MONTH=startMonth:endMonth, .SD), by="ID"]
ID MONTH values startMonth endMonth
a_1 1 10 1 3
a_1 2 10 1 3
a_1 3 10 1 3
a_2 3 11 3 6
...
另外,只是为了检查一下你看过roll=TRUE
?通常,您只有一个startMonth列(不规则的间隙),然后只有roll
加入它。您的示例数据虽然具有重叠的月份范围,但这会使其复杂化。
答案 1 :(得分:11)
看着这个我意识到答案是唯一可能的,因为ID
是一个唯一的密钥(没有重复)。这是另一个重复的答案。但是,顺便说一下,有些NA
似乎在悄悄进入。这可能是一个错误吗?我正在使用v1.8.7(提交796)。
library(data.table)
DT <- data.table(x=c(1,1,1,1,2,2,3),y=c(1,1,2,3,1,1,2))
DT[,rep:=1L][c(2,7),rep:=c(2L,3L)] # duplicate row 2 and triple row 7
DT[,num:=1:.N] # to group each row by itself
DT
x y rep num
1: 1 1 1 1
2: 1 1 2 2
3: 1 2 1 3
4: 1 3 1 4
5: 2 1 1 5
6: 2 1 1 6
7: 3 2 3 7
DT[,cbind(.SD,dup=1:rep),by="num"]
num x y rep dup
1: 1 1 1 1 1
2: 2 1 1 1 NA # why these NA?
3: 2 1 1 2 NA
4: 3 1 2 1 1
5: 4 1 3 1 1
6: 5 2 1 1 1
7: 6 2 1 1 1
8: 7 3 2 3 1
9: 7 3 2 3 2
10: 7 3 2 3 3
为了完整起见,更快捷的方法是rep
行号,然后在一步中获取子集(不分组,不使用cbind
或.SD
):
DT[rep(num,rep)]
x y rep num
1: 1 1 1 1
2: 1 1 2 2
3: 1 1 2 2
4: 1 2 1 3
5: 1 3 1 4
6: 2 1 1 5
7: 2 1 1 6
8: 3 2 3 7
9: 3 2 3 7
10: 3 2 3 7
在此示例数据中,列rep
恰好与rep()
基函数同名。
答案 2 :(得分:0)
这是我写的一个模仿disaggregate
的函数(我需要处理复杂数据的东西)。它可能对你有用,如果它不是矫枉过正的话。要仅扩展行,请将参数fact
设置为c(1,12),其中12将为每个'年'行的12个月'行。
zexpand<-function(inarray, fact=2, interp=FALSE, ...) {
fact<-as.integer(round(fact))
switch(as.character(length(fact)),
'1' = xfact<-yfact<-fact,
'2'= {xfact<-fact[1]; yfact<-fact[2]},
{xfact<-fact[1]; yfact<-fact[2];warning(' fact is too long. First two values used.')})
if (xfact < 1) { stop('fact[1] must be > 0') }
if (yfact < 1) { stop('fact[2] must be > 0') }
# new nonloop method, seems to work just ducky
bigtmp <- matrix(rep(t(inarray), each=xfact), nrow(inarray), ncol(inarray)*xfact, byr=T)
#does column expansion
bigx <- t(matrix(rep((bigtmp),each=yfact),ncol(bigtmp),nrow(bigtmp)*yfact,byr=T))
return(invisible(bigx))
}
答案 3 :(得分:-2)
最快捷,最简洁的方式:
DT[rep(1:nrow(DT), endMonth - startMonth)]
我们也可以按组列举:
dd <- DT[rep(1:nrow(DT), endMonth - startMonth)]
dd[, nn := 1:.N, by = ID]
dd