Разделите строки с разделителями в столбце и вставьте в качестве новых строк - программирование
Подтвердить что ты не робот

Разделите строки с разделителями в столбце и вставьте в качестве новых строк

У меня есть кадр данных:

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

Каждый из алфавитов является символом, разделенным запятой. Я хотел бы разделить V2 на каждую запятую и вставить разделенные строки в виде новых строк. Например, желаемый результат будет:

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

Я пытаюсь использовать strsplit(), чтобы сначала наплевать V2, а затем перечислить список в фрейм данных. Это не сработало. Любая помощь будет оценена.

4b9b3361

Ответ 1

Вот еще один способ сделать это.

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

Ответ 2

По состоянию на декабрь 2014 это можно сделать, используя функцию unsest из пакета Hadley Wickham tidyr (см. примечания к выпуску 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  .  .

Ответ 3

Здесь a data.table решение:

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))
# a b c a c b d e f 
# 1 1 1 1 1 1 1 1 1 

Ответ 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/

Ответ 5

Вы можете рассмотреть cSplit с помощью direction = "long" из моего пакета splitstackshape.

Использование:

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

Старый ответ....

Вот один подход с использованием базы R. Предполагается, что мы начинаем с data.frame с именем "mydf". Он использует read.csv для чтения во втором столбце как отдельный data.frame, который мы объединяем с первым столбцом из ваших исходных данных. Наконец, вы используете reshape для преобразования данных в длинную форму.

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

Еще одна довольно прямая альтернатива:

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

Ответ 6

Другое решение data.table, которое не полагается на существование каких-либо уникальных полей в исходных данных.

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)), это "поддельный" уникальный идентификатор, на котором происходит расщепление. Заманчиво использовать by=.I вместо этого, так как его нужно определить одинаково, но .I кажется волшебной вещью, которая меняет ее значение, лучше придерживаться by=seq_len(nrow(DT))

На выходе есть три столбца. Мы просто называем два существующих столбца, а затем вычисляем третий как разделенный

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