24

我有一个月度数据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,所以我想知道我是否可以摆脱代码中的最后三行,即setkeyandjoin操作。事实证明,您可以,只需执行以下操作:

#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您想要所有列的任何简单方法。我想念什么?

4

4 回答 4

14

看着这个,我意识到答案是唯一可能的,因为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行号,然后一步获取子集(不分组也不使用cbindor .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()

于 2013-01-16T13:35:45.357 回答
13

好问题。你尝试的非常合理。假设您使用的是 v1.7.1,现在更容易制作list列。在这种情况下,它试图在第二组(4 项)的 MONTH 列旁边从(3 项)中创建一list列。.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加入它。但是,您的示例数据具有重叠的月份范围,因此使其复杂化。

于 2011-11-04T15:28:21.513 回答
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))
}
于 2011-11-04T14:13:50.040 回答
-2

最快最简洁的方法:

DT[rep(1:nrow(DT), endMonth - startMonth)]

我们还可以按组枚举:

dd <- DT[rep(1:nrow(DT), endMonth - startMonth)]
dd[, nn := 1:.N, by = ID]
dd
于 2016-12-01T23:52:23.993 回答