Transponha / remodele o dataframe sem “timevar” do formato longo para o formato amplo

Eu tenho um quadro de dados que segue o padrão longo abaixo:

Name MedName Name1 atenolol 25mg Name1 aspirin 81mg Name1 sildenafil 100mg Name2 atenolol 50mg Name2 enalapril 20mg 

E gostaria de obter abaixo (eu não me importo se eu posso obter as colunas a serem nomeadas dessa maneira, só quero os dados neste formato):

  Name medication1 medication2 medication3 Name1 atenolol 25mg aspirin 81mg sildenafil 100mg Name2 atenolol 50mg enalapril 20mg NA 

Através deste mesmo site eu me familiarizei com o pacote reshape / reshape2, e passei por várias tentativas de tentar fazer isso funcionar, mas até agora falharam.

Quando eu tento dcast(dataframe, Name ~ MedName, value.var='MedName') eu só pegar um monte de colunas que são sinalizadores dos nomes de medicamentos (valores que são transpostos são 1 ou 0) exemplo:

  Name atenolol 25mg aspirin 81mg Name1 1 1 Name2 0 0 

Eu também tentei um dcast(dataset, Name ~ variable) depois que eu derreti o dataset, no entanto, isso apenas mostra o seguinte (apenas conta quantos medicamentos cada pessoa tem):

  Name MedName Name1 3 name2 2 

Finalmente, tentei derreter os dados e, em seguida, reformular usando idvar="Name" timevar="variable" (dos quais todos são apenas Mednames), no entanto isso não parece construído para o meu problema, pois se houver várias correspondências para o idvar, a mudança apenas pega o primeiro MedName e ignora o resto.

Alguém sabe como fazer isso usando a reformulação ou outra function R? Eu percebo que provavelmente há uma maneira de fazer isso de uma maneira mais confusa com alguns loops for e condicionais para basicamente dividir e colar novamente os dados, mas eu esperava que houvesse uma solução mais simples. Muito obrigado!

    Supondo que seus dados estão no dataset do object:

     library(plyr) ## Add a medication index data_with_index < - ddply(dataset, .(Name), mutate, index = paste0('medication', 1:length(Name))) dcast(data_with_index, Name ~ index, value.var = 'MedName') ## Name medication1 medication2 medication3 ## 1 Name1 atenolol 25mg aspirin 81mg sildenafil 100mg ## 2 Name2 atenolol 50mg enalapril 20mg  

    Você sempre pode gerar um timevar exclusivo antes de usar a reshape . Aqui eu uso ave para aplicar a function seq_along ‘junto’ a cada “Nome”.

     test < - data.frame( Name=c(rep("name1",3),rep("name2",2)), MedName=c("atenolol 25mg","aspirin 81mg","sildenafil 100mg", "atenolol 50mg","enalapril 20mg") ) # generate the 'timevar' test$uniqid <- with(test, ave(as.character(Name), Name, FUN = seq_along)) # reshape! reshape(test, idvar = "Name", timevar = "uniqid", direction = "wide") 

    Resultado:

      Name MedName.1 MedName.2 MedName.3 1 name1 atenolol 25mg aspirin 81mg sildenafil 100mg 4 name2 atenolol 50mg enalapril 20mg  

    Com o pacote data.table , isso poderia ser facilmente resolvido com a nova function rowid :

     library(data.table) dcast(setDT(d1), Name ~ rowid(Name, prefix = "medication"), value.var = "MedName") 

    que dá:

      Name medication1 medication2 medication3 1 Name1 atenolol 25mg aspirin 81mg sildenafil 100mg 2 Name2 atenolol 50mg enalapril 20mg  

    Outro método (comumente usado antes da versão 1.9.7):

     dcast(setDT(d1)[, rn := 1:.N, by = Name], Name ~ paste0("medication",rn), value.var = "MedName") 

    dando o mesmo resultado.


    Uma abordagem semelhante, mas agora usando os pacotes dplyr e tidyr :

     library(dplyr) library(tidyr) d1 %>% group_by(Name) %>% mutate(rn = paste0("medication",row_number())) %>% spread(rn, MedName) 

    que dá:

     Source: local data frame [2 x 4] Groups: Name [2] Name medication1 medication2 medication3 (fctr) (chr) (chr) (chr) 1 Name1 atenolol 25mg aspirin 81mg sildenafil 100mg 2 Name2 atenolol 50mg enalapril 20mg NA 

    Isso parece ser um problema bastante comum, então incluí uma function chamada getanID no meu pacote “splitstackshape”.

    Veja o que faz:

     library(splitstackshape) getanID(test, "Name") # Name MedName .id # 1: name1 atenolol 25mg 1 # 2: name1 aspirin 81mg 2 # 3: name1 sildenafil 100mg 3 # 4: name2 atenolol 50mg 1 # 5: name2 enalapril 20mg 2 

    Já que “data.table” é carregado junto com “splitstackshape”, você tem access ao dcast.data.table , assim você pode proceder como no exemplo do @mnel.

     dcast.data.table(getanID(test, "Name"), Name ~ .id, value.var = "MedName") # Name 1 2 3 # 1: name1 atenolol 25mg aspirin 81mg sildenafil 100mg # 2: name2 atenolol 50mg enalapril 20mg NA 

    A function essencialmente implementa uma sequence(.N) pelos grupos identificados para criar a coluna “time”.

    @ A solução do thelatemail é semelhante a esta. Quando eu rle a variável time, eu uso rle caso eu não esteja trabalhando de forma interativa e a variável Name precise ser dinâmica.

     # start with your example data x < - data.frame( Name=c(rep("name1",3),rep("name2",2)), MedName=c("atenolol 25mg","aspirin 81mg","sildenafil 100mg", "atenolol 50mg","enalapril 20mg") ) # pick the id variable id <- 'Name' # sort the data.frame by that variable x <- x[ order( x[ , id ] ) , ] # construct a `time` variable on the fly x$time <- unlist( lapply( rle( as.character( x[ , id ] ) )$lengths , seq_len ) ) # `reshape` uses that new `time` column by default y <- reshape( x , idvar = id , direction = 'wide' ) # done y 

    Aqui está um caminho mais curto, aproveitando a maneira como o unlist lida com nomes:

     library(dplyr) df1 %>% group_by(Name) %>% do(as_tibble(t(unlist(.[2])))) # # A tibble: 2 x 4 # # Groups: Name [2] # Name MedName1 MedName2 MedName3 #     # 1 name1 atenolol 25mg aspirin 81mg sildenafil 100mg # 2 name2 atenolol 50mg enalapril 20mg