web-dev-qa-db-ja.com

データフレームで文字を2つの変数に分割します

次のような変数のベクトルがあるとしましょう。

>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'

しかし、それは私に上記のエラーを与えました。どうすればこの問題を解決できますか?

11
Alby

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
7
Jilber Urbina

更新:2017年12月24日

どこかで、「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

元の回答:2013年4月24日

「変数」でパターンを検出できても、使用できるクリーンな分割文字がない場合は、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

追加オプション:2017年12月23日

私の「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」パッケージ)には、値を異なる列に分割するための便利な関数がいくつかあります:separateextractseparate 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
10

ベクトル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
6
jazzurro

substrを使用して分割できます。

例えば.

df <- data.frame(treatment =   substr(variable, start = 1, stop = 1),
                 time =        substr(variable, start = 2, stop = 2) )
5
user1317221_G

新しい関数tstrsplit()が_data.table v1.9.5_に導入されました。 ttransposeの略です。これは、文字ベクトルを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
_

はい、それはとても簡単です。 :-)

4
Rich Scriven

正規表現を使用した別のソリューション

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
4
dickoa

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)
3
Arhopala

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
2
Simon O'Hanlon

@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))
1
U. Windl