将列转换为行而不指定列名称

时间:2015-05-19 14:32:32

标签: r reshape2 tidyr

我有一个具有以下结构的数据框:

type

我需要将它收集到这样的东西中。每行应包含一个id,参与者和角色。

bad_df <- data.frame(
id = c("id001", "id002", "id003"),
participant.1 = c("Jana", "Marina", "Vasilei"),
participant.2 = c("Niko", "Micha", "Niko"),
role.1 = c("writer", "writer", "speaker"),
role.2 = c("observer", "observer", "observer"),
stringsAsFactors = F
)
bad_df

我看到无数问题非常类似,但我发现很难理解如何将good_df <- data.frame( id = c("id001", "id001", "id002", "id002", "id003", "id003"), participant = c("Jana", "Niko", "Marina", "Micha", "Vasilei", "Niko"), role = c("writer", "observer", "writer", "observer", "speaker", "observer"), stringsAsFactors = F ) good_df tidyr应用于这种情况。我知道这必须以某种方式使用gather()。

但是,数据框可能包含更多参与者和相应的角色,因此理想情况下,该方法不需要指定列名。我想出的一个解决方案如下,但我不认为这是最优雅的方式。我仍然需要处理一些包含参与者3,角色3等的数据框。

reshape2

谢谢!

2 个答案:

答案 0 :(得分:4)

您可以尝试data.table的开发版本ie。 v1.9.5。安装说明为here

library(data.table)
melt(setDT(bad_df), measure=list(grep('participant', names(bad_df)),
    grep('role', names(bad_df))))[order(id)][, variable:= NULL]
#      id  value1   value2
#1: id001    Jana   writer
#2: id001    Niko observer
#3: id002  Marina   writer
#4: id002   Micha observer
#5: id003 Vasilei  speaker
#6: id003    Niko observer

或者我们可以使用merged.stack我们只需要提供唯一列的前缀。根据前缀值,它将对具有相同前缀的列进行分组。

library(splitstackshape)
merged.stack(bad_df, var.stubs=c('participant', 'role'), 
                       sep='var.stubs')[, 2:= NULL]
#      id participant     role
#1: id001        Jana   writer
#2: id001        Niko observer
#3: id002      Marina   writer
#4: id002       Micha observer
#5: id003     Vasilei  speaker
#6: id003        Niko observer

或使用dplyr/tidyr

library(dplyr)
library(tidyr)
gather(bad_df, Var, Val, -id) %>% 
        separate(Var, into=c('Var1', 'Var2')) %>% 
        spread(Var1, Val) %>%
        select(-Var2)
#    id participant     role
#1 id001        Jana   writer
#2 id001        Niko observer
#3 id002      Marina   writer
#4 id002       Micha observer
#5 id003     Vasilei  speaker
#6 id003        Niko observer

答案 1 :(得分:3)

我会在base R:

中走这条路
 #find the participant columns
 partCol<-grep("part",colnames(bad_df))
 #... and the role columns
 roleCol<-grep("role",colnames(bad_df))
 data.frame(id=rep(bad_df$id,each=length(partCol)),
            partecipant=as.vector(as.matrix(t(bad_df[,partCol]))),
            role=as.vector(as.matrix(t(bad_df[,roleCol]))))