2011-11-04 38 views
17

Aylık bir veri data.table ve yıllık verileri başka bir data.table var ve şimdi yıllık verileri aylık verilerdeki ilgili gözlemle eşleştirmek istiyorum.Verilerdeki data.table etkinliğinde çoğaltma yollarım var mı?

Benim yaklaşımım şu şekildedir: Her ay için yıllık verileri çoğaltma ve ardından aylık ve yıllık verilere katılma. Ve şimdi satırların çoğaltılması ile ilgili bir sorum var. Bunu nasıl yapacağımı biliyorum ama bunu yapmanın en iyi yolu olup olmadığından emin değilim, bu yüzden bazı görüşler harika olurdu.

İşte benim yıllık veriler için bir exemplatory data.table DT ve ben şu anda çoğaltmak nasıl:

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 
[...] 

son istediğim tam olarak ne katılmak. Ancak, DT[, list(MONTH=startMonth:endMonth), by="ID"] zaten diğer sütunları DT'a eklemek dışında istediğim her şeyi yapıyor, bu yüzden kodumdaki son üç satırdan, yani setkey ve join işlemlerinden kurtulabilir miyim diye merak ediyordum. Bu, sadece aşağıdakileri yapabilirsiniz, çıkıyor: Ben list ifadeye sütun adları kodlanmış çünkü

#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 
... 

Ancak bu, yalnızca çalışır. Gerçek verilerimde, tüm sütunların isimlerini önceden bilmiyorum, bu yüzden'unumaralı sütunu, yukarıdaki gibi ve diğer tüm sütunları DT olarak gösterdiğim şekilde döndürüp döndüremeyeceğimi anlayabiliyordum. .SD hile yapabilmek için görünüyordu, ama:

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) 

yüzden bu yapıldı nasıl olduğunu özetlemek için, ama yine de mücadele ediyorum çünkü bunu yapmak için en iyi yoldur diye merak edildi data.table sözdizimi ile biraz ve genellikle yazılarda ve wiki'de okumak iyi ve kötü şeyler yapmanın yollarının olduğunu. Ayrıca, .SD kullanırken neden hata alıyorum. Tüm sütunları istediğinizi data.table bildirmenin kolay bir yolu olduğunu düşündüm. Ne özledim

cevap

11

Harika bir soru. Denediğin şey çok mantıklıydı. V1.7.1 kullandığınızı varsayalım artık list sütunlarını yapmak artık daha kolay. Bu durumda, 2. grubun (4 öğe) MONTH sütununun yanına bir list sütunu .SD (3 öğe) dışında yapmaya çalışmaktadır. Bir hata olarak geliştireceğim [DÜZENLEME: şimdi v1.7.5'te düzeltildi], teşekkürler.

arada

, deneyin:

Ayrıca
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 
... 

, sadece roll=TRUE gördüğüm kontrol edilir? Tipik olarak sadece bir startMonth sütunu (boşluklarla düzensiz) ve daha sonra sadece roll ürününe katılabilirsiniz. Örnek verileriniz çakışan ay aralıklarına sahip olsa da, karmaşık hale getirir.

0

Burada yazdığım bir işlevi yazdım: disaggregate (karmaşık verileri işleyen bir şeye ihtiyacım vardı). Aşırı değilse, sizin için yararlı olabilir. Yalnızca satırları genişletmek için, fact argümanını c (1,12) olarak ayarlayın, burada 12, her 'yıl' satırı için 12 'aylık' satırlar içindir.

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)) 
} 
9

Buna baktığımda, cevabın sadece ID'un benzersiz bir anahtar olması (yinelenen olmadan) olması nedeniyle mümkün olduğunu anladım. İşte yinelenen başka bir cevap. Ancak, bu arada, bazı NA sürünüyor gibi görünüyor. Bu bir hata olabilir mi? V1.8.7 kullanıyorum (taahhüt 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 

Sadece şeyiyle daha hızlı bir şekilde rep satır numaraları etmektir ve ardından tek adımda alt kümesini (hiçbir gruplaşma ve cbind veya .SD ait hiçbir faydası) atın:

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 

Bu örnek verisinde, rep numaralı sütunun rep() ana işleviyle aynı ad olduğu ortaya çıkar.

+0

teşekkür. Ben koştum (v1.8.7) ama ben 'NA' göremiyorum. Hangi sürüme sahipsiniz? –

+0

Teşekkürler. Hala 'NA' görmüyorum ama şimdi iki uyarı olsun hem özdeş:' 1'de: rep: sayısal ifade 2 öğesi vardır: sadece ilk used' –

+0

deneyin en son (796) daha sonra ilk adım, lütfen, sadece üzere yönetin. –

-2

bunu yapmanın en hızlı ve en sözün yolu:

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

Biz de tarafından grup tarafından numaralandırabilmesidir:

dd <- DT[rep(1:nrow(DT), endMonth - startMonth)] 
dd[, nn := 1:.N, by = ID] 
dd 
+0

Ayrıca grup ile numaralandırmayı da yapabiliriz: dd = DT [rep (1: nrow (DT), bitişMonth-startMonth] – user7238835

+0

Ayrıca grup tarafından numaralandırmayı da yapabiliriz: 'code' dd = DT [rep (1: nrow (DT), endMonth-startMonth)] dd [, nn: = 1 :.N, ile = ID] 'code' – user7238835

+0

Lütfen cevabınızı düzenleyin, yorum bölümünü doldurmayın. Yukarıdaki _edit_ bağlantısını kullanın. – Marcs