将具有不同列长度的数据帧重新整形为两列,复制列ID

时间:2015-04-07 03:29:31

标签: r multiple-columns reshape

我有以下数据框,具有不同的行长度:

myvar <- as.data.frame(rbind(c("Walter","NA","NA","NA","NA"),
                             c("Walter","NA","NA","NA","NA"),
                             c("Walter","Jesse","NA","NA","NA"),
                             c("Gus","Tuco","Mike","NA","NA"), 
                             c("Gus","Mike","Hank","Saul","Flynn")))
ID <- as.factor(c(1:5))   
data.frame(ID,myvar)

ID     V1    V2   V3   V4    V5
 1 Walter    NA   NA   NA    NA
 2 Walter    NA   NA   NA    NA
 3 Walter Jesse   NA   NA    NA
 4    Gus  Tuco Mike   NA    NA
 5    Gus  Mike Hank Saul Flynn

我的目标是将此数据框切换为两列数据框。第一列是ID,另一列是字符名称。请注意,ID必须与字符最初放置的行相对应。我期待以下结果:

ID      V
1  Walter    
2  Walter
3  Walter
3  Jesse
4  Gus
4  Tuco
4  Mike
5  Gus
5  Mike
5  Hank
5  Saul
5  Flynn

我尝试过dcast {reshape2},但它没有返回我需要的内容。值得注意的是,我的原始数据框架相当大。有小费吗?欢呼声。

4 个答案:

答案 0 :(得分:7)

myvar <- as.data.frame(rbind(c("Walter","NA","NA","NA","NA"),
                             c("Walter","NA","NA","NA","NA"),
                             c("Walter","Jesse","NA","NA","NA"),
                             c("Gus","Tuco","Mike","NA","NA"), 
                             c("Gus","Mike","Hank","Saul","Flynn")))
ID <- as.factor(c(1:5))   
df <- data.frame(ID, myvar)

使用基础重塑。 (我将您的"NA"字符串转换为NA,您可能不需要这样做,这只是由于您创建此示例的原因)

df[df == 'NA'] <- NA
na.omit(reshape(df, direction = 'long', varying = list(2:6))[, c('ID','V1')])

#     ID     V1
# 1.1  1 Walter
# 2.1  2 Walter
# 3.1  3 Walter
# 4.1  4    Gus
# 5.1  5    Gus
# 3.2  3  Jesse
# 4.2  4   Tuco
# 5.2  5   Mike
# 4.3  4   Mike
# 5.3  5   Hank
# 5.4  5   Saul
# 5.5  5  Flynn

或使用reshape2

library('reshape2')
## na.omit(melt(df, id.vars = 'ID')[, c('ID','value')])

## or better yet as ananda suggests:
melt(df, id.vars = 'ID', na.rm = TRUE)[, c('ID','value')]

#    ID  value
# 1   1 Walter
# 2   2 Walter
# 3   3 Walter
# 4   4    Gus
# 5   5    Gus
# 8   3  Jesse
# 9   4   Tuco
# 10  5   Mike
# 14  4   Mike
# 15  5   Hank
# 20  5   Saul
# 25  5  Flynn

你得到的警告是,列上的因子水平不一样,但没关系。

答案 1 :(得分:7)

您可以使用unlist

 res <- subset(data.frame(ID,value=unlist(myvar[-1], 
                              use.names=FALSE)), value!='NA')
 res
 #   ID  value
 #1   1 Walter
 #2   2 Walter
 #3   3 Walter
 #4   4    Gus
 #5   5    Gus
 #6   3  Jesse
 #7   4   Tuco
 #8   5   Mike
 #9   4   Mike
 #10  5   Hank
 #11  5   Saul
 #12  5  Flynn

注意: NAs是&#39;字符&#39;数据集中的元素,最好不带引号创建它,以便它是真正的NA,我们可以通过na.omitis.nacomplete.cases等删除它。

数据

myvar <- data.frame(ID,myvar)

答案 2 :(得分:6)

修复您的"NA",使其真正NA首先:

mydf[mydf == "NA"] <- NA

使用一些子集来一举完成所有这些:

data.frame(ID=mydf$ID[row(mydf[-1])[!is.na(mydf[-1])]], V=mydf[-1][!is.na(mydf[-1])])

#   ID      V
#1   1 Walter
#2   2 Walter
#3   3 Walter
#4   4    Gus
#5   5    Gus
#6   3  Jesse
#7   4   Tuco
#8   5   Mike
#9   4   Mike
#10  5   Hank
#11  5   Saul
#12  5  Flynn

或者在基础R中更具可读性:

sel <- which(!is.na(mydf[-1]), arr.ind=TRUE)
data.frame(ID=mydf$ID[sel[,1]], V=mydf[-1][sel])

答案 3 :(得分:5)

使用tidyr

library("tidyr")

myvar <- as.data.frame(rbind(c("Walter","NA","NA","NA","NA"),
                             c("Walter","NA","NA","NA","NA"),
                             c("Walter","Jesse","NA","NA","NA"),
                             c("Gus","Tuco","Mike","NA","NA"), 
                             c("Gus","Mike","Hank","Saul","Flynn")))
ID <- as.factor(c(1:5))   

myvar <- data.frame(ID,myvar)

myvar %>% 
    gather(ID, Name, V1:V5 ) %>%
    select(ID, value) %>%
    filter(value != "NA")

如果您的NAs编码为NA而不是"NA",那么我们实际上可以使用na.rm = TRUE中的gather选项。 E.g:

myvar[myvar == "NA"] <- NA
myvar %>% 
    gather(ID, Name, V1:V5, na.rm = TRUE ) %>%
    select(ID, value)

给出

   ID  value
1   1 Walter
2   2 Walter
3   3 Walter
4   4    Gus
5   5    Gus
6   3  Jesse
7   4   Tuco
8   5   Mike
9   4   Mike
10  5   Hank
11  5   Saul
12  5  Flynn