2014-12-05 3 views
1

У меня есть data.frame с тремя столбцами:Как подвести один столбец на основе ключа двух других столбцов

To  Amount Type 
Smith $1  A 
John $5  B 
Jeff $8  A 
Smith $4  C 
... ...  ... 

И мне нужно, чтобы преобразовать его в кадр данных, который показывает, сколько денег каждого типа каждый человек получил.

Name TotalAmtOfTypeA TotalAmtOfTypeB TotalAmtOfTypeC ... 
Smith $1    $0    $4 
John $0    $5    $0 
Jeff $8    $0    $0 
... 

оригинальный data.frame длиной чуть более трех миллионов строк, поэтому более эффективным или распараллеливание решение, тем лучше. Использует ли решение aggregate? Или я должен смотреть в plyr? Любое руководство будет высоко оценено!

+0

Это решение включает в себя «изменение формы» фрейма данных. Существует базовая функция R 'reshape', но если вы хотите изучить dllr-семейные инструменты, пакет для использования - 'tidyr' (он дополняет' dplyr'). Посмотрите на функцию 'spread()' – konvas

ответ

2

Вот два варианта:

library(tidyr) 
spread(df, Type, Amount) 
#  To ordered.A ordered.B ordered.C 
#1 Jeff  $8  <NA>  <NA> 
#2 John  <NA>  $5  <NA> 
#3 Smith  $1  <NA>  $4 

Или

library(reshape2) 
dcast(df, To ~ Type, value.var = "Amount") 
#  To A B C 
#1 Jeff $8 <NA> <NA> 
#2 John <NA> $5 <NA> 
#3 Smith $1 <NA> $4 

Или, если вы измените класс столбца из фактора по характеру, вы можете сделать:

df$Amount <- as.character(df$Amount) 
dcast(df, To ~ Type, value.var = "Amount", fill = "$0") 
#  To A B C 
#1 Jeff $8 $0 $0 
#2 John $0 $5 $0 
#3 Smith $1 $0 $4 

И одинаково

spread(df, Type, Amount, fill = "$0") 
#  To A B C 
#1 Jeff $8 $0 $0 
#2 John $0 $5 $0 
#3 Smith $1 $0 $4 

Примечание: если оставить столбец «Сумма», как фактор и попытаться использовать fill = "$0" вы получите сообщение об ошибке, как это:

Warning message: In [<-.factor (*tmp* , is.na(ordered), value = 0) : invalid factor level, NA generated


Если вы хотите, чтобы избавиться от этих «$» в столбце Суммы, так что вы можете использовать эти цифры для дальнейшей обработки, вот как вы могли бы сделать это в dplyr/tidyr цепи:

library(dplyr) 
library(tidyr) 
df %>% 
    mutate(Amount = as.numeric(gsub("\\$", "", Amount))) %>% 
    spread(Type, Amount, fill = 0) 

#  To A B C 
#1 Jeff 8 0 0 
#2 John 0 5 0 
#3 Smith 1 0 4 
2

Вот data.table решения, которое должно работать крысу она быстро:

данных

library(data.table) 
n <- 1e6 
dat <- data.table(Name = LETTERS[sample(26, n, TRUE)], 
        Amount = rpois(n, 100), 
        Type = letters[sample(26, n, TRUE)]) 

Код

setkey(dat, Name, Type) 
dat.agg <- dat[, .(Sum = sum(Amount)), by =.(Name, Type)] 
dat.agg[, as.list(setattr(Sum, 'names', Type)), by = .(Name)] 

Объяснение

Первые [.data.table агрегаты Teh data.table иметь суммы всех Name/Type комбинации. Второй [.data.table, форматирует data.table так, как вы этого хотели. setattr используется для получения хорошего вывода (для подбора столбцов в соответствии с уровнями Type.

+0

Это похоже на правильный путь, но с моими реальными данными я получить ошибку: 'Ошибка в \' [.data.table \ '(pacdons2.agg,, as.list (setattr (Sum," names ",: j не оценивается с одинаковым количеством столбцов для каждой группы ' – eiowmqui

Смежные вопросы