在列中分隔分隔string并插入为新行

我有一个数据框如下:

+-----+-------+ | V1 | V2 | +-----+-------+ | 1 | a,b,c | | 2 | a,c | | 3 | b,d | | 4 | e,f | | . | . | +-----+-------+ 

每个字母都是用逗号分隔的字符。 我想在每个逗号分割V2,并插入拆分string作为新的行。 例如,期望的输出将是:

 +----+----+ | V1 | V2 | +----+----+ | 1 | a | | 1 | b | | 1 | c | | 2 | a | | 2 | c | | 3 | b | | 3 | d | | 4 | e | | 4 | f | +----+----+ 

我试图使用strsplit()先吐出V2,然后将列表投入数据框。 它没有工作。 任何帮助将不胜感激。

这是另一种做法..

 df <- read.table(textConnection("1|a,b,c\n2|a,c\n3|b,d\n4|e,f"), header = F, sep = "|", stringsAsFactors = F) df ## V1 V2 ## 1 1 a,b,c ## 2 2 a,c ## 3 3 b,d ## 4 4 e,f s <- strsplit(df$V2, split = ",") data.frame(V1 = rep(df$V1, sapply(s, length)), V2 = unlist(s)) ## V1 V2 ## 1 1 a ## 2 1 b ## 3 1 c ## 4 2 a ## 5 2 c ## 6 3 b ## 7 3 d ## 8 4 e ## 9 4 f 

截至2014年12月,这可以使用Hadley Wickham的tidyr软件包中最独特的function完成(参见发行说明http://blog.rstudio.org/2014/12/08/tidyr-0-2-0/

 > library(tidyr) > library(dplyr) > mydf V1 V2 2 1 a,b,c 3 2 a,c 4 3 b,d 5 4 e,f 6 . . > mydf %>% mutate(V2 = strsplit(as.character(V2), ",")) %>% unnest(V2) V1 V2 1 1 a 2 1 b 3 1 c 4 2 a 5 2 c 6 3 b 7 3 d 8 4 e 9 4 f 10 . . 

这是一个data.table解决scheme:

 d.df <- read.table(header=T, text="V1 | V2 1 | a,b,c 2 | a,c 3 | b,d 4 | e,f", stringsAsFactors=F, sep="|", strip.white = TRUE) require(data.table) d.dt <- data.table(d.df, key="V1") out <- d.dt[, list(V2 = unlist(strsplit(V2, ","))), by=V1] # V1 V2 # 1: 1 a # 2: 1 b # 3: 1 c # 4: 2 a # 5: 2 c # 6: 3 b # 7: 3 d # 8: 4 e # 9: 4 f > sapply(out$V2, nchar) # (or simply nchar(out$V2)) # abcacbdef # 1 1 1 1 1 1 1 1 1 

你可以从我的“splitstackshape”包中考虑cSplit direction = "long"

用法是:

 cSplit(mydf, "V2", ",", "long") ## V1 V2 ## 1: 1 a ## 2: 1 b ## 3: 1 c ## 4: 2 a ## 5: 2 c ## 6: 3 b ## 7: 3 d ## 8: 4 e ## 9: 4 f 

老答案….

这里是一个使用base R的方法。它假设我们从一个名为“mydf”的数据data.frame开始。 它使用read.csv在第二列中读取一个单独的data.frame ,我们将它与源数据中的第一列进行组合。 最后,你使用reshape将数据转换成一个长forms。

 temp <- data.frame(Ind = mydf$V1, read.csv(text = as.character(mydf$V2), header = FALSE)) temp1 <- reshape(temp, direction = "long", idvar = "Ind", timevar = "time", varying = 2:ncol(temp), sep = "") temp1[!temp1$V == "", c("Ind", "V")] # Ind V # 1.1 1 a # 2.1 2 a # 3.1 3 b # 4.1 4 e # 1.2 1 b # 2.2 2 c # 3.2 3 d # 4.2 4 f # 1.3 1 c 

另一个相当直接的select是:

 stack( setNames( sapply(strsplit(mydf$V2, ","), function(x) gsub("^\\s|\\s$", "", x)), mydf$V1)) values ind 1 a 1 2 b 1 3 c 1 4 a 2 5 c 2 6 b 3 7 d 3 8 e 4 9 f 4 

现在你可以使用tidyr 0.5.0的separate_rows来代替strsplit + unnest

例如:

 library(tidyr) (df <- read.table(textConnection("1|a,b,c\n2|a,c\n3|b,d\n4|e,f"), header = F, sep = "|", stringsAsFactors = F)) 
  V1 V2 1 1 a,b,c 2 2 a,c 3 3 b,d 4 4 e,f 
 separate_rows(df, V2) 

得到:

  V1 V2 1 1 a 2 1 b 3 1 c 4 2 a 5 2 c 6 3 b 7 3 d 8 4 e 9 4 f 

请参阅参考资料: https : //blog.rstudio.org/2016/06/13/tidyr-0-5-0/

另一个data.table解决scheme,它不依赖于原始数据中任何唯一字段的存在。

 DT = data.table(read.table(header=T, text="blah | splitme T | a,b,c T | a,c F | b,d F | e,f", stringsAsFactors=F, sep="|", strip.white = TRUE)) DT[,.( blah , splitme , splitted=unlist(strsplit(splitme, ",")) ),by=seq_len(nrow(DT))] 

重要的是by=seq_len(nrow(DT)) ,这是分裂发生的'假'uniqueID。 我倾向于用by=.I来代替,因为它应该被定义为相同的,但是.I似乎是一个改变它的值的神奇的东西,更好地坚持by=seq_len(nrow(DT))

输出中有三列。 我们简单地命名两个现有的列,然后将第三个计算为分割

 .( blah # first column of original , splitme # second column of original , splitted = unlist(strsplit(splitme, ",")) ) 
Interesting Posts