No.21832 【R】文字列マッチングの多重ループの高速化  【赤羽】 2015/10/31(Sat) 18:09

青木先生,
赤羽と申します,いつもご教示を頂戴し,誠にありがとうございます。
改めて御礼を申し上げます。

文字列マッチングの多重ループを回す処理を高速化するための,
apply関数の適用について,
ご教示をいただければ,大変に助かります。

どうぞ,よろしくお願いいたします。

------
添付の画像(単純な例示)を用いて,ご説明をいたします。

txは,テキスト(文字列)を格納するベクトルです。
txの長さを,ntxとします。

kwは,キーワード(文字列)を格納するベクトルです。
kwの長さを,nkwとします。

txの各要素(テキスト)に,kwの各要素が出現するかどうか(0/1の2値)を,
mxの行列で表します(ntx 行 * nkw 列)。

作成しましたRコードを,下記にお示しをしますが,
tx,kwが大規模であることから,性能向上のために,
多重ループを回す処理を高速化するための,apply関数の適用を試みていますが,
誠に恥ずかしいのですが,できないでおります。

ご教示をいただければ,大変に助かります。
どうぞ,よろしくお願いいたします。

ntx <- length(tx)
nkw <- length(kw)

mx <- matrix(0, ntx, nkw)

for(i in 1:ntx) {
v <- numeric(nkw)
for (j in 1:nkw) {
v[j] <-grepl(kw[j], tx[i])
}
mx[i,] <- v
}

mx


No.21833 Re: 【R】文字列マッチングの多重ループの高速化  【青木繁伸】 2015/10/31(Sat) 19:52

添付された図は,解像度が悪くて見えないし,見えてもそれを入力するのは面倒。以下のような簡単なテストデータを作った。
tx <- c("j matrix v", "v vmx nkw", "1 grepl grepl nkw j numeric", "ntx vmx j numeric v", 
"nkw for i", "0 j tx in", "mx length grepl tx nkw", "1 ntx j numeric nkw numeric matrix",
"numeric 0 length ntx nkw", "tx kw i 1 1")
kw <- c("for", "grepl", "in", "length", "matrix", "numeric")
ntx <- length(tx)
nkw <- length(kw)

mx <- matrix(0, ntx, nkw)

for(i in 1:ntx) {
v <- numeric(nkw)
for (j in 1:nkw) {
v[j] <-grepl(kw[j], tx[i])
}
mx[i,] <- v
}

mx

[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 0 0 0 1 0
[2,] 0 0 0 0 0 0
[3,] 0 1 0 0 0 1
[4,] 0 0 0 0 0 1
[5,] 1 0 0 0 0 0
[6,] 0 0 1 0 0 0
[7,] 0 1 0 1 0 0
[8,] 0 0 0 0 1 1
[9,] 0 0 0 1 0 1
[10,] 0 0 0 0 0 0
となる。
これと同じ解を for を使わないで求めるには,以下の一行
unname(sapply(kw, grepl, tx)+0)
ただし,速いかどうかは保証しない。

No.21834 【御礼】 Re: 【R】文字列マッチングの多重ループの高速化  【赤羽】 2015/11/01(Sun) 09:55

青木先生,
赤羽と申します,いつもご教示を頂戴し,誠にありがとうございます。
改めて御礼を申し上げます。

画像ファイルのサイズに収まる範囲内で,
必要な情報を提示しようと思いましたが,結果として見づらくなり,
先生には不愉快な思いをさせてしまい,大変に申し訳ございませんでした。

ご教示いただきましたコードは,にわかには理解できないため,
実行しながら内容をしっかりと理解いたします。

この度も助けていただき,誠にありがとうございました。

No.21835 Re: 【R】文字列マッチングの多重ループの高速化  【荒】 2015/11/01(Sun) 12:32

mx <- matrix(0, ntx, nkw)

for (i in 1:nkw) {
mx[,i] <- grepl(kw[i], tx)
}
mx

の方がループが1つなので理解しやすいと思います。
これをsapply化したものが青木先生の示された
unname(sapply(kw, grepl, tx)+0)
ですね。

No.21836 【御礼】 Re: 【R】文字列マッチングの多重ループの高速化  【赤羽】 2015/11/05(Thu) 21:54

荒 様;

赤羽と申します,
分かりやすい解説をしてくださり,誠にありがとうございます。
心から御礼を申し上げます。

青木先生の,研ぎ澄まされたコードを理解すべく勉強していましたが,
まったく理解できないでおりましたので,
荒様のお助けは大変に貴重です。

仕事が忙しくて,PCを開く時間的余裕がなく,
御礼が遅くなり,大変に失礼をいたしました。
ご容赦ください。

No.21837 Re: 【R】文字列マッチングの多重ループの高速化  【荒】 2015/11/06(Fri) 07:56

赤羽様

蛇足ですが,
青木先生の示された始めのコードの方が分りやすいです。
勝手に解説すると以下のようになります。

mx <- matrix(0, ntx, nkw) # 結果を入れる変数をあらかじめ用意(この方が早くなる)

for(i in 1:ntx) { # 各テキストごとに操作を行う
v <- numeric(nkw) # 各キーワードごとの結果を入れる一時的な変数を用意(ループの外に出した方がいいかも)
for (j in 1:nkw) {
v[j] <-grepl(kw[j], tx[i]) # 各テキストに対して各キーワードごとに正規検索を行い,結果を一時的な変数に入れる
}
mx[i,] <- v
}

試したところgreplはベクトル化された関数だったため,
grepl(kw[j], tx)で
各テキストに対する検索結果を一度に得ることができました。
そのため外側のループを省略することができ,
かつ
v <- numeric(nkw)
が不必要になりました。
その結果が

for (i in 1:nkw) {
mx[,i] <- grepl(kw[i], tx)
}

です。
御参考までに。

ちなみに私が始めに考えたコードは
sapply(1:nkw, function(i) grepl(kw[i], tx)) + 0
だったため,
青木先生の示された
unname(sapply(kw, grepl, tx)+0)
のコードに感動しました。

● 「統計学関連なんでもあり」の過去ログ--- 047 の目次へジャンプ
● 「統計学関連なんでもあり」の目次へジャンプ
● 直前のページへ戻る