京橋のバイオインフォマティシャンの日常

まずは、データ分析、コマンドラインのメモとして

【Rでの文字列処理シリーズ(その2)】文字列ベクトルの連結とカウント

Rでの文字列ベクトルの連結とカウントについて、いろいろと試してまとめてみた。

主に、baseやstringrとかのパッケージ内の関数群を扱う。

文字列の連結・結合は普段もよく使うので簡単と思ってたけど、いろいろと試してみると奥が深いかも。

下準備について

########################
#シリーズ共通
########################
#必要なパッケージの読み込み
require(readr)
require(stringr)
require(stringdist)

#テストファイルのダウンロード
utils::download.file(url="https://raw.githubusercontent.com/kumeS/Blog/master/TXT_proc/test.txt",
                     destfile="test.txt")

【1】文字列ベクトルの連結

base::paste0 ・ stringr::str_c

base::paste0、stringr::str_c についての実行例を示す。

paste0関数は、paste関数の引数 sep = ""が標準出力の関数である。

#入力ベクトル
abc <- c("A", "B", "C", "D", "E")

# 使用する引数
# sep: 入力ベクトル間に挿入する文字列
# collapse: 入力ベクトルを1つの文字列に連結するために使用される文字列

#base::paste0での実行例
#paste0での標準出力
base::paste0(abc)
#[1] "A" "B" "C" "D" "E"

#ベクトルの各要素の後ろに「,」を付与する
base::paste0(abc, sep=",")
#[1] "A," "B," "C," "D," "E,"

#ただ、base::pasteでは同じ出力とはならない
base::paste(abc, sep=",")
#[1] "A" "B" "C" "D" "E"  => この場合、処理効果なし

#文字列ベクトルを1つの文字列として連結する
base::paste0(abc, collapse="")
#[1] "ABCDE"

#ベクトルの各要素の間に「,」を付与して、文字列ベクトルを1つの文字列として連結する
base::paste0(abc, collapse=",")
#[1] "A,B,C,D,E"

次に、ベクトルではなく、文字列を並べたときの出力結果を見ていく。

#"A", "B", "C", "D", "E"と、文字列として並べたときのデフォルト出力
base::paste0("A", "B", "C", "D", "E")
#[1] "ABCDE"

#sep=","を設定すると、最後にコンマが付く
base::paste0("A", "B", "C", "D", "E", sep=",")
#[1] "ABCDE,"

#ただ、base::pasteでは同じ出力とはならず、間にコンマが入る
base::paste("A", "B", "C", "D", "E", sep=",")
#[1] "A,B,C,D,E"

#collapse=","を設定すると
base::paste0("A", "B", "C", "D", "E", collapse=",")
#[1] "ABCDE"  => この場合、処理効果なし

stringr::str_c

続いて、stringr::str_c関数での実行例を見ていく。

#デフォルト出力
stringr::str_c(abc)
#[1] "A" "B" "C" "D" "E"

#sep=","の設定にすると
stringr::str_c(abc, sep=",")
#[1] "A" "B" "C" "D" "E"  => この場合、処理効果なし

#collapse=","の設定にすると、間にコンマが入る
stringr::str_c(abc, collapse=",")
#[1] "A,B,C,D,E"

#ベクトルではなく、文字列を並べたときの出力
stringr::str_c("A", "B", "C", "D", "E")
#[1] "ABCDE"

#sep=","の設定にすると、間にコンマが入る
stringr::str_c("A", "B", "C", "D", "E", sep=",")
#[1] "A,B,C,D,E"

#collapse=","の設定にすると、
stringr::str_c("A", "B", "C", "D", "E", collapse=",")
#[1] "ABCDE"  => この場合、処理効果なし

関数によって、sep、collapseの引数としての影響が若干違ってくるみたい。

【2】文字列長のカウント

文字列長をカウントする関数として、 base::nchar関数、stringr::str_length関数、stringr::str_count関数を取り上げる。

base::nchar

#文字列長のカウント: ベクトルでの実行
#入力ベクトル
abc <- c("A", "B", "C", "D", "E")

#文字列長のカウント: 文字列での実行
base::nchar(abc)
#[1] 1 1 1 1 1

#文字列長のカウント: データフレームでの実行
#入力データフレーム
c <- data.frame(readr::read_tsv(file="./test.txt", col_names=F))
c
#           X1
#1 abc ABC abc
#2 ABC abc ABC
#3 def DEF def
#4 DEF def DEF
#5 abc.ABC.abc
#6 ABC.abc.ABC

#データフレームに含まれる全文字数のカウント
base::nchar(c)
#X1 
#91

#要素ごとでの文字数のカウント
base::nchar(c$X1)
#[1] 11 11 11 11 11 11

少し横道にそれるが、apply関数とbase::nchar関数とを組み合わせる場合もやってみる。

#apply関数を組み合わせた文字数のカウント
#MARGIN = 1 (rows)でapply実行する
apply(c, MARGIN=1, base::nchar)
#[1] 11 11 11 11 11 11

#MARGIN = 2 (columns)でapply実行する
apply(c, MARGIN=2, base::nchar)
#     X1
#[1,] 11
#[2,] 11
#[3,] 11
#[4,] 11
#[5,] 11
#[6,] 11

MARGIN=1の場合に、横に出力されて、 MARGIN=2の場合に、縦に出力されるのがやや違和感あるけど。。

次に、データフレームを分割して、3x6のデータフレームで、文字数のカウントをやってみる。

行列で入力するか、データフレームで入力するかで、どうも出力結果が変わるみたい。

#分割した行列での実行
c2 <- stringr::str_split_fixed(c$X1, pattern=c(" ", " ", " ", " ", "[.]", "[.]"), n=3)
c2
#     [,1]  [,2]  [,3] 
#[1,] "abc" "ABC" "abc"
#[2,] "ABC" "abc" "ABC"
#[3,] "def" "DEF" "def"
#[4,] "DEF" "def" "DEF"
#[5,] "abc" "ABC" "abc"
#[6,] "ABC" "abc" "ABC"

#要素ごとの文字列長のカウント
base::nchar(c2)
#     [,1] [,2] [,3]
#[1,]    3    3    3
#[2,]    3    3    3
#[3,]    3    3    3
#[4,]    3    3    3
#[5,]    3    3    3
#[6,]    3    3    3
#セルごとでカウントされる

#分割したデータフレームでの実行
c3 <- data.frame(stringr::str_split_fixed(c$X1, pattern=c(" ", " ", " ", " ", "[.]", "[.]"), n=3))
c3
#   X1  X2  X3
#1 abc ABC abc
#2 ABC abc ABC
#3 def DEF def
#4 DEF def DEF
#5 abc ABC abc
#6 ABC abc ABC

base::nchar(c3)
#X1 X2 X3 
#43 43 43 
#列ごとでカウントされる。

stringr::str_length ・ stringr::str_count

次に、stringr::str_length関数やstringr::str_count関数でカウントしてみた。どちらの関数も、行列を入力としたところ、ベクトルで出力された。

#stringr::str_lengthでのカウント実行: 文字列の長さをベクトルで出力
stringr::str_length(c2)
#[1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3

#文字列マッチでのカウント: 大文字あるいは小文字のアルファベット数でカウント
stringr::str_count(c2, pattern = "[a-z]|[A-Z]")
#[1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3

補足情報

formatC関数を使って、出力文字列の桁数を揃える

d <- 1:10
d
#[1]  1  2  3  4  5  6  7  8  9 10

#「0」を加えて、桁数3桁で揃える。
formatC(d, width = 3, flag = "0")
#[1] "001" "002" "003" "004" "005" "006" "007"
#[8] "008" "009" "010"

連番数値を作成する

d1 <- seq_len(10)
d1
#[1]  1  2  3  4  5  6  7  8  9 10

大文字 <=> 小文字の変換

小文字 => 大文字への変換では、toupper関数、str_to_upper関数(ベクトル化される)を使用する。また、大文字 => 小文字への変換では、tolower関数、str_to_lower関数(ベクトル化される)を使用する。

#大文字・小文字が混在する行列を使用する
c2
#     [,1]  [,2]  [,3] 
#[1,] "abc" "ABC" "abc"
#[2,] "ABC" "abc" "ABC"
#[3,] "def" "DEF" "def"
#[4,] "DEF" "def" "DEF"
#[5,] "abc" "ABC" "abc"
#[6,] "ABC" "abc" "ABC"

#大文字への変換
toupper(c2)
#     [,1]  [,2]  [,3] 
#[1,] "ABC" "ABC" "ABC"
#[2,] "ABC" "ABC" "ABC"
#[3,] "DEF" "DEF" "DEF"
#[4,] "DEF" "DEF" "DEF"
#[5,] "ABC" "ABC" "ABC"
#[6,] "ABC" "ABC" "ABC"

#小文字への変換
tolower(c2)
#     [,1]  [,2]  [,3] 
#[1,] "abc" "abc" "abc"
#[2,] "abc" "abc" "abc"
#[3,] "def" "def" "def"
#[4,] "def" "def" "def"
#[5,] "abc" "abc" "abc"
#[6,] "abc" "abc" "abc"

#大文字ベクトルへの変換
stringr::str_to_upper(c2)
# [1] "ABC" "ABC" "DEF" "DEF" "ABC" "ABC" "ABC"
# [8] "ABC" "DEF" "DEF" "ABC" "ABC" "ABC" "ABC"
#[15] "DEF" "DEF" "ABC" "ABC"

#小文字ベクトルへの変換
stringr::str_to_lower(c2)
# [1] "abc" "abc" "def" "def" "abc" "abc" "abc"
# [8] "abc" "def" "def" "abc" "abc" "abc" "abc"
#[15] "def" "def" "abc" "abc"

参考資料

https://cran.r-project.org/web/packages/readr/readr.pdf

https://cran.r-project.org/web/packages/stringr/stringr.pdf

cran.r-project.org

github.com