2013-05-17 7 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 но не адаптируюсь ответ G Гротендик дал нам в то время ...

EDIT: Как обычно, я просто получил его после того, как написал запись ... Мне просто нужно заменить эти 0 на NA (я мог бы получить 0 в v, и я хочу, чтобы уметь отделять 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, но ОП отметил, что это тоже работает и может быть быстрее:

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 == я])), с = "х"] '? – 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

... см. мой EDIT, эти 0s действительно являются проблемой ... – statquant

+0

вы видите трюк, чтобы заменить эти 0s на NA, это слишком плохо, потому что это легко ... – statquant

+0

@statquant, не просто, но мне удалось .. проверьте редактирование, пожалуйста. – 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. Re: Вторая идея, которая звучит как хороший запрос функции, а? – Frank

+0

Если была запрошена функция, включающая 'DT [, paste0 (" v. ", .GRP): = v, by = x]', было бы неплохо, если бы она включала средство для задания значения заполнения в случае какого-либо другого значения, чем 'NA' были желательны. –

+0

@Frank, я второй это. Но я думаю, что это было поднято когда-то раньше .. iirc. И я думаю, что это будет самым быстрым на сегодняшний день, тем более, что столбцы уже выделены в data.table .. – Arun