機械翻訳用のデータは言語毎にファイルは別になっていて、文同士の対応は行番号が同じことによって保たれている
例えばこんな感じ
# ja.txt こんにちは 私はテニスが好きです 私はペンを持っています
# en.txt hello I like tennis I have a pen
これをtoken化してモデルへの入力として使うのだが、あまりにもtoken数の多い文があるとメモリに乗り切らなくなったり処理の効率が落ちたりする。
それを避けるために一定数以上のtokenを持つ行はそれぞれのファイルから削除したい。
token化した後のデータは各言語とも以下のような数字がスペース区切りで書いてあるものとすると
1 723 84 935 3385 4 172 7435 6 213 183 575 155 26 9 54 2025 4 199 279 2404 6 5 2 1 1415 333 375 27 239 26 7572 4 27 1745 67 77 13 7 1891 2024 6 8 183 517 2258 46 26 10 4148 10 7 203 8 12 366 211 5 2 1 120 9 116 665 21 98 64 1435 21 26 72 1890 183 517 10 52 605 10 943 166 2025 5 2 ...
以下のような処理で一定数以下のtokenを持つ文のみを残したファイルを作成できる
max_words=50 token_file1=... token_file2=... # 2つのファイルからmax_words以上を持つ行を消すためのsedコマンドを生成 cat $token_file1 | awk -v mw=$max_words 'mw < NF { print NR "d" }' > a.sed.tmp cat $token_file2 | awk -v mw=$max_words 'mw < NF { print NR "d" }' >> a.sed.tmp cat a.sed.tmp | sort | uniq > a.sed # -fですべての命令を一括適用 sed -f a.sed $token_file1 > ${token_file1}.tmp sed -f a.sed $token_file2 > ${token_file2}.tmp # 元のファイルへ上書き mv ${token_file1}.tmp $token_file1 mv ${token_file2}.tmp $token_file2
ポイントとしてはsed -fによって一気に適用してること。1コマンドずつ順番に適用すると削除しているために行数がずれてしまいうまくいかない。
最後にmvで上書きする形をとっているのは、GNUとBSDでsed -iの挙動が異なるため。どちらかでよいなら-iでやってしまって問題なし。
あとawkの処理のところで条件を足せば空行削除も簡単。
参考