はじめに
文字列処理・テキスト処理とは、プログラミングを行うなかで、文字列・テキストに対する色々な操作のことを指します。それら処理をうまく使いこなすことで、文字列を自由に処理できるようになります。文字列処理の活用事例は、キーワード抽出、テキスト分類、テキストマイニングの前処理など、多岐に渡ります。 今回の「Rでの文字列処理」シリーズで扱う、文字列処理のライブラリ・関数群やプログラムコードは、R環境上で無料で提供されている、オープン・ソフトウェアを用います。
この記事では、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