2013-05-17 55 views
3

我有一個data.table DT我怎樣才能重塑我的data.table有效

set.seed(1) 
DT <- data.table(x=rep(c(1,2,3),each=4), y=c("A","B"), v=sample(1:100,12)) 
DT 
    x y v 
1: 1 A 29 
2: 1 B 92 
3: 1 A 100 
4: 1 B 82 
5: 2 A 28 
6: 2 B 26 
7: 2 A 18 
8: 2 B 22 
9: 3 A 30 
10: 3 B 96 
11: 3 A 15 
12: 3 B 4 

我想擴大它像波紋管,創造的x每個值的新列並報告v值,在數據結構不應該期望(不是像波紋管塊)

x y v.1 v.2 v.3 
1: 1 A 29 NA NA 
2: 1 B 92 NA NA 
3: 1 A 100 NA NA 
4: 1 B 82 NA NA 
5: 2 A NA 28 NA 
6: 2 B NA 26 NA 
7: 2 A NA 18 NA 
8: 2 B NA 22 NA 
9: 3 A NA NA 30 
10: 3 B NA NA 96 
11: 3 A NA NA 15 
12: 3 B NA NA 4 

我問了一個非常類似的問題here但無法適應答案摹格羅騰迪克給了我們當時的...

編輯: 像往常一樣,我寫了後我幾乎得到它......我只需要用NA代替那些0(我可能在v中得到0,我想能夠解離v == 0從缺項)

DT2 <- DT[, {SUM.<-factor(x); data.table(model.matrix(~ SUM.:v + 0))}] 
txtR) DT2 
    SUM.1:v SUM.2:v SUM.3:v 
1:  29  0  0 
2:  92  0  0 
3:  100  0  0 
4:  82  0  0 
5:  0  28  0 
6:  0  26  0 
7:  0  18  0 
8:  0  22  0 
9:  0  0  30 
10:  0  0  96 
11:  0  0  15 
12:  0  0  4 

回答

4
set.seed(1) 
DT <- data.table(x=rep(c(1,2,3),each=4), y=c("A","B"), v=sample(1:100,12)) 

這給

x y v 
1: 1 A 27 
2: 1 B 37 
3: 1 A 57 
4: 1 B 89 
5: 2 A 20 
6: 2 B 86 
7: 2 A 97 
8: 2 B 62 
9: 3 A 58 
10: 3 B 6 
11: 3 A 19 
12: 3 B 16 

接下來,答曰:

ux <- unique(DT$x) 
DT[,c(v.=lapply(ux,function(i)v[x==i])),by="x,y"] 

這給

x y v.1 v.2 v.3 
1: 1 A 27 NA NA 
2: 1 A 57 NA NA 
3: 1 B 37 NA NA 
4: 1 B 89 NA NA 
5: 2 A NA 20 NA 
6: 2 A NA 97 NA 
7: 2 B NA 86 NA 
8: 2 B NA 62 NA 
9: 3 A NA NA 58 
10: 3 A NA NA 19 
11: 3 B NA NA 6 
12: 3 B NA NA 16 

這個答案可能R中的更高版本的突破,但OP指出,這個工程太大,可能會更快:

DT[,paste0("v.",ux):=lapply(ux,function(i)v[x==i]),by="x"] 
+0

我認爲'by = x'足夠嗎? – Arun

+1

嗯,無論如何,所需的輸出有一個「Y」列。如果不把它放在'by'中,我會不得不做一些類似合併或DT [,c(list(y = y),v。= lapply(1:3,function(i)v [x == I])),通過= 「X」]'? – Frank

+0

@Frank,我想是的。你現在的答案'by =「x,y」'不會與OP的要求相同。仔細查看你爲列獲得的值,並與我的數據進行比較..(除了NA,在創建model.matrix時我仍不知道如何替換)。 – Arun

3

這裏有一種方法:

tt <- model.matrix(data=DT, ~ factor(x):rep(1, nrow(DT)) + 0) 
tt[tt==0] <- NA 
cbind(DT, DT$v * tt) 
#  x y v factor(x)1:v factor(x)2:v factor(x)3:v 
# 1: 1 A 69   69   NA   NA 
# 2: 1 B 39   39   NA   NA 
# 3: 1 A 76   76   NA   NA 
# 4: 1 B 49   49   NA   NA 
# 5: 2 A 100   NA   100   NA 
# 6: 2 B 95   NA   95   NA 
# 7: 2 A 36   NA   36   NA 
# 8: 2 B 73   NA   73   NA 
# 9: 3 A 86   NA   NA   86 
# 10: 3 B 20   NA   NA   20 
# 11: 3 A 59   NA   NA   59 
# 12: 3 B 12   NA   NA   12 
+0

上也得到了警告......看到我的編輯這些0s的確是個問題... – statquant

+0

你看到一個伎倆,以NA取代這些0它是太糟糕,因爲它是lightnin'快... – statquant

+0

@statquant,不直接,但我已經管理..檢查編輯please。 – Arun

3

可能只是在x上循環並使用data.table作業:

setkey(DT, x) 
for (i in unique(DT$x)) { 
    DT[J(i), paste0("v.", i) := v] 
} 

P.S.我真的希望下面的工作,但.GRP但是不適用:

DT[, paste0("v.", .GRP) := v, by = x] 

編輯多了一個解決方案(試圖獲得上述.GRP想法以某種方式工作),採用rbind.fill(我沒有跑很小心長凳,但這似乎相當好)

library(plyr) 

cbind(DT, 
     rbind.fill(DT[, list(list(setnames(data.table(v), paste0("v.", .GRP)))), 
         by = x]$V1)) 
+2

+1。回覆:第二個想法,這聽起來像一個很好的功能要求,呃? – Frank

+0

如果要求啓用'DT [,paste0(「v。」,.GRP):= v,by = x]'的功能,那麼它會很好,如果它包含一個設施來指定填充值,需要「NA」。 –

+0

@弗蘭克,我第二個這個。但我認爲這已經提前一段時間了.. iirc。我認爲這是迄今爲止最快的,特別是因爲列已經在data.table中分配了。 – Arun