次のようなデータフレームがあります。
_+-----+-------+
| 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を吐き出し、リストをデータフレームにキャストしようとしています。うまくいきませんでした。任意の助けをいただければ幸いです。
ここに別の方法があります。
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パッケージのunnest関数を使用して実行できます(リリースノートを参照 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 . .
更新2017:以下の@Tifで説明されているseparate_rows
関数に注意してください。
これは非常に優れており、1つのステートメントで複数の列を「ネスト解除」できます。
> head(mydf)
geneid chrom start end strand length gene_count
ENSG00000223972.5 chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1 11869;12010;12179;12613;12613;12975;13221;13221;13453 12227;12057;12227;12721;12697;13052;13374;14409;13670 +;+;+;+;+;+;+;+;+ 1735 11
ENSG00000227232.5 chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1;chr1 14404;15005;15796;16607;16858;17233;17606;17915;18268;24738;29534 14501;15038;15947;16765;17055;17368;17742;18061;18366;24891;29570 -;-;-;-;-;-;-;-;-;-;- 1351 380
ENSG00000278267.1 chr1 17369 17436 - 68 14
ENSG00000243485.4 chr1;chr1;chr1;chr1;chr1 29554;30267;30564;30976;30976 30039;30667;30667;31097;31109 +;+;+;+;+ 1021 22
ENSG00000237613.2 chr1;chr1;chr1 34554;35277;35721 35174;35481;36081 -;-;- 1187 24
ENSG00000268020.3 chr1 52473 53312 + 840 14
> mydf %>% separate_rows(strand, chrom, gene_start, gene_end)
geneid length gene_count strand chrom start end
ENSG00000223972.5 1735 11 + chr1 11869 12227
ENSG00000223972.5 1735 11 + chr1 12010 12057
ENSG00000223972.5 1735 11 + chr1 12179 12227
ENSG00000223972.5 1735 11 + chr1 12613 12721
ENSG00000223972.5 1735 11 + chr1 12613 12697
ENSG00000223972.5 1735 11 + chr1 12975 13052
ENSG00000223972.5 1735 11 + chr1 13221 13374
ENSG00000223972.5 1735 11 + chr1 13221 14409
ENSG00000223972.5 1735 11 + chr1 13453 13670
ENSG00000227232.5 1351 380 - chr1 14404 14501
ENSG00000227232.5 1351 380 - chr1 15005 15038
ENSG00000227232.5 1351 380 - chr1 15796 15947
ENSG00000227232.5 1351 380 - chr1 16607 16765
ENSG00000227232.5 1351 380 - chr1 16858 17055
ENSG00000227232.5 1351 380 - chr1 17233 17368
ENSG00000227232.5 1351 380 - chr1 17606 17742
ENSG00000227232.5 1351 380 - chr1 17915 18061
ENSG00000227232.5 1351 380 - chr1 18268 18366
ENSG00000227232.5 1351 380 - chr1 24738 24891
ENSG00000227232.5 1351 380 - chr1 29534 29570
ENSG00000278267.1 68 5 - chr1 17369 17436
ENSG00000243485.4 1021 8 + chr1 29554 30039
ENSG00000243485.4 1021 8 + chr1 30267 30667
ENSG00000243485.4 1021 8 + chr1 30564 30667
ENSG00000243485.4 1021 8 + chr1 30976 31097
ENSG00000243485.4 1021 8 + chr1 30976 31109
ENSG00000237613.2 1187 24 - chr1 34554 35174
ENSG00000237613.2 1187 24 - chr1 35277 35481
ENSG00000237613.2 1187 24 - chr1 35721 36081
ENSG00000268020.3 840 0 + chr1 52473 53312
これで、strsplit
+ unnest
の代わりにtidyr 0.5.0のseparate_rows
を使用できます。
例えば:
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
解決:
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
「splitstackshape」パッケージのdirection = "long"
でcSplit
を検討できます。
使用法は次のとおりです。
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を使用する1つのアプローチを次に示します。「mydf」という名前のdata.frame
で始まることを前提としています。 read.csv
を使用して、2番目の列を個別の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
別の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))
です。これは、分割が行われる「偽の」一意のIDです。同じように定義する必要があるため、代わりにby=.I
を使用するのは魅力的ですが、.I
はその値を変更する魔法のようで、by=seq_len(nrow(DT))
に固執する方がよい
出力には3つの列があります。 2つの既存の列に名前を付けてから、3番目の列を分割として計算します
.( blah # first column of original
, splitme # second column of original
, splitted = unlist(strsplit(splitme, ","))
)