次のような変数のベクトルがあるとしましょう。
>variable
[1] "A1" "A1" "A1" "A1" "A2" "A2" "A2" "A2" "B1" "B1" "B1" "B1"
これを次のようなデータフレームに変換したいと思います。
treatment time
1 A 1
2 A 1
3 A 1
4 A 1
5 A 2
6 A 2
7 A 2
8 A 2
9 B 1
10 B 1
11 B 1
12 B 1
そのために、reshape2のcolsplit関数を使用しました。文字列を分割するにはパターンが必要ですが、スペースなしで2つの文字を分割する明確なパターンがないことにすぐに気付きます。 「」を試してみたところ、次の結果が得られました。
> colsplit(trialm$variable,"",names=c("treatment","time"))
treatment time
1 NA A1
2 NA A1
3 NA A1
4 NA A1
5 NA A2
6 NA A2
7 NA A2
8 NA A2
9 NA B1
10 NA B1
11 NA B1
12 NA B1
また、後読みまたは先読みの正規表現を試しました。
>colsplit(trialm$variable,"(?<=\\w)",names=c("treatment","time"))
Error in gregexpr("(?<=\\w)", c("A1", "A1", "A1", "A1", "A2", "A2", "A2", :
invalid regular expression '(?<=\w)', reason 'Invalid regexp'
しかし、それは私に上記のエラーを与えました。どうすればこの問題を解決できますか?
substr
はそれを行う別の方法です。
> variable <- c(rep("A1", 4), rep("A2", 4), rep("B1", 4))
> data.frame(treatment=substr(variable, 1,1), time=as.numeric(substr(variable,2,2)))
treatmen time
1 A 1
2 A 1
3 A 1
4 A 1
5 A 2
6 A 2
7 A 2
8 A 2
9 B 1
10 B 1
11 B 1
12 B 1
どこかで、「stringr」パッケージ(「reshape2」でインポートされ、colsplit
で行われる分割を担当)は、その機能のいくつかに「stringi」を使用し始めました。そのため、一部の動作が変更されたようです。
現在の「reshape2」(および現在の「stringr」パッケージ)を使用すると、colsplit
はコードで期待したとおりに機能します。
packageVersion("reshape2")
## [1] ‘1.4.3’
packageVersion("stringr")
## [1] ‘1.2.0’
colsplit(variable, "", names = c("treatment", "time"))
## treatment time
## 1 A 1
## 2 A 1
## 3 A 1
## 4 A 1
## 5 A 2
## 6 A 2
## 7 A 2
## 8 A 2
## 9 B 1
## 10 B 1
## 11 B 1
## 12 B 1
「変数」でパターンを検出できても、使用できるクリーンな分割文字がない場合は、1つ追加してください:)
library(reshape2)
variable <- c("A1", "A1", "A1", "A1", "A2", "A2",
"A2", "A2", "B1", "B1", "B1", "B1")
## Here, we add a "." between upper case letters and numbers
colsplit(gsub("([A-Z])([0-9])", "\\1\\.\\2", variable),
"\\.", c("Treatment", "Time"))
# Treatment Time
# 1 A 1
# 2 A 1
# 3 A 1
# 4 A 1
# 5 A 2
# ::::: snip :::: #
# 11 B 1
# 12 B 1
私の「splitstackshape」パッケージには、これに使用できるNoSep
と呼ばれる単一目的のエクスポートされていないヘルパー関数があります。
splitstackshape:::NoSep(variable)
## .var .time_1
## 1 A 1
## 2 A 1
## 3 A 1
## 4 A 1
## 5 A 2
## ::: snip :::: #
## 11 B 1
## 12 B 1
「tidyverse」(具体的には「tidyr」パッケージ)には、値を異なる列に分割するための便利な関数がいくつかあります:separate
とextract
。 separate
has すでにjazzuroによって示されています ですが、解決策はこの特定の問題に非常に固有です。また、通常、区切り文字を使用するとうまく機能します。 extract
は、キャプチャするグループで正規表現を指定することを想定しています。
library(tidyverse)
data.frame(variable) %>%
extract(variable, into = c("Treatment", "Time"), regex = "([A-Z]+)([0-9]+)")
# Treatment Time
# 1 A 1
# 2 A 1
# 3 A 1
# 4 A 1
# 5 A 2
# ::::: snip :::: #
# 11 B 1
# 12 B 1
ベクトルvariable
を使用してデータフレームを作成する場合、tidyr
パッケージのseparate()
を使用できます。
mydf <- data.frame(variable = c(rep("A1", 4), rep("A2", 4), rep("B1", 4)),
stringsAsFactors = FALSE)
separate(mydf, variable, c("treatement", "time"), sep = 1)
# treatement time
#1 A 1
#2 A 1
#3 A 1
#4 A 1
#5 A 2
#6 A 2
#7 A 2
#8 A 2
#9 B 1
#10 B 1
#11 B 1
#12 B 1
substr
を使用して分割できます。
例えば.
df <- data.frame(treatment = substr(variable, start = 1, stop = 1),
time = substr(variable, start = 2, stop = 2) )
新しい関数tstrsplit()
が_data.table v1.9.5
_に導入されました。 t
はtransposeの略です。これは、文字ベクトルをstrsplit()
で分割してから、転置それを分割した結果です。
_# dummy data
library(data.table)
dt <- data.table(var = c(rep("A1", 4), rep("A2", 4), rep("B1", 4)))
_
tstrsplit()
の使用:
_dt[, tstrsplit(var, "")]
V1 V2
1: A 1
2: A 1
3: A 1
4: A 1
5: A 2
6: A 2
7: A 2
8: A 2
9: B 1
10: B 1
11: B 1
12: B 1
_
はい、それはとても簡単です。 :-)
正規表現を使用した別のソリューション
require(stringr)
variable <- c(paste0("A", c(rep(1, 4), rep(2, 3))),
paste0("B", rep(1, 4))
)
data.frame(
treatment = str_extract(variable, "[[:alpha:]]"),
time = as.numeric(str_extract(variable, "[[:digit:]]"))
)
## treatment time
## 1 A 1
## 2 A 1
## 3 A 1
## 4 A 1
## 5 A 2
## 6 A 2
## 7 A 2
## 8 B 1
## 9 B 1
## 10 B 1
## 11 B 1
Substring()を使用してベクトルを作成し、data.frame関数を使用してそれらを結合できます。
yyy<-c("A1", "A1", "A1", "A1", "A2", "A2", "A2", "A2", "B1", "B1", "B1", "B1")
treatment<-substring(yyy, 1,1)
time<-as.numeric(substring(yyy,2,2))
data.frame(treatment,time)
strsplit
を使用できます
df <- t(data.frame(strsplit(variable, "")))
rownames(df) <- NULL
colnames(df) <- c("treatment" , "time" )
df
treatment time
[1,] "A" "1"
[2,] "A" "1"
[3,] "A" "1"
[4,] "A" "1"
[5,] "A" "2"
[6,] "A" "2"
[7,] "A" "2"
[8,] "A" "2"
[9,] "B" "1"
[10,] "B" "1"
[11,] "B" "1"
[12,] "B" "1"
t
を使用する代わりに、rbind
を使用してから、次のようにdata.frame
に強制変換できます。
setNames(as.data.frame(do.call(rbind, strsplit(variable, ""))),
c("Treatment", "Time"))
# Treatment Time
# 1 A 1
# 2 A 1
# 3 A 1
# 4 A 1
# 5 A 2
# 6 A 2
# 7 A 2
# 8 B 1
# 9 B 1
# 10 B 1
# 11 B 1
@Justinのコメントに基づいて、私はこれを提案します(v <- c("A1", "B2")
を使用):
> t(sapply(strsplit(v, ''), '[', c(1, 2)))
[,1] [,2]
[1,] "A" "1"
[2,] "B" "2"
`'['の後のベクトルは、分割ベクトルからアイテムを選択します。だから私は一度だけ分割し、両方のアイテムを保持しました。すべてのアイテムを保持したい場合は、これはさらに簡単かもしれません。
t(sapply(strsplit(v, ''), identity))