How to strsplit data frame column and replicate rows accordingly? [duplicate]

老子叫甜甜 提交于 2020-01-03 10:19:08

问题


I have a data frame like this:

> df <- data.frame(Column1=c("id1", "id2", "id3"), Column2=c("text1,text2,text3", "text4", "text5,text6"), Column3=c("text7", "text8,text9,text10,text11", "text12,text13"))

> df
  Column1           Column2                   Column3
1     id1 text1,text2,text3                     text7
2     id2             text4 text8,text9,text10,text11
3     id3       text5,text6             text12,text13

How do I transform it in this format?

  Column1 variable                     value
1     id1  Column2                     text1
2     id1  Column2                     text2
3     id1  Column2                     text3
4     id2  Column2                     text4
5     id3  Column2                     text5
6     id3  Column2                     text6
7     id1  Column3                     text7
8     id2  Column3                     text8
9     id2  Column3                     text9
10    id2  Column3                    text10
11    id2  Column3                    text11
12    id3  Column3                    text12
13    id3  Column3                    text13

I guess the first step is to melt() the data frame (btw, should I worry about that warning?):

> library(reshape2)    
> mdf <- melt(df, id.vars="Column1", measure.vars=c("Column2", "Column3"))
> mdf
  Column1 variable                     value
1     id1  Column2         text1,text2,text3
2     id2  Column2                     text4
3     id3  Column2               text5,text6
4     id1  Column3                     text7
5     id2  Column3 text8,text9,text10,text11
6     id3  Column3             text12,text13
Warning message:
attributes are not identical across measure variables; they will be dropped

Then I would basically need to ``strsplit()` the 'value' column and replicate the rows accordingly, but I can't think of a way to do it.

> strsplit(mdf$value, ",")
[[1]]
[1] "text1" "text2" "text3"

[[2]]
[1] "text4"

[[3]]
[1] "text5" "text6"

[[4]]
[1] "text7"

[[5]]
[1] "text8"  "text9"  "text10" "text11"

[[6]]
[1] "text12" "text13"

Any help is appreciated! Thanks.


回答1:


You could try:

 library(reshape2)

cSplit from https://gist.github.com/mrdwab/11380733

 cSplit(melt(df, id.vars="Column1"), "value", ",", "long")
 #      Column1 variable  value
 # 1:     id1  Column2  text1
 # 2:     id1  Column2  text2
 # 3:     id1  Column2  text3
 # 4:     id2  Column2  text4
 # 5:     id3  Column2  text5
 # 6:     id3  Column2  text6
 # 7:     id1  Column3  text7
 # 8:     id2  Column3  text8
 # 9:     id2  Column3  text9
 #10:     id2  Column3 text10
 #11:     id2  Column3 text11
 #12:     id3  Column3 text12
 #13:     id3  Column3 text13

Alternatively, if one wants to stick to functions available in CRAN packages:

library(reshape2)
library(splitstackshape)
library(dplyr)
select(na.omit(concat.split.multiple(melt(df, id.vars="Column1"), split.col="value", sep=",", direction="long")), -time)



回答2:


A data.table solution:

library(data.table)
mdt <- melt(setDT(df), id.vars="Column1")[,strsplit(as.character(value),",",fixed=TRUE),
                                          by=list(Column1,variable)]

the result:

> mdt
    Column1 variable     V1
 1:     id1  Column2  text1
 2:     id1  Column2  text2
 3:     id1  Column2  text3
....

You can also use the tstrsplit function from the latest version of data.table (v1.9.5+) which keeps the name for the value column instead of renaming it to V1:

mdt <- melt(setDT(df), id.vars="Column1")[,lapply(.SD, function(x) tstrsplit(x, ",", fixed=TRUE)),
                                          by=list(Column1,variable)]

the result:

> mdt
    Column1 variable  value
 1:     id1  Column2  text1
 2:     id1  Column2  text2
 3:     id1  Column2  text3
....

An alternative solution with dplyr & tidyr:

library(dplyr)
library(tidyr)
mdf <- df %>% gather(variable, value, -Column1) %>% 
  transform(value = strsplit(as.character(value),",")) %>%
  unnest(value)

the result:

> mdf
   Column1 variable  value
1      id1  Column2  text1
2      id1  Column2  text2
3      id1  Column2  text3
....

With the latest version of tidyr, you can also use the separate_rows-function:

mdf <- df %>% 
  gather(variable, value, -Column1) %>% 
  separate_rows(value)



回答3:


You got this far:

mdf <- melt(df, id.vars="Column1", measure.vars=c("Column2", "Column3"))
values <- strsplit(mdf$value, ",")

Now all you need to do is to create an index of which rows of mdf to use:

n <- vapply(values, length, integer(1))
index <- rep.int(seq_along(n), n)

and then combine that with values:

cbind(mdf[index,], unlist(values, use.names = FALSE))



回答4:


About the Warning: it appears because you are using factor variables for the melting.

In your example you can avoid the warning adding stringAsFactors=FALSE at the end of the df declaration:

df <- data.frame(Column1=c("id1", "id2", "id3"), Column2=c("text1,text2,text3", "text4", "text5,text6"), Column3=c("text7", "text8,text9,text10,text11", "text12,text13"), stringsAsFactors=FALSE)


来源:https://stackoverflow.com/questions/24595421/how-to-strsplit-data-frame-column-and-replicate-rows-accordingly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!