- ベストアンサー
Perl初心者のための頻度表作成
- Perl初心者の方に向けて、タブ区切りのデータから頻度表を作成する方法をご説明します。
- 質問文章では、タブ区切りのデータがあり、6番目、7番目、8番目のデータが全く同じ場合にカウントしたいという要望があります。
- Perlのバージョンは5.8を使用しており、ウィンドウズの環境で作業しています。助けていただける方がいれば幸いです。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
#2になにも返事してないってことは丸投げ? そもそも「ご質問」はないわな。 #!/usr/bin/perl use strict; use warnings; my $delim = '/'; my %counts; my %lines; while (my $line = <DATA>) { chomp $line; my $key = join $delim, (split $delim, $line)[5,6,7]; $counts{$key}++; $lines{$key} ||= $line; } foreach my $key (keys %lines) { #printf "%d/%s\n", $counts{$key}, $lines{$key}; printf "%d/%s\n", $counts{$key}, $key; } __END__ PB10_00045/10/B/神々/カミガミ/神々/カミガミ/名詞-普通名詞-一般/0/1/カミガミ/10/30/神々/0/1/1 PB10_00047/20/I/の/ノ/の/ノ/助詞-格助詞/0/1/ノ/30/40/の/0/1/1 PB10_00047/30/I/零落/レイラク/零落/レイラク/名詞-普通名詞-サ変可能/0/1/レーラク/40/60/零落/0/1/1 PB10_00045/10/B/神々/カミガミ/神々/カミガミ/名詞-普通名詞-一般/0/1/カミガミ/10/30/神々/0/1/1 PB10_00047/20/I/の/ノ/の/ノ/助詞-格助詞/0/1/ノ/30/40/の/0/1/1 PB10_00047/30/I/零落/レイラク/零落/レイラク/名詞-普通名詞-サ変可能/0/1/レーラク/40/60/零落/0/1/1 PB10_00045/10/B/神々/カミガミ/神々/カミガミ/名詞-普通名詞-一般/0/1/カミガミ/10/30/神々/0/1/1 PB10_00047/20/I/の/ノ/の/ノ/助詞-格助詞/0/1/ノ/30/40/の/0/1/1 PB10_00048/20/I/の/ノ/の/ノ/名詞-非自立/0/1/ノ/30/40/の/0/1/1 PB10_00050/20/I/の/ノ/の/ノ/助詞-格助詞/0/1/ノ/30/40/の/0/1/1 >perl okw.pl 3/神々/カミガミ/名詞-普通名詞-一般 2/零落/レイラク/名詞-普通名詞-サ変可能 4/の/ノ/助詞-格助詞 1/の/ノ/名詞-非自立 十万件あったとして、みたとこデータ一件が100バイトそこそこですから Perlが管理するために余計なものが引っ付いたとしても PCのスペック次第でいけなくもないでしょう。 頻度表とやらで出力するときに行丸ごとが必要ないならその分減るでしょうし。
その他の回答 (4)
- Tacosan
- ベストアンサー率23% (3656/15482)
できなかったにしても, 単に「できなかった」とだけ書くのではなく「これこれこうなった」とまで書くようにしてほしい. 実際にどうなったかというのは, 考える上で大きなヒントになる. あなたの周りがどうかはさておいて, 一般に超能力者は多くないと推定されるんだから. 「回答しやすい質問」というものを心掛けてほしいなあ. でなんだけど, これは「split をそのまま書いたんだろうな」と推測できる. もしそうなら, split するときにタブで区切るように直してくれ.
お礼
そうですね、そこが問題だったみたいです。便宜上、/を使ったのが、混乱を招いたみたいです。すみません・・・・
- Tacosan
- ベストアンサー率23% (3656/15482)
面倒なことをしたくなかったらハッシュを使えばいいんじゃないの? 例えば while (<>) { ++$occurence{join('/', (split(m!/!))[5, 6, 7])}; } で終わり? もちろん順序が重要なときにはそれなりの処理が必要ですが.
補足
この方法でやってみましたが、できませんでした・・
- mizutaki
- ベストアンサー率33% (111/333)
10万件のデータというのが厄介だなぁ そのデータはある程度固定であり、ごく希にしか内容が変化しない、と仮定の上にあれば、これで何とかなると思います。 1.6,7,8番目をソートキーとしてソートする。 2.前の行と現在の行を順番にチェックしていく 3.6,7,8,がそれぞれ同一内容ならカウントを増やし、違っていたらファイルへ追記出力 4.ループで無くなるまでやる こんな感じでやれば、チェック出来るかな? sort { (split(/\t/,$a))[$x]<=>(split(/\t/,$b))[$x]; } @array; //二次元配列を昇順ソートする $xにはソートキーになる配列番号を入れる を使用して、6,7,8をそれぞれ1回ずつソートしたデータを作って、 後はループでガンガン。 問題点としては、一度ソートしてしまうので、順番が狂うと困る場合には、全行程終了後にソートし直す必要がある。ソート回数が多いので時間がかかる。 データを追記したり変更する場合には、それなりに凝ったアルゴリズムで対策した方がいい。 と、いろいろと面倒な部分もありますが、 これで何とかなりそうですか?
お礼
アドバイス、ありがとうございます。しかし、自分の知識では、このアドバイスに対応できなさそうです・・・
- mizutaki
- ベストアンサー率33% (111/333)
6と7と8が=になったらカウントアップ、という事なのですか? もしそうでしたら、splitとstrcmpあたりを使えば出来ますけど、 それでいいのでしょうか? if文を少し組み合わせれば、出現頻度が調べれますけど
補足
わかりにくかったようで、申し訳ありません。それと、自分のやりたいことにちょっと問題もあったので、補足いたします。すみません。たとえば、下記のようであれば、6番目、7番目、8番目で全く同じ場合にカウントします。たとえば、下記のデータでは、2番目のデータは、6→の、7→ノ、8→助詞→格助詞ですが、3番目は6→の、7→ノ、8→名詞→非自立となり、3つすべてが同じではないので、別のものとしてカウントをしたいと思います。 <データ> PB10_00045/10/B/神々/カミガミ/神々/カミガミ/名詞-普通名詞-一般/0/1/カミガミ/10/30/神々/0/1/1 PB10_00047/20/I/の/ノ/の/ノ/助詞-格助詞/0/1/ノ/30/40/の/0/1/1 PB10_00048/20/I/の/ノ/の/ノ/名詞-非自立/0/1/ノ/30/40/の/0/1/1 PB10_00050/20/I/の/ノ/の/ノ/助詞-格助詞/0/1/ノ/30/40/の/0/1/1 ここからちょっと訂正したいのですが、 頻度表では、6と7と8だけを取り出し、文頭に頻度をつけたいと思っております。 頻度表 <データ> 1/神々/カミガミ/名詞-普通名詞-一般 2/の/ノ/助詞-格助詞 1/の/ノ/名詞-非自立/
お礼
ありがとうございます。無事にできました!