« 2008年12月 | トップページ | 2009年3月 »

2009年1月

そのような率

年が明けたと思ったら、仕事の方では延伸だの発注停止だの暗い話題続き。政治の世界でもイスラエルのガザ虐殺はエスカレートする一方で何とも重苦しい1月です。

さて、気を取り直して文字分析の続きです。
Interstage Data Effector体験版というツールを使っているのですが、データの連結機能が文字列の出現頻度を測るのに使えると分かりました。

これは意外な発見でした。データベースで言うとJOIN操作に当たる機能ですが、文字の部分列の一致でJOINができるのが面白い所です。

以下のようなコメントデータベース(タブ区切りテキストファイル)があるとします。

■de1-test.txt
filename    blogdate    comauthor    comdate    comtime    post    body
26873583.html    2005年07月01日    鉄男    2005-07-02    01:31    Posted by 鉄男 at 2005年07月02日 01:31     あのような物体をそのような態度で取り扱ったのがこのような事態を招いた原因だ。
27140626.html    2005年07月04日    正雄    2005-07-06    08:44    Posted by 正雄 at 2005年07月06日 08:44     うんこのような黒い物体をそのように取り扱ってはならない。このような取り扱いが正しいのです。
27140626.html    2005年07月04日    正雄    2005-07-06    10:45    Posted by 正雄 at 2005年07月06日 10:45     そうですか
26873583.html    2005年09月01日    鉄男    2005-09-02    01:31    Posted by 鉄男 at 2005年09月02日 01:31     あのような物体をあのような態度で取り扱ったのがあのような事態を招いた原因だ。

これを以下のコマンドで処理します。
shunreplace -s de1-testrep.cfg -j de1-repcond.txt > test1-rep.txt

出力されたファイルは以下のようになります。

■test1-rep.txt
"comdate","comtime","comauthor","countkey"
"2005-07-02","01:31","鉄男","あのような"
"2005-07-02","01:31","鉄男","そのような"
"2005-07-02","01:31","鉄男","このような"
"2005-07-02","01:31","鉄男","。"
"2005-07-06","08:44","正雄","このような"
"2005-07-06","08:44","正雄","そのように"
"2005-07-06","08:44","正雄","。"
"2005-07-06","10:45","正雄",
"2005-09-02","01:31","鉄男","あのような"
"2005-09-02","01:31","鉄男","。"

「あのような」「このような」「そのような」「あのように」「このように」「そのように」「。」という7種類の文字列が出現すると、そのレコード(行)のコメント日付、時刻、著者とその文字列を出力するよう設定したのです。

鉄男さんの最初のコメントは、「あのような」「そのような」「このような」「。」の4つを含んでいるので、4行の出力に展開されました。
正雄さんの最初のコメントには「このような」が2回含まれていますが、この場合でも出力は1行になります。コメントの中の出現回数を測る事はできなくて、出現したか否かだけを測る事ができます。また、文節などは意識していませんので、「うんこのように」という文脈であっても「このように」という文字列として判定されます。
正雄さんの2番目のコメントのように該当文字列が無い場合には、空の項目が出力されます。

上記のようにするための設定ファイルは以下のようになります。

■de1-testrep.cfg
FieldSeparator "\t"
JnlFile J "F:\stringcount\de1-test.txt"
MstFile {
  M "F:\stringcount\de1-repmaster.txt"
}

■de1-repmaster.txt
keyword    countkey
。    。
あのような    あのような
あのように    あのように
このような    このような
このように    このように
そのような    そのような
そのように    そのように

■de1-repcond.txt
CharacterCode UTF-8
InFileType CSV
ListDef {
  document(J) {
    $filename filename,
    $blogdate blogdate,
    $comauthor comauthor,
    $comdate comdate,
    $comtime comtime,
    $post post,
    $body body
  },
  document(M) { $key keyword, $countkey countkey }
}
OutputDef {
  $comdate, $comtime, $comauthor, $countkey
}
Jcondition {
  join(J,M, $body = $key, "LEFT")
}

これができてしまえば、shunanalyzeコマンドを使った以下の集計で簡単に頻度一覧を出せます。

shunanalyze -s de2-analyze.cfg -a de2-anacond.txt < test1-rep.txt > test2-ana.txt

結果は以下の通り。

■test2-ana.txt
"comauthor","time","maru","total","あのような","あのように","このような","このように","そのような","そのように"
"正雄","2005-07-01",1,2,0,0,1,0,0,1
"鉄男","2005-07-01",2,4,2,0,1,0,1,0

カラムの意味は以下の通りです。
1カラム目comauthor:コメント著者
2カラム目time:コメント日付
3カラム目maru:「。」の出現したコメント数
4カラム目total:「あのような」~「そのように」の6種の文字列が出現した延べコメント数
5カラム目あのような:「あのような」が出現した延べコメント数
・・・

「。」の出現するコメント数は、おそらく全コメント数に近くなると思っています。全コメント数に対する比率を考えたかったので数えてみました。本当はコメント数を別途集計する方が正確なのですが、面倒なので「。」の出現するコメント数で代替したのです。

また、totalは一つのコメントを2回以上カウントしている可能性のある数なので、全コメント数との比率を読む時には注意が必要です。

設定ファイルは以下のようにしました。

■de2-anacond.txt
CharacterCode  UTF-8

InFileType     CSV
OutFileType    CSV
MemorySize     1000

LCondition {
  $n_。_ :=
    IF  $countkey == "。" THEN 1
    ELSE 0
    ENDIF,
  $n_あのような_ :=
    IF  $countkey == "あのような" THEN 1
    ELSE 0
    ENDIF,
  $n_あのように_ :=
    IF  $countkey == "あのように" THEN 1
    ELSE 0
    ENDIF,
  $n_このような_ :=
    IF  $countkey == "このような" THEN 1
    ELSE 0
    ENDIF,
  $n_このように_ :=
    IF  $countkey == "このように" THEN 1
    ELSE 0
    ENDIF,
  $n_そのような_ :=
    IF  $countkey == "そのような" THEN 1
    ELSE 0
    ENDIF,
  $n_そのように_ :=
    IF  $countkey == "そのように" THEN 1
    ELSE 0
    ENDIF
}

GCondition  substr($comauthor,0,25) comauthor, trunc_date($comdate,"HALF") time
RCondition    sum($n_。_) maru ,  sum($n_あのような_) + sum($n_このような_) + sum($n_そのような_) + sum($n_あのように_) + sum($n_このように_) + sum($n_そのように_) total,  sum($n_あのような_) あのような,  sum($n_あのように_) あのように,  sum($n_このような_) このような,  sum($n_このように_) このように,  sum($n_そのような_) そのような,  sum($n_そのように_) そのように

■de2-analyze.cfg
# FieldSeparator "\t"
WorkFolder "F:\stringcount\"

なぜこのようにしたかと言うと、シベリア板に以下のような発言があって、気になっていたからです。

20 名前:いやあ名無しってほんとにいいもんですね[sage] 投稿日:2008/12/09(火) 20:03:38 発信元:219.165.53.195
前から気になってたんですが、今回のエントリで数えて、みたら
このような 9回
そのような 2回
この、その、これ、それ等多数が使用されていました。
それだけですが…

22 名前:いやあ名無しってほんとにいいもんですね[sage] 投稿日:2008/12/10(水) 21:27:02 発信元:219.165.53.195
ANA関係のエントリではざっと数えて(文脈のおかしいのはおいといて)
このような(に) 1
この 12
これ 7
その 2
それ 4
> この件ですが、これは飲んでいたことは事実ですが、その後の調査でこのサプリメントはその検査機には反応しないことが分かったそうです。
サプリメントは「ミッカンMICRA」と言うものだそうですが、それは酢酸が混入しているので、それが検査機に反応したと思ったそうですが、
そうではなかったという回答が得られました。
この件も私がブログで書いたので、慌てて会社側が調べ直して、「サプリメントではなかった。」と報告をし直したと私は考えています。
あくまでも初期段階の話で、後日判明したそうですが、私が書かなければこのケースはサプリメントが犯人にされていたかも知れません。
さて、日本航空が花火を積んで運んだ件ですが、この便に乗車した方がいればと呼びかけましたが、現在までの所メールはありませんでした。

こういうものなんでしょうか?

23 名前:いやあ名無しってほんとにいいもんですね[sage] 投稿日:2008/12/10(水) 21:37:40 発信元:219.165.53.195
領海侵犯
このような 4
この 6
その 6

言われてみると、瀬戸氏の発言には「このような」という言い回しが多用されている印象があります。てな訳で、2008年末までの全コメントについて先ほどの方法でカウントしてみました。

■stringcount.bat
rem stringcount.bat
rem de-repmaster.txt で定義したキーワードの出現回数をカウントする
del countout1-rep.txt countout2-ana.txt countout3-sel.txt countout4-sort.txt
shunreplace -s de1-rep.cfg -j de1-repcond.txt > countout1-rep.txt
shunanalyze -s de2-analyze.cfg -a de2-anacond.txt < countout1-rep.txt > countout2-ana.txt
shunselect -s de3-sel.cfg -q de3-selcond.txt < countout2-ana.txt > countout3-sel.txt
shunsort -a de4-sortcond.txt < countout3-sel.txt > countout4-sort.txt

■de1-rep.cfg
FieldSeparator "\t"
JnlFile J "D:\scomgram\commentdb-noq.txt"
MstFile {
  M "F:\stringcount\de1-repmaster.txt"
}

■de3-selcond.txt (以下の条件で抽出)
1 $total >= 5 AND $maru >= 20

結果をExcelに取り込んで、「。」出現コメント数に対するtotal数の率の順に並べてみました。
20%以上のコメント者は以下のようになります。timeの欄は、yyyy-01-01となっているのが1月~6月の上半期、yyyy-07-01となっているのが7月~12月の下半期を表します。これを見ると、どの時期をとっても、瀬戸氏の発言は率が高い事が分かります。こんなに鮮やかに現れるとは驚きです。

comauthor    time    maru    total    率
ヒトシ1015    2008-01-01    28    9    32.1%
せと弘幸    2007-07-01    81    26    32.1%
大韓王    2008-07-01    82    25    30.5%
瀬戸弘幸    2006-07-01    418    126    30.1%
sayoku?    2006-07-01    217    64    29.5%
瀬戸弘幸    2006-01-01    693    189    27.3%
基準点    2006-07-01    33    9    27.3%
土民    2008-07-01    46    12    26.1%
瀬戸弘幸    2007-01-01    267    67    25.1%
愛国主義者    2007-01-01    20    5    25.0%
datetopic    2006-07-01    20    5    25.0%
月影兵庫    2008-07-01    85    21    24.7%
!    2008-07-01    78    19    24.4%
多聞丸    2008-01-01    25    6    24.0%
瀬戸弘幸    2005-07-01    30    7    23.3%
荑戸弘幸    2006-01-01    95    22    23.2%
視点    2006-07-01    52    12    23.1%
せと弘幸    2008-07-01    261    59    22.6%
主婦    2008-01-01    46    10    21.7%
WWWへの同情者その2    2008-07-01    37    8    21.6%
せと弘幸    2008-01-01    128    27    21.1%
トランプ    2006-07-01    86    18    20.9%
まりこ    2006-07-01    34    7    20.6%

では、どの言葉の出現頻度が高いかを以下の一覧で見てみます。瀬戸氏については、「そのような」「このような」が多いようです。

comauthor    time    maru    total    率    あのような    あのように    このような    このように    そのような    そのように
ヒトシ1015    2008-01-01    28    9    32.1%    0    0    8    0    1    0
せと弘幸    2007-07-01    81    26    32.1%    0    0    7    0    13    6
大韓王    2008-07-01    82    25    30.5%    0    0    11    1    11    2
瀬戸弘幸    2006-07-01    418    126    30.1%    2    0    26    6    77    15
sayoku?    2006-07-01    217    64    29.5%    3    1    11    2    31    16
瀬戸弘幸    2006-01-01    693    189    27.3%    4    1    59    12    96    17
基準点    2006-07-01    33    9    27.3%    0    0    6    0    2    1
土民    2008-07-01    46    12    26.1%    2    0    5    2    3    0
瀬戸弘幸    2007-01-01    267    67    25.1%    1    0    13    2    44    7
愛国主義者    2007-01-01    20    5    25.0%    0    0    3    0    2    0
datetopic    2006-07-01    20    5    25.0%    1    0    3    0    1    0
月影兵庫    2008-07-01    85    21    24.7%    2    0    10    0    7    2
!    2008-07-01    78    19    24.4%    0    0    9    0    6    4
多聞丸    2008-01-01    25    6    24.0%    1    0    2    1    2    0
瀬戸弘幸    2005-07-01    30    7    23.3%    0    0    1    0    4    2
荑戸弘幸    2006-01-01    95    22    23.2%    0    0    8    1    13    0
視点    2006-07-01    52    12    23.1%    2    0    7    0    3    0
せと弘幸    2008-07-01    261    59    22.6%    1    0    10    0    34    14
主婦    2008-01-01    46    10    21.7%    0    0    4    3    2    1
WWWへの同情者その2    2008-07-01    37    8    21.6%    1    0    3    0    2    2
せと弘幸    2008-01-01    128    27    21.1%    0    0    8    2    14    3
トランプ    2006-07-01    86    18    20.9%    1    0    9    0    7    1
まりこ    2006-07-01    34    7    20.6%    0    0    4    0    3    0

そこで、「そのような」の出現率に着目して並べたのが以下の一覧です。この表では更に鮮やかに瀬戸氏の「そのような」多用傾向が現れていると思います。

comauthor    time    maru    total    率    あのような    あのように    このような    このように    そのような    そのように    そのような率
瀬戸弘幸    2006-07-01    418    126    30.1%    2    0    26    6    77    15    18.4%
瀬戸弘幸    2007-01-01    267    67    25.1%    1    0    13    2    44    7    16.5%
せと弘幸    2007-07-01    81    26    32.1%    0    0    7    0    13    6    16.0%
sayoku?    2006-07-01    217    64    29.5%    3    1    11    2    31    16    14.3%
瀬戸弘幸    2006-01-01    693    189    27.3%    4    1    59    12    96    17    13.9%
荑戸弘幸    2006-01-01    95    22    23.2%    0    0    8    1    13    0    13.7%
大韓王    2008-07-01    82    25    30.5%    0    0    11    1    11    2    13.4%
瀬戸弘幸    2005-07-01    30    7    23.3%    0    0    1    0    4    2    13.3%
せと弘幸    2008-07-01    261    59    22.6%    1    0    10    0    34    14    13.0%
『日本よ何処へ』管理者    2007-07-01    86    11    12.8%    0    0    0    0    11    0    12.8%
せと弘幸    2008-01-01    128    27    21.1%    0    0    8    2    14    3    10.9%
opps    2006-07-01    46    9    19.6%    0    0    3    0    5    1    10.9%
極右評論管理者    2006-01-01    231    30    13.0%    1    1    2    0    24    2    10.4%
kame    2006-07-01    78    12    15.4%    1    0    2    0    8    1    10.3%
愛国主義者    2007-01-01    20    5    25.0%    0    0    3    0    2    0    10.0%

本日は以上です。

| | コメント (0) | トラックバック (0)

特定著者コメントのNグラム頻度集計

今回は、前回出した瀬戸氏コメント集をNグラム集計してみました。

まずは数が少ないのですが2005年分(コメント数:31)から。
8グラムのTOP2は以下の通りです。コメントに対して応答を返しているとすると納得行きます。
"8","ありがとう御座い",10
"8","りがとう御座いま",10

2グラムのTOP5は以下の通りです。文尾の形は共通になりやすいという事だと思います
"2","す。",106
"2","ます",77
"2","てい",68
"2","いま",64
"2","。 ",59

漢字2文字の2グラムのTOP5は以下の通りです。極右の政治ブログらしい熟語が並んでいます。
"2","主義",26
"2","日本",23
"2","極右",22
"2","社会",19
"2","国家",16

次は最も年間コメント数が多い2006年分(コメント数:1207)です。
8グラムの上位は以下の通りです。とおるさんと怒る小市民さんへの返答が多かった事が伺えます。
"8","ありがとう御座い",254
"8","りがとう御座いま",254
"8","がとう御座います",217
"8","とう御座います。",211
"8"," とおるさんへ ",124
"8","ではないでしょう",117
"8"," 怒る小市民さん",109
"8","る小市民さんへ ",107
"8","怒る小市民さんへ",107

このほか、特定の人へのコメントと思われるものとしては以下がありました。これはMultiSyncさんへのものでしょう。ハンドルネームが短い人の名前は他の語に紛れてしまうので、8グラムだけで取り上げるのは不公平かもしれません。
"8","iSync さん",42

6グラムの上位は以下の通りです。やはり、文尾の形は共通になりやすいという事でしょうか。
"6","と思います。",467
"6","とう御座いま",258
"6","ないでしょう",257

4グラムの上位は以下の通りです。「さんへ 」という相手への呼びかけを除けば文尾の形ばかりです。
"4","さんへ ",1906
"4","います。",1331
"4","でしょう",950
"4","しょう。",755
"4","ました。",720
"4","ます。 ",638
"4","ています",581
"4","ません。",568
"4","思います",566

漢字2文字の2グラムの上位は以下の通りです。中国・朝鮮・社会・共産といった熟語が上位に登場しており、瀬戸氏の主張と符合する感じです。
"2","日本",1018
"2","問題",372
"2","中国",301
"2","御座",296
"2","主義",276
"2","朝鮮",258
"2","国家",256
"2","社会",237
"2","今後",218
"2","共産",205
"2","韓国",204
"2","新聞",187
"2","本人",187
"2","極右",186
"2","米国",176
"2","市民",171
"2","左翼",168
"2","政治",161

三番目は2007年分(コメント数:375)です。
8グラム上位は以下の通りです。
"8","ありがとう御座い",39
"8","りがとう御座いま",39
"8","ありがとうござい",38

4グラムの上位は以下の通りです。やはり「さんへ 」以外は文尾の形です。
"4","います。",289
"4","さんへ ",262
"4","ました。",228
"4","ます。 ",172
"4","でしょう",166

漢字2文字の2グラムの上位は以下の通りです。「新風」が2位に「支持」が7位に来ており、選挙があった事を反映しているようです。
"2","日本",113
"2","新風",69
"2","問題",65
"2","御座",46
"2","投稿",46
"2","各位",45
"2","支持",42
"2","朝鮮",42
"2","極右",42
"2","主義",40
"2","今後",40
"2","批判",37
"2","政治",37
"2","本人",36
"2","活動",36
"2","出来",34
"2","国家",34
"2","意見",34
"2","政党",32
"2","現在",32

最後に2008年分(コメント数:391)です。
8グラムの上位は以下の通りです。なんとshinok30さんが8位に登場しています。ハンドルネームの短い人が埋もれている可能性はあるのですが、それでも瀬戸氏がshinok30さんに返答を返す頻度は高かったと言えるでしょう。
"8","ありがとう御座い",40
"8","りがとう御座いま",40
"8","ではありません。",32
"8","がとう御座います",26
"8","とう御座います。",26
"8","ありがとうござい",25
"8","りがとうございま",25
"8","shinok30",23

漢字2文字の2グラムの上位は以下の通りです。いきなり「創価」がトップに立った一方、新風・朝鮮・極右といった熟語は軒並み順位を下げています。
"2","創価",79
"2","学会",73
"2","価学",72
"2","日本",70
"2","問題",63
"2","投稿",55
"2","我々",46
"2","各位",45
"2","削除",44
"2","御座",43
"2","関係",43
"2","今後",42
"2","紹介",40
"2","記事",40
"2","出来",37
"2","今回",36
"2","裁判",35
"2","訂正",33
"2","新風",32

以上、ざっと頻度集計の上位を見てみました。直感的に分かりやすいのは固有名詞か漢字熟語ですね。ちなみに、予想はしていたのですが、創価のキーワードが圧倒的に多くなるのは2008年です。
com2gram1.1-2008-sort.txt(1847): "2","創価",79
com2gram1.1-2007-sort.txt(2044): "2","創価",25
com2gram1.1-2006-sort.txt(10307): "2","創価",35

他にも色々な分析ができると思いますし、他者との比較も大事なのですが今日はここまで。楽しかった正月休みも終わるので、記事投稿頻度はぐっと下がると思います。

最後に使用したプログラムをまとめておきます。

以下のようなバッチファイルで一括処理しました。

rem 2008
del com2gram1.1-result.txt com2gram1.1-ana.txt com2gram1.1-select.txt
com2gram1.1.pl cdb2008.txt -skip1
shunanalyze -s analyze.cfg -a anacond.txt < com2gram1.1-result.txt > com2gram1.1-ana.txt
shunselect -s select.cfg -q selectcond.txt < com2gram1.1-ana.txt > com2gram1.1-select.txt
shunsort -a sortcond.txt < com2gram1.1-select.txt > com2gram1.1-2008-sort.txt

rem 2007
del com2gram1.1-result.txt com2gram1.1-ana.txt com2gram1.1-select.txt
com2gram1.1.pl cdb2007.txt -skip1
shunanalyze -s analyze.cfg -a anacond.txt < com2gram1.1-result.txt > com2gram1.1-ana.txt
shunselect -s select.cfg -q selectcond.txt < com2gram1.1-ana.txt > com2gram1.1-select.txt
shunsort -a sortcond.txt < com2gram1.1-select.txt > com2gram1.1-2007-sort.txt

rem 2006
del com2gram1.1-result.txt com2gram1.1-ana.txt com2gram1.1-select.txt
com2gram1.1.pl cdb2006.txt -skip1
shunanalyze -s analyze.cfg -a anacond.txt < com2gram1.1-result.txt > com2gram1.1-ana.txt
shunselect -s select.cfg -q selectcond.txt < com2gram1.1-ana.txt > com2gram1.1-select.txt
shunsort -a sortcond.txt < com2gram1.1-select.txt > com2gram1.1-2006-sort.txt

rem 2005
del com2gram1.1-result.txt com2gram1.1-ana.txt com2gram1.1-select.txt
com2gram1.1.pl cdb2005.txt -skip1
shunanalyze -s analyze.cfg -a anacond.txt < com2gram1.1-result.txt > com2gram1.1-ana.txt
shunselect -s select.cfg -q selectcond.txt < com2gram1.1-ana.txt > com2gram1.1-select.txt
shunsort -a sortcond.txt < com2gram1.1-select.txt > com2gram1.1-2005-sort.txt

com2gram.plには、若干手を加えてcom2gram1.1.plとしました。主な変更点は-skip1オプションの導入で、これを指定すると、(1)最初の行を読み飛ばす、(2)行の最初と最後の引用符を読み飛ばす、という処理をします。

# com2gram1.1.pl [-skip1] file...
# fileのテキストを1~8グラム分割して以下のファイルに出力する
# $resultfilename ("D:\com2gram\com2gram1.1-result.txt")
# 入出力するファイルはUTF8の想定
#
# 引数にテキストファイルを複数指定可能
# -skip1 はオプションとして以下の意味を持つ
# (shunselectの出力を食うためのオプション)
# ・ 最初の1行をスキップ(カラム名のある行と見て)
# ・ 行の最初と最後にあるダブルクオートを削除

use strict;
use utf8;
use Encode;

my @filelist;
my $skip1 = 0; # skip1オプションフラグ
# 結果出力ファイルをフルパスで指定(UTF8の想定)
my $resultfilename = "D:\\com2gram\\com2gram1.1-result.txt";

# 引数を@filelistに読み込む。skip1オプションのみ特殊処理
foreach my $arg (@ARGV) {
  if( $arg eq "-skip1" ) {  $skip1 = 1; }
  else { push @filelist, $arg ; }
}

open(OUT,">:utf8",$resultfilename);
print OUT "num\tstring\n";

foreach my $file (@filelist) {
  open(IN, "<:utf8","$file") || die("cannot open $file\n");
  my @comlist = <IN>;
  close(IN);
  if (@comlist == 0) { next; }  # ファイルが空ならば次へ
  chomp(@comlist);
  if( $skip1 ) {        # -skip1 オプション指定の場合
    shift( @comlist ); # 最初の行を削除
    for(my $i =0; $i <= $#comlist; $i++  ) { # 各行の先頭と最後のダブルクオートを削除
      $comlist[$i] =~ s/^"//;
      $comlist[$i] =~ s/"$//;
    }
  }

  foreach my $com ( @comlist ) {
    # $j はグラム数を表す
    for( my $j = 1; $j <= 8; $j++ ) {
      # 文字列の先頭から1文字ずつずらして区切って行く
      for( my $i = 0; $i < ( length($com) - ($j-1) ); $i++ ) {
        print OUT $j, "\t", substr($com,$i,$j), "\n";
      }
    }
  }
  close OUT;
}

| | コメント (0) | トラックバック (0)

コメントデータベースから特定著者の発言抽出

今回は、前回作ったコメントデータベース(タブ区切りテキスト)から、特定のコメント著者の発言部分だけを抽出し、年別にファイルに分けてみます。

Data Effectorで提供されているshunselectコマンドに条件毎にファイルに振り分ける機能があったのでこれを使ってみます。中核となるコマンド行は以下です。
shunselect -s select.cfg -q selectcond.txt -o selectout.txt < commentdb.txt

各設定ファイルは以下のようにしました。

■selectcond.txt

1 { $body } $blogdate = "^2005" AND $comauthor = "弘幸$"
2 { $body } $blogdate = "^2006" AND $comauthor = "弘幸$"
3 { $body } $blogdate = "^2007" AND $comauthor = "弘幸$"
4 { $body } $blogdate = "^2008" AND $comauthor = "弘幸$"
5 (%1) OR (%2) OR (%3) OR (%4)

■selectout.txt

1> D:\scomgram\cdb2005.txt
2> D:\scomgram\cdb2006.txt
3> D:\scomgram\cdb2007.txt
4> D:\scomgram\cdb2008.txt
5> D:\scomgram\cdbOther.txt

■select.cfg

CharacterCode  UTF-8
InFileType     CSV
FieldSeparator "\t"
LogFile "D:\scomgram\Select.log"
ErrFile "D:\scomgram\selecterr.csv" 10

「shuncond.txt」で振り分けの条件と、結果として書かれる値を指定しています。
ここでは瀬戸弘幸氏の名前で書かれたコメントを抽出する事にして、コメント著者名の末尾が「弘幸」であるものをブログの日付の年別に振り分ける条件を書いています。「{ $body }」という記述は、出力されるファイルに書かれる内容が、コメントDBの「body」というカラムだけという指定です。つまり、コメント内容だけが出力されます。

この条件に応じた出力先のファイル名を「selectout.txt」に指定しています。5番目の「cdbOhter.txt」は後のチェック用に1~4番目の条件に該当するものの全カラムを出力しています。

Data Effectorの「体験版」には、記述できる振り分け条件数5以下という制約があるらしいのですが、上記を試すには丁度良い上限でした。

2008年12月までのコメントを処理して、最初のコメントDBは68.9MBありましたが、抽出後のファイルの大きさは以下のようになりました。
2005年分:20KB
2006年分:792KB
2007年分:190KB
2008年分:175KB
色々論争が多かった2008年分が多いと予想したのですが、これは間違ってました。実は2006年の方が記述量は遙かに多かったんですね。

なお、Data Effectorのマニュアルを読んだのですが、半角の引用符(")を一般の文字として扱うオプションを見つけられず、やむなく振り分け処理の前に半角引用符(")を全角ダブルプライム(″)に置き換えました。したがって、半角引用符と全角ダブルプライムについては今後の集計が正しく出ません。
(この辺の特殊文字の使い方も個人差が出そうです。私は今回初めて全角ダブル引用符(“”)と全角ダブルプライム(″)の差を意識しました。)

上記の文字変換のために以下のような簡単なPerlプログラムを書きました。

# convertquote.pl file1 file2
# file1の引用符(")(ダブルクオート)を全角のダブルプライム(″)に置き換えてfile2に書く
# file2を上書きするので要注意
use utf8;
my $file1 = shift;
my $file2 = shift;

open(IN, "<:utf8", $file1) || die("cannot read open $file1\n");
open(OUT,">:utf8", $file2) || die("cannot write open $file2\n");

while (my $line = <IN>) {
  $line =~ s/"/″/g;
  print OUT $line;
}
close(IN);
close(OUT);

最終的には以下のようなバッチファイルでコメントDB(commentdb.txt)から抽出を行いました。

rem コメントDBを年別にファイルに分割する
rem 事前に引用符(")を全角のダブルプライムに変換する
rem 分割先ファイル名はselectout.txtに、分割条件はselectcond.txtに指定

convertquote.pl commentdb.txt commentdb-noq.txt
shunselect -s select.cfg -q selectcond.txt -o selectout.txt < commentdb-noq.txt

この振り分けの結果、例えばcdb2005.txt(2005年分の瀬戸氏のコメント集)の冒頭部分は以下のようになりました。これで特定著者のNグラム頻度分析の準備がだいたいできた事になります。

"body"
" 投稿ありがとう。宋教仁については余り詳しくありませんが、石原莞爾と北一輝には興味があり、若かりし頃は北一輝の故郷であった佐渡に行きました。 しかし、佐渡の住民で北一輝のことを知る人とは会うことは出来ませんでした。 対して、石原莞爾の故郷を訪ねた時のことです。殆どの人が石原莞爾を「あの偉い先生」と呼んで尊敬していました。 先生の墓を訪ねた時のことは今でも忘れません、山の上に小高く盛られたその墓は、威厳に満ちていました。 夏の暑い日でした。蝉の鳴き声がうるさいにの、何故かシーンと静まり返っていたのを記憶しています。記帳のノートがあり、覗いてみると遠くは米国、ブラジルからも墓参りに来ていた人がおりました。"
" ある意味、日本は情ない。 戦略的思考がゼロです。"

文字分析を始めてから気がつきましたが、こういった事前のデータ振り分けは処理時間を減らすために重要です。著者と日時の情報を持っていれば、論理的には全データをひとまとめにして処理する事で著者別・日時別の集計も出せるのですが、現実には処理時間がかかり過ぎてしまい人間がついていけません。できるだけデータを小分けにして処理する算段をするのが分析の効率化には欠かせないと思いました。

それにしても、ブログが花盛りの昨今、ブログのデータを元にした研究も盛んに行われていると思うのですが、皆さん、どうやってデータ処理されているのでしょう? 定番があって良さそうですが、実はそうでもないのかなぁという気がしてます。

| | コメント (0) | トラックバック (0)

ブログのコメントのデータベース化

今回は、ブログのコメントをデータベース化する方法について書いてみます。
データベース化と言ってもデータベースシステムにデータを入れるのではなく、幾つかのキーを使った抽出や集計が行いやすいようにタブ区切りテキスト化するだけです。

題材としては、おなじみの「せと弘幸Blog『日本よ何処へ』」を使わせていただきます。

おそらく、コメントを記述するHTMLの構造はLivedoorのブログに共通していると思うので、Livedoorブログであれば他のブログにも応用可能だと思います。

タブ区切りテキストの形としては以下を想定します。(実際のコメントから内容例を引用しています)

filename	blogdate	comauthor	comdate	comtime	post	body
29704240.html 2005年08月05日 瀬戸弘幸 2005-08-05 20:22 Posted by 瀬戸弘幸 at 2005年08月05日 20:22 ある意味、日本は情ない。 戦略的思考がゼロです。
50282975.html 2005年11月28日 瀬戸弘幸 2005-12-01 17:01 Posted by 瀬戸弘幸 at 2005年12月01日 17:01 たしかにおっしゃられる点は理解します。ハンチントンにおかされているか、そうでないかは別にしても、不気味な世界情勢になっていることは確かではないでしょうか。

これらのカラムは以下の意味を持ちます。

filename: そのコメントが存在するブログのファイル名
blogdate: そのブログの記事が書かれた日付
comauthor: コメント著者(後ろのpostから抽出)
comdate: コメント日付(後ろのpostから抽出)
comtime: コメント時刻(後ろのpostから抽出)
post: コメント投稿情報(HTMLの<div class="comments-post">タグの内容)
body: コメント本文(HTMLの<div class="comments-body">タグの内容)

こういう形にしておくと、コメント著者名やコメント本文を区別した検索が簡単になります。
例えば、コメント著者名として「瀬戸弘幸」氏が現れるコメントを検索したいのであれば、
^.*\t.*\t瀬戸弘幸\t
という正規表現を使えばできます。ここまで正確にしなくても「\t瀬戸弘幸\t」でも十分でしょう。(ちなみに、瀬戸氏は「せと弘幸」や瀬の異字体を使った名前でもコメントされているので、もっと単純な「弘幸\t」がかなり正確で網羅的な検索条件になるかと思います)

また、例えば、「新風連ヲチスレテンプレ置き場」にある以下の指摘に出てくるコメントを検索するには「弘幸\t.*\t.*\t.*\t.*弘幸氏.*$」とすれば良いです。コメント著者名が「弘幸」で終わっており、かつ、コメント本文中に「弘幸氏」という文字が入っているコメントを検索しています。

(2)2008年3月、再び自演失敗。
ttp://s04.megalodon.jp/2008-0325-2253-05/blog.livedoor.jp/the_radical_right/archives/51862209.html
>ただし大阪の大衆は割合ざっくばらんです。まずは行動する集団を支持するのです。
>維新政党新風副代表瀬戸弘幸氏は、確かに「大阪というギルド」に風穴をあけました。
>
>Posted by せと弘幸 at 2008年03月25日 22:21

このデータベース化をするPerlプログラムは以下です。もちろん、何の動作保証もありませんので、試したい方は自己責任でお願いします。

use strict;
use utf8;
use HTML::TreeBuilder;
use Encode;

# 出力ファイル名(コメントDB)指定
my $cdbfile = "D:\\temp2\\commentdb.txt";

# コマンドの第一引数にディレクトリのパスが与えられていると仮定
my $dirname = shift;
my @filelist;
# 指定されたディレクトリをOpenし、99999999.htmlのファイル名のみを@filelistに入れる
# @filelistの中にあるファイルだけが処理対象
opendir(DIR, $dirname) || die("error: cannot open $dirname\n");
while (my $file = readdir(DIR)) { 
  if( $file =~ /^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\.html$/ ) {
    push (@filelist, $file); 
    }
  }
closedir(DIR);
if( @filelist == 0 ) { die("error: filelist empty\n"); }

# ディレクトリパスの最後が\でなければ補っておく
if( $dirname !~ /\\$/ ) { $dirname = $dirname . "\\" ; }

open(CDBOUT, ">:utf8", $cdbfile); # UTF8指定を忘れずに
print CDBOUT "filename\tblogdate\tcomauthor\tcomdate\tcomtime\tpost\tbody\n";  # 見出し行

foreach my $file ( @filelist ) {
  print "$file\n";  # 進行状況が見えるように、ファイル名をコンソールに出力
  my $tree = HTML::TreeBuilder->new;
  my $filepath = $dirname . $file ;
  # Livedoor BlogはEUCなのでEUC指定しているつもりなのだが正しくないかも。
  #open(HTML, "<:euc_jp","$filename") || die("cannot open $filename\n");
  open(HTML,"<:encoding(euc-jp)","$filepath") || die("cannot open $filepath\n");

  my @line = ;
  close(HTML);
  foreach my $line1 (@line) {
    $tree->parse($line1);
  }
  $tree->eof();

  my $title = ($tree->find("title"))->as_text;    # titleタグの中身を抽出
  my $date = ($tree->find("h2"))->as_text;     # 最初のH2タグの中身は日付と思う

  # コメント本体とポスト日付・主名の抽出
  my @cbody = $tree->look_down("class","comments-body");
  my @cpost = $tree->look_down("class","comments-post");
  
  if( @cbody != @cpost ) {  # 両者の個数が違う場合は対応が崩れていると判断しスキップ
    print "skip!! number of body and post is not equal: $file\n";
    next;
  }
  if (@cbody == 0) { next; }  # コメント数が0なら次へ
  
  my $i;
  for( $i=0; $i < $#cbody ; $i++ ) {
    print CDBOUT "$file\t";    # 1カラム目:ファイル名
    print CDBOUT "$date\t";  # 2カラム目:日付(ブログ記事自体の)
    my $post = $cpost[$i]->as_text; # Post情報から改行とタブを削除
    $post =~ s/\n//g;
    $post =~ s/\t//g;
    my $body = $cbody[$i]->as_text; # Body情報から改行とタブを削除
    $body =~ s/\n//g;
    $body =~ s/\t//g;
    if( $post =~ "^Posted by *(.*) at ([0-9][0-9][0-9][0-9]).+([0-9][0-9]).+([0-9][0-9]).+([0-9][0-9]:[0-9][0-9])\$" ) {
      print CDBOUT "$1\t", "$2-$3-$4\t", "$5\t", "$post\t", "$body\n";
      # $1: 投稿者名、$2-$3-$4: yyyy-mm-dd、$5: hh:mm となっている筈
    } 
    else { die "posted by pattern mis match: $post\n"; }
  }
  $tree->delete; # Deleteは必須。こうしないとメモリが開放されない。
}
close CDBOUT;
print "finished\n";

このプログラムはコマンドの第一引数にgetHTMLで取得したarchivesディレクトリのパスが指定されると想定しています。例えば、このPerlプログラムのファイルがblog2cdb.plだとすると、以下のようなコマンドラインで起動します。
blog2cdb.pl "D:\temp2\getHTML\blog.livedoor.jp\the_radical_right\archives"
ちなみに、私のロートルPCでは2008年10月22日分までの記事で実行に1時間以上かかりました。
(getHTMLの話は、「テキスト処理の道具達(1):Webページの収集ツール」に載せました)

生成するファイルは以下のようにPerlの中に直に書いてますので、変更したい時はPerlプログラムを修正してください。
my $cdbfile = "D:\\temp2\\commentdb.txt";

コメントの認識は、HTML中に以下のような構造で記述されている事を利用しています。つまり、コメント本文は<div class="comments-body">というタグの中に現れ、著者情報は<div class="comments-post">というタグの中に現れるという構文です。

        <div class="comments-body">
たしかにおっしゃられる点は理解します。ハンチントンにおかされているか、そうでないかは別にしても、不気味な世界情勢になっていることは確かではないでしょうか。</div>
        <div class="comments-post">Posted by 瀬戸弘幸
at 2005年12月01日 17:01</div>

但し、この構造には例外があります。本文中でコメントを引用する際に、このタグが一緒にコピーされている例があります。この場合、現在のプログラムの作りでは、本文の中でのコメント引用なのか、コメント本体なのかを区別できません。また、本文中のコメント引用は、記事を書く人が勝手にできるのか、<div class="comments-body">と<div class="comments-post">が対をなさない構造も書けてしまうようです。こういう勝手な構造を作られると正常に認識できなくなるので、せめてもの対処として、両者の数が同じであるかをチェックしています。数が異なるHTMLがあった場合には、HTMLファイルの手修正で対応するしかありません。

| | コメント (0) | トラックバック (0)

Nグラム文字分割による単語頻度分析

あけましておめでとうございます。
年末は忙しいやら体調を崩すやらで何もできない状態でしたが、ようやく休みに入って少しまとまった時間ができたので、文字解析の続きをやってみました。

今回は、文の中に現れる「単語」の頻度を調べてみます。
文字分析の世界では、文章から切り出した1文字の文字列切片を1グラム、2文字の文字列切片を2グラム・・という風に呼ぶそうです。任意の自然数Nに対して、その長さの文字列切片が考えられるので、切片を切り出す方法そのものをNグラム方式などと称するようです。

このNグラム方式で「単語」らしきものを切り出してみて頻度を集計してみました。
対象とする文としては、ネットウォッチ大賞2008の「瀬戸ゼリ幸」さんへの投票の際の「投票理由」を選んでみました。これは、おそらく「うんこ」とか「ウンコ」の頻度が高く出てくるだろうという手堅い予測(笑)があったからです。まぁザッと見ただけで分かるのですが。なお、投票の際には投票者名も自由に記入できるのですが、今回は対象としていません。

http://www4.atpages.jp/watch2008/vote/vote.cgi?mode=comm&no=3
ネットウォッチ大賞2008 瀬戸ゼリ幸 の投票理由

処理の手順と手法は以下の通りです。
(1) 投票理由のテキストファイルを作る(一行に一理由とする)
  秀丸エディタで手作業
(2) 上記を切り刻んで1グラム~8グラムに分解したテキストファイルを作る
  Perlのプログラムで処理
(3) 上記を集計
  ShunAnalyzeコマンド(Data Effector体験版)利用
(4) 上記から頻度10以上の切片のみを抽出
  ShunSelectコマンド(Data Effector体験版)利用
(5) 上記を頻度順にソート
  ShunSortコマンド(Data Effector体験版)利用

この方法では、形態素解析のように単語の区切りや品詞を意識しないので、結果として得られるリストには単語ではない文字列も含まれます。例えば、「価学会のウンコ攻」(8グラム)とか「ャーナリ」(4グラム)などです。
したがって、どれを単語とみなすかは最終的に人間が目で見て判断する必要があります。

という訳で、結果のリストを見て意味のありそうな文字列を拾ってみました。各カラムは、それぞれグラム数,文字列,頻度の意味です。
"3","うんこ",86
"3","ウンコ",76
"3","だから",23
"2","ゼリ",30
"2","創価",20
"2","瀬戸",19
"1","!",92
"1","・",39
"1","w",37
"1","人",25
"1","糞",22

やはり今回はウンコ用語が圧倒的な存在感を示しています。これがなければ、創価学会関係とゼリー関係が上位に来たのかもしれません。残念ながら分かったのはそれだけです(笑)。

今回使った方法を以下に説明します。

(1) 投票理由のテキストファイルを作る(一行に一理由とする)
投票理由の一行は「・最強のブーメラン使い (2008/11/03(Mon) 00:54/nanomania)」のような形式になっているので、先頭の「・」と末尾の「 (2008/」以降を秀丸エディタで削除しました。この結果をcom.txtというテキストファイルに入れます。

■com.txt(354行)

ニコニコにうpされてたナノゼリーの動画が最高に面白かった
そろそろこの人がとってると面白そうなので
ゼリーだから
・・・

(2)から(5)までは以下のバッチファイルで一括実行します。この位のデータ量であればExcelでの処理も可能ですが、時間がかかるのと手操作の繰り返しが苦しいので、できるだけバッチ化するのが吉です。
私も文字分析をやり初めて分かったのですが、多量のデータを簡単に集められるので計算量も簡単に増大して手に負えなくなります。Excelに頼り過ぎない方が結果的には作業の効率が上がると思います。

■バッチファイル

rem テキストファイルから1~Nグラム文字列の頻度を求めるバッチ

rem 1~Nグラムの文字列を生成
rem 入力:com.txt
rem 出力:D:\temp\com2gram-result.txt
com2gram.pl com.txt

shunanalyze -s analyze.cfg -a anacond.txt < com2gram-result.txt > com2gram-ana.txt

shunselect -s select.cfg -q selectcond.txt < com2gram-ana.txt > com2gram-select.txt

shunsort -a sortcond.txt < com2gram-select.txt > com2gram-sort.txt

(2)で使ったPerlプログラムは以下です。処理の際の文字コードはUTF8に統一しておくのが吉です。Shift-JISやEUCでは表現できる文字の範囲が狭いので、もはや文字処理には使えないと思います。
PerlでのUTF8の使い方が分からずに苦労しましたが、以下のプログラムではOpenの際に明にUTF8である事を宣言しています。標準入出力でのUTF8の扱いが良く分からないので、ここでは入力も出力もファイルとしています。
また、このプログラムの中で1~8グラムの切片を切り出す事を決めてます。ここを変えれば、4グラムだけ、とか、3~5グラムを対象とするといった変更が可能(な筈)です。

■com2gram.pl

# com2gram.pl
# 引数にテキストファイル名(1個)を指定して実行
# 結果は $resultfilename ("D:\temp\com2gram-result.txt") に出力される

use strict;
use utf8;
use Encode;

# 結果出力ファイルをフルパスで指定(UTF8の想定)
my $resultfilename = "D:\\temp\\com2gram-result.txt";

# 第一パラメタは引数となるテキストファイル名(UTF8の想定)
# 内容を配列@comlistに読み込む
my $file = shift;
open(IN, "<:utf8","$file") || die("cannot open $file\n");
my @comlist = ;
close(IN);
chomp(@comlist);

# 出力ファイルは固定名、utf8指定
open(OUT,">:utf8",$resultfilename); 

print OUT "num\tstring\n";
foreach my $com ( @comlist ) {
  # $j はグラム数を表す
  for( my $j = 1; $j <= 8; $j++ ) {
    # 文字列の先頭から1文字ずつずらして区切って行く
    for( my $i = 0; $i < ( length($com) - ($j-1) ); $i++ ) {
      print OUT $j, "\t", substr($com,$i,$j), "\n";
    }
  }
}
close OUT;

このプログラムを通すと、例えば、最初の一行が以下のように1~8グラムに分割されます。こうやって処理過程でデータ量が何層倍にもなっていくのが醍醐味でしょうか(笑)。

■com2gram-result.txtの先頭(全体は29562行、約462KB)

num	string
1 ニ
1 コ
1 ニ
1 コ
1 に
1 う
1 p
1 さ
1 れ
1 て
1 た
1 ナ
1 ノ
1 ゼ
1 リ
1 ー
1 の
1 動
1 画
1 が
1 最
1 高
1 に
1 面
1 白
1 か
1 っ
1 た
2 ニコ
2 コニ
2 ニコ
2 コに
2 にう
2 うp
2 pさ
2 され
2 れて
2 てた
2 たナ
2 ナノ
2 ノゼ
2 ゼリ
2 リー
2 ーの
2 の動
2 動画
2 画が
2 が最
2 最高
2 高に
2 に面
2 面白
2 白か
2 かっ
2 った
3 ニコニ
3 コニコ
3 ニコに
3 コにう
3 にうp
3 うpさ
3 pされ
3 されて
3 れてた
3 てたナ
3 たナノ
3 ナノゼ
3 ノゼリ
3 ゼリー
3 リーの
3 ーの動
3 の動画
3 動画が
3 画が最
3 が最高
3 最高に
3 高に面
3 に面白
3 面白か
3 白かっ
3 かった
4 ニコニコ
4 コニコに
4 ニコにう
4 コにうp
4 にうpさ
4 うpされ
4 pされて
4 されてた
4 れてたナ
4 てたナノ
4 たナノゼ
4 ナノゼリ
4 ノゼリー
4 ゼリーの
4 リーの動
4 ーの動画
4 の動画が
4 動画が最
4 画が最高
4 が最高に
4 最高に面
4 高に面白
4 に面白か
4 面白かっ
4 白かった
5 ニコニコに
5 コニコにう
5 ニコにうp
5 コにうpさ
5 にうpされ
5 うpされて
5 pされてた
5 されてたナ
5 れてたナノ
5 てたナノゼ
5 たナノゼリ
5 ナノゼリー
5 ノゼリーの
5 ゼリーの動
5 リーの動画
5 ーの動画が
5 の動画が最
5 動画が最高
5 画が最高に
5 が最高に面
5 最高に面白
5 高に面白か
5 に面白かっ
5 面白かった
6 ニコニコにう
6 コニコにうp
6 ニコにうpさ
6 コにうpされ
6 にうpされて
6 うpされてた
6 pされてたナ
6 されてたナノ
6 れてたナノゼ
6 てたナノゼリ
6 たナノゼリー
6 ナノゼリーの
6 ノゼリーの動
6 ゼリーの動画
6 リーの動画が
6 ーの動画が最
6 の動画が最高
6 動画が最高に
6 画が最高に面
6 が最高に面白
6 最高に面白か
6 高に面白かっ
6 に面白かった
7 ニコニコにうp
7 コニコにうpさ
7 ニコにうpされ
7 コにうpされて
7 にうpされてた
7 うpされてたナ
7 pされてたナノ
7 されてたナノゼ
7 れてたナノゼリ
7 てたナノゼリー
7 たナノゼリーの
7 ナノゼリーの動
7 ノゼリーの動画
7 ゼリーの動画が
7 リーの動画が最
7 ーの動画が最高
7 の動画が最高に
7 動画が最高に面
7 画が最高に面白
7 が最高に面白か
7 最高に面白かっ
7 高に面白かった
8 ニコニコにうpさ
8 コニコにうpされ
8 ニコにうpされて
8 コにうpされてた
8 にうpされてたナ
8 うpされてたナノ
8 pされてたナノゼ
8 されてたナノゼリ
8 れてたナノゼリー
8 てたナノゼリーの
8 たナノゼリーの動
8 ナノゼリーの動画
8 ノゼリーの動画が
8 ゼリーの動画が最
8 リーの動画が最高
8 ーの動画が最高に
8 の動画が最高に面
8 動画が最高に面白
8 画が最高に面白か
8 が最高に面白かっ
8 最高に面白かった

次は(3)の集計ですが、これには「Interstage Data Effector Standard Edition 体験版」を使います。いつの間にかV9.0からV9.1になっていました。色々とエンハンスされているようですが、私にとってはタブ区切りテキストを読めるようになってくれたのが一番嬉しいですね。相変わらず正式サポートされてないWindowsXP上で動かしてます。
http://software.fujitsu.com/jp/middleware/softlook/interstage/is_dese.html

Analyze.cfgは以下の通り。LogFileやErrFileはデバッグ用なのでどうでも良いのですが、FieldSeparatorは重要です。このFieldSeparatorの指定でタブ区切りテキストを読めるようになります。

■Analyze.cfg

LogFile "D:\temp\analyze.log"
ErrFile "D:\temp\analyzeerr.csv" 10
FieldSeparator "\t"

Anacond.txtは以下の通り。GConditionで集計の切り口となる項目名を指定します。com2gram-result.txtの先頭には、numとstringを項目名とするための先頭行が加えてあります。RConditionで集計値として文字列の出現回数(count)を指定します。

■Anacond.txt

CharacterCode  UTF-8
InFileType     CSV
OutFileType    CSV
MemorySize     1500
GCondition  $num, substr($string,0,10)
RCondition  count($string) count

これで、以下のようなテキストファイルが出力されます。

■com2gram-ana.txt(20142行、約479KB)

"num","substr(string,0,10)","count"
"1"," ",5
"1","%",2
"1","(",6
"1",")",6
"1","0",7
"1","1",4
・・・

上記のcom2gram-ana.txtには、1回しか出現しないような文字列が大量に含まれています。そのため、(4)で頻度10未満のものを切り捨てます。これでテキストファイルの量は約100分の1くらいに縮小できます。以下の定義ファイルを使ってShunSelectを動かします。

■select.cfg

CharacterCode  UTF-8
InFileType     CSV
LogFile "D:\temp\Select.log"
ErrFile "D:\temp\selecterr.csv" 10

■selectcond.txt

1 $count >= 10

最後は(5)のソートです。以下の定義ファイルで、num(文字列長)とcount(頻度)の降順ソートを指定しています。

■sortcond.txt

CharacterCode  UTF-8
InFileType     CSV
OCondition     val($num) DESC, val($count) DESC

以上の結果が以下のテキストファイルとなります。同じ文章らしきものの8グラム文字列が繰り返し現れているのは、この同じ文章を理由として複数回の投票があったからです。逆に言うと、8グラムという長い切片になると、この程度の対象文章量では10回以上出現というハードルを越えられるものは少ないという事です。当たり前ではありますが面白いです。コピペされた文章をある程度自動的に検出できたと言う事もできるでしょう(汎用的に使えるかは別の問題として)。

■com2gram-sort.txt(256行、約5KB)

"num","substr(string,0,10)","count"
"8","会のウンコ攻撃に",12
"8","価学会のウンコ攻",12
"8","創価学会のウンコ",12
"8","学会のウンコ攻撃",12
"8","攻撃に負けないで",12
"8","に負けないで!!",11
"8","ウンコ攻撃に負け",11
"8","コ攻撃に負けない",11
"8","ンコ攻撃に負けな",11
"8","撃に負けないで!",11
"8","のウンコ攻撃に負",10
"7","のウンコ攻撃に",12
"7","会のウンコ攻撃",12
"7","価学会のウンコ",12
"7","創価学会のウン",12
"7","学会のウンコ攻",12
"7","撃に負けないで",12
"7","攻撃に負けない",12
"7","に負けないで!",11
"7","ウンコ攻撃に負",11
"7","コ攻撃に負けな",11
"7","ンコ攻撃に負け",11
"7","負けないで!!",11
"7","wwwwwww",11
"7","ジャーナリスト",10
"6","に負けないで",13
"6","ウンコ攻撃に",13
"6","wwwwww",13
"6","けないで!!",12
"6","のウンコ攻撃",12
"6","会のウンコ攻",12
"6","価学会のウン",12
"6","創価学会のウ",12
"6","学会のウンコ",12
"6","撃に負けない",12
"6","攻撃に負けな",12
"6","コ攻撃に負け",11
"6","ンコ攻撃に負",11
"6","負けないで!",11
"6","ジャーナリス",10
"6","ャーナリスト",10
"5","wwwww",15
"5","に負けない",13
"5","ウンコ攻撃",13
"5","ンコ攻撃に",13
"5","創価学会の",13
"5","攻撃に負け",13
"5","負けないで",13
"5","けないで!",12
"5","ないで!!",12
"5","のウンコ攻",12
"5","会のウンコ",12
"5","価学会のウ",12
"5","学会のウン",12
"5","撃に負けな",12
"5","コ攻撃に負",11
"5","ジャーナリ",10
"5","ャーナリス",10
"5","ーナリスト",10
"4","wwww",17
"4","のウンコ",16
"4","創価学会",15
"4","けないで",14
"4","に負けな",13
"4","ウンコ攻",13
"4","コ攻撃に",13
"4","ンコ攻撃",13
"4","価学会の",13
"4","撃に負け",13
"4","攻撃に負",13
"4","負けない",13
"4","いで!!",12
"4","ないで!",12
"4","会のウン",12
"4","学会のウ",12
"4","ジャーナ",10
"4","ナリスト",10
"4","ャーナリ",10
"4","ーナリス",10
"3","うんこ",86
"3","ウンコ",76
"3","だから",23
"3","www",19
"3","ないで",17
"3","のウン",16
"3","攻撃に",16
"3","に負け",15
"3","ゼリー",15
"3","価学会",15
"3","創価学",15
"3","けない",14
"3","学会の",14
"3","コ攻撃",13
"3","ンコ攻",13
"3","撃に負",13
"3","負けな",13
"3","いで!",12
"3","で!!",12
"3","会のウ",12
"3","nko",10
"3","です。",10
"3","ジャー",10
"3","ナリス",10
"3","ャーナ",10
"3","リスト",10
"3","ーナリ",10
"3","偽うん",10
"2","うん",96
"2","んこ",86
"2","ウン",78
"2","ンコ",77
"2","から",41
"2","ゼリ",30
"2","ない",27
"2","!!",27
"2","って",25
"2","だか",23
"2","です",23
"2","ww",23
"2","いで",20
"2","創価",20
"2","瀬戸",19
"2","リー",17
"2","・・",17
"2","攻撃",17
"2","して",16
"2","のウ",16
"2","学会",16
"2","撃に",16
"2","負け",16
"2","に負",15
"2","会の",15
"2","価学",15
"2","けな",14
"2","す。",14
"2","この",13
"2","コ攻",13
"2","スト",13
"2","リス",13
"2","で!",12
"2","ko",11
"2","った",11
"2","ャー",11
"2","nk",10
"2","un",10
"2","さい",10
"2","した",10
"2","んだ",10
"2","ジャ",10
"2","ナリ",10
"2","ーナ",10
"2","偽う",10
"1","ん",149
"1","の",138
"1","う",129
"1","い",120
"1","こ",120
"1","ン",102
"1","ー",92
"1","!",92
"1","ウ",87
"1","で",85
"1","に",84
"1","コ",84
"1","な",82
"1","か",81
"1","る",72
"1","て",68
"1","は",66
"1","だ",63
"1","ら",63
"1","を",55
"1","し",53
"1","す",52
"1","リ",51
"1","た",49
"1","っ",48
"1","、",44
"1","が",41
"1","も",40
"1","・",39
"1","と",38
"1","w",37
"1","ト",35
"1","。",34
"1","れ",33
"1","け",31
"1","ゼ",31
"1","ま",30
"1","さ",27
"1","よ",27
"1","ち",26
"1","お",25
"1","人",25
"1","り",24
"1","ス",24
"1","く",23
"1","糞",22
"1","き",20
"1","会",20
"1","価",20
"1","創",20
"1","大",20
"1","ナ",19
"1","戸",19
"1","撃",19
"1","瀬",19
"1","ぎ",18
"1","カ",18
"1","ロ",18
"1","あ",17
"1","イ",17
"1","タ",17
"1","偽",17
"1","学",17
"1","攻",17
"1","負",17
"1","k",16
"1","え",16
"1","そ",15
"1","ジ",15
"1","「",14
"1","」",14
"1","ね",14
"1","ャ",14
"1","国",14
"1","政",14
"1","せ",13
"1","党",13
"1","年",13
"1","思",13
"1","日",13
"1","n",12
"1","o",12
"1","ク",12
"1","ブ",12
"1","一",12
"1","右",12
"1","波",12
"1","票",12
"1","電",12
"1","(",12
"1",")",12
"1","u",11
"1","め",11
"1","グ",11
"1","ッ",11
"1","ノ",11
"1","ラ",11
"1","想",11
"1","笑",11
"1","者",11
"1","風",11
"1","ど",10
"1","わ",10

| | コメント (0) | トラックバック (0)

« 2008年12月 | トップページ | 2009年3月 »