Rubyで自然言語処理を行う際、テキストデータの取り扱いでよくつかうものをまとめました。今後も追加していきます。Ruby 2.6基準でまとめています。
文字列に対する操作
文字列中の特定文字にアクセスしたい
文字列中の特定文字にアクセスしたい場合は位置を指定してやればよい。
"hoge"[0] => "h"
少々冗長ではあるが、chars を使って配列化したほうがお行儀は良い。
"hoge".chars[0] => "h"
配列にしておくと、例えば複数文字に対して同時にアクセスしたい場合に values_at を組み合わせて使うことで配列で返すことができる。
"hoge".chars.values_at(0, 2) => ["h", "g"]
配列中の文字列を一括で文字の配列にしたい
map でスッキリかける。ブロックの部分は Symbol#to_proc を使えばさらに短縮できる。
["hoge", "moge"].map(&:chars) => [["h", "o", "g", "e"], ["m", "o", "g", "e"]]
簡易的に英文の分かち書きをする
split の区切り文字をいい感じに指定する。例えば、アルファベット以外を区切り文字にしたい場合は \W が [^a-zA-Z0-9_] を指しているので便利。
"Hoge, moge. mogera.".split(/\W+/) => ["Hoge", "moge", "mogera"]
ただし、英文中には、"moge-ra" のようなハイフン区切りの表現も出現する場合があるので、ハイフンもまとめて抽出したい場合は区切り文字を限定してやる必要がある。
"Hoge, moge. moge-ra.".split(/ ,./) => ["Hoge", "moge", "moge-ra"]
日本語の文章から文を抽出する
split の区切り文字に句点 "。" を指定する。
"Rubyを使って自然言語処理をしましょう。結構つらいですけど。".split(/。/) => ["Rubyを使って自然言語処理をしましょう", "結構つらいですけど"]
N-gramをつくる
each_cons はブロックなしでを使うと、要素を重複ありで n 要素ずつに区切り繰り返す Enumerator を返してくれる。これをArrayに直してやるとそれっぽいものができる。以下は文字bi-gramの例。
"hoge".chars.each_cons(2).to_a => [["h", "o"], ["o", "g"], ["g", "e"]]
もちろん、対象の配列が単語区切りのものであれば、単語bi-gramを表現することもできる。
"hoge moge. mogera".split(/\W+/).each_cons(2).to_a => [["hoge", "moge"], ["moge", "mogera"]]
結果を2次元配列で持たせたくない場合は join してあげればよい。
"hoge".chars.each_cons(2).map(&:join) => ["ho", "og", "ge"]
文字⇔文字コード間の変換を行う
文字に対して ord を使えば、文字コードを取得できる。
'a'.ord => 97
文字コードに対して chr を使えば、文字を取得できる。
97.chr => "a"
文字列中の文字をシャッフルする
chars で文字の配列に戻してから shuffle でシャッフルして、join でつなぎなおす。
"hogehogemogemoge".chars.shuffle.join => "hmggegoeeemooogh"
単純な文字列置換
短い文に対して正規表現を使わなくてもいい場合は tr が楽。
"hogehoge".tr("o", " ") => "h geh ge"
正規表現を使った文字列置換
正規表現を使う必要がある複雑な文字列置換の場合は gsub を使う。文中でマッチしたすべての文字列が置換される。
"hogehoge".gsub(/o\w/, " ") => "h eh e"
最初のマッチだけ文字列置換を行いたい場合は sub を使う。
"hogehoge".sub(/o\w/, " ") => "h ehoge"
ファイル操作
相対パスをソースファイルの位置基準で絶対パスに変換する
File.expand_path でパスを絶対パスに変換できる。__dir__ は、現在のソースファイルのあるディレクトリ名を絶対パスで返してくれるので、表題の通り変換できる。
File.expand_path('../data/data.txt', __dir__) => "/usr/app/data/data.txt"
テキストファイルを行単位で配列で返す
テキストファイルを読み込んで改行位置で分割し配列で返すには Fille.readlines を使うと便利。
File.readlines(file_path, chomp: true) => ["hoge\n", "moge\n", "fuga"]
文末の改行コードを除去したい場合は、chomp: true をつけてやると除去もしてくれる。
File.readlines(file_path, chomp: true) => ["hoge", "moge", "fuga"]
テキストファイルの行数を数える
Fille.readlines でファイルを読み込んで配列にした後、配列のサイズを返してやる。
File.readlines(file_path).size => 30
CSVファイルを読み込んで配列に変換する
CSVファイルを読み込んで、カンマ "," で区切った配列に変換する場合は CSV.read を使うと変換できる。
require "csv" CSV.read(input_file_path) => [["hoge", "hogehoge", "1", "2019-12-01"], ["moge", "mogemoge", "2", "2019-12-02"]]
TSVファイルを読み込んで配列に変換する
CSVファイルと同様に CSV.read で変換できる。引数に col_sep: "\t" を追加する。
require "csv" CSV.read(input_file_path, col_sep: "\t") => [["hoge", "hogehoge", "1", "2019-12-01"], ["moge", "mogemoge", "2", "2019-12-02"]]