古い記事
ランダムジャンプ
新しい記事
各行にラベルとそれに関する要素のリストを持つデータをよく使う。
類似文書検索や機械学習やクラスタリングなどに。
自分流の使い方を後で参照するためにメモ。

データの各行のフォーマットはこんな感じ:
^ラベル1\t要素1-1:数値1-1,要素1-2:数値1-2,要素1-3:数値1-3,...$
^ラベル2\t要素2-1:数値2-1,要素2-2:数値2-2,要素2-3:数値2-3,...$
^ラベル3\t要素3-1:数値3-1,要素3-2:数値3-2,要素3-3:数値3-3,...$
...
各行の要素は数値の降順で並んでいる。

サンプルデータ1 (a.txt):
ゆで卵	卵:3
カレー	米:4,牛:3,豚:3,鶏肉:3,ソース:2
釜玉	卵:2,うどん:2,醤油:1
焼き鳥	鶏肉:10,醤油:5,塩:4,豚:1
豚カツ	豚:27,ソース:7,塩:6,味噌:1
豚汁	豚:3,味噌:1,ネギ:1
サンプルデータ2 (a2.txt):
ゆで卵	卵:1,塩:1,マヨネーズ:1
牛丼	牛:8,米:3
豚汁	豚:10,味噌:10,ニンジン:5,ネギ:1

以下、定番処理を Perl のワンライナーで記述。
表示のため複数行にしているのもあり。

フォーマットチェック

perl -ne 'die if !/^(.+?)\t(([^,]+?(:\d[\d.]*?)?[,\n])+)$/;' a.txt

平均要素数

perl -nlaF, -e '$n+=@F;END{print$n/$.}' a.txt
実行結果:
3.33333333333333

要素数を指定してカット

perl -pe 's/^(([^,]+?[,\n]){3}).*$/$1/;s/,$//' a.txt
実行結果:
ゆで卵  卵:3
カレー  米:4,牛:3,豚:3
釜玉    卵:2,うどん:2,醤油:1
焼き鳥  鶏肉:10,醤油:5,塩:4
豚カツ  豚:27,ソース:7,塩:6
豚汁    豚:3,味噌:1,ネギ:1

要素数分布

perl -nle '@c=split/,/;$n{@c}++;
END{map{$m=$n{$_}if$m<$n{$_}}keys%n;
$m=$m>60?60/$m:1;
print join"\n",map{"$_:$n{$_}\t".("|"x($n{$_}*$m))}sort{$b<=>$a}keys%n
}' a.txt
実行結果:
5:1     |
4:2     ||
3:2     ||
1:1     |

転置インデックスの作成

perl -nle '($l,$s)=split/\t/;
map{/^(.+):(.+)$/;$h{$1}{$l}+=$2}(split(/,/,$s));
END{for$i(sort keys%h){
print"$i\t".join",",map{"$_:$h{$i}{$_}"}
sort{$h{$i}{$b}<=>$h{$i}{$a}}keys%{$h{$i}}}
}' a.txt
実行結果:
うどん  釜玉:2
ソース  豚カツ:7,カレー:2
ネギ    豚汁:1
卵      ゆで卵:3,釜玉:2
味噌    豚汁:1,豚カツ:1
塩      豚カツ:6,焼き鳥:4
牛      カレー:3
米      カレー:4
豚      豚カツ:27,豚汁:3,カレー:3,焼き鳥:1
醤油    焼き鳥:5,釜玉:1
鶏肉    焼き鳥:10,カレー:3
(ref. [を] 転置インデックスによる検索システムを作ってみよう![2007-11-26-5])

マージ

perl -nle '($l,$s)=split/\t/;
map{/^(.+):(.+)$/;$h{$l}{$1}+=$2}(split(/,/,$s));
END{for$i(sort keys%h){print"$i\t".join",",
map{"$_:$h{$i}{$_}"}sort{$h{$i}{$b}<=>$h{$i}{$a}}keys%{$h{$i}}}
}' a.txt a2.txt
実行結果:
ゆで卵  卵:4,マヨネーズ:1,塩:1
カレー  米:4,鶏肉:3,豚:3,牛:3,ソース:2
焼き鳥  鶏肉:10,醤油:5,塩:4,豚:1
牛丼    牛:8,米:3
豚カツ  豚:27,ソース:7,塩:6,味噌:1
豚汁    豚:13,味噌:11,ニンジン:5,ネギ:2
釜玉    うどん:2,卵:2,醤油:1

共通ラベルの数

perl -nle '$h{$1}++if/^(.+)\t/;
END{$n=grep{$h{$_}==2}keys%h;print$n}' a.txt a2.txt
実行結果:
2