1
0

More than 3 years have passed since last update.

日本語プログラミング言語「プロデル」でZipfの法則のグラフを描く

Last updated at Posted at 2019-12-08

はじめに

自然言語処理・情報検索界で最も有名なのがZipf's Lawですが,これは,どんなテキストでやっても同様の傾向が見られるはずなので,日本語text8を使ってやってみます。

実装

前処理

Zipfの法則では,別に単語に分割する必要はないのですが,text8は既にスペース区切りになっているので,これをそのまま利用します。プロデルにsplit相当の手順はないので,以前実装したものがありますが,なんとこれがとても遅い。全部で何語あるかというと,

nipo@nipo:~$ wc ja.text8
        0  16900732 100000347 ja.text8
nipo@nipo:~$ 

1690万語です。コンパイルしても非常に遅くなります。原因は恐らく,区切り文字が出現する都度配列に追加しているからです。内部のデータ構造がどうなっているか知りませんが,配列の大きさが変わる場合,全てのデータ+追加したデータをメモリの別の場所に移すはずなので,これを1600万回もやっていたらどんどん遅くなるでしょう。

今回は,別に単語を配列に入れる必要がないので,1語ごとに辞書に出現回数をカウントしていくことにします。よって,次のような,アクセスする度に次の単語を返す手順を持つ種類を書きました。

文字列操作.rdr
文字列分割器とは
    【分割対象:文字列】は,「」。
    【前回位置:整数】は,0。
    【今回位置:整数】は,1。
    はじめ(対象)の手順
        分割対象は,対象。
    終わり
    自分を【区切り文字:文字列】で分割する手順
        繰り返す
            もし今回位置が分割対象の文字数より大きいなら
                「」を返す
            もし終わり
            もし今回位置が分割対象の文字数なら
                今回位置は,今回位置+1。
                分割対象の[前回位置+1]文字目以降を返す。
            もし終わり
            もし分割対象の[今回位置]文字目が区切り文字なら
                【結果】は,分割対象の[前回位置+1]文字目から[今回位置-前回位置-1]文字取り出したもの。
                前回位置は,今回位置。
                今回位置は,今回位置+1。
                結果を返す。
            でないなら
                今回位置は,今回位置+1。
            もし終わり
        繰り返し終わり
    終わり
終わり

これを使って,良い感じに辞書に頻度を数え上げていきます。

「文字列操作.rdr」を参照する。
「行列.rdr」を参照する。
「グラフ描画.rdr」を参照する。
「色.rdr」を参照する。
「Produire.WinControl.dll」を利用する。
「Produire.PGraphics.dll」を利用する。

コーパスという文字列分割器(「ja.text8」から読み込んだもの)を作る。
【頻度:辞書】。
繰り返す
    単語は,コーパスを「 」で分割したもの。
    もし単語が「」なら
        繰り返しから抜ける
    もし終わり
    もし頻度が無なら,頻度(「_[単語]」)は,0。
    頻度(「_[単語]」)は,頻度(「_[単語]」)+1。
繰り返し終わり

データを並べ替える

サイズを指定しない場合さっきと同じことが起こるので,サイズを指定して配列を作りたいのですが,これには固定長配列という種類を用います。しかし,この固定長配列は並び替え手順が実装されていません(マニュアルには書いてある)。

また,コンパイルすると,配列の要素へのアクセスが非常に難しくなるので,注意します。

【頻度一覧:整数の配列(頻度の個数)】は,固定長配列(頻度の個数)を作ったもの。
カウンタは,1。
限界は,頻度一覧の個数。
頻度の見出しを【キー】へそれぞれ繰り返す
    もしカウンタが限界未満なら
        頻度一覧(カウンタ)は,頻度(キー)。
    もし終わり
    カウンタは,カウンタ+1。
繰り返し終わり

さて,これで頻度一覧に頻度の値が全て入ったので,大きい順に並べ替えます。

頻度一覧を大きい順に並び替える

これはエラーです。固定長配列には並び替えの手順が実装されていません。そこで,配列を経由します。

【頻度降順:配列】は,{}。
頻度降順は,頻度一覧のクローン。
頻度降順を大きい順に並び替える。

これで準備ができました。

描画

今回は,20000を超えるデータ数があり,プロットしても何も見えないので,上位600個に限ります。

データという行列(1,600)を作る。
データの中身(1)は,頻度降順の1番目から600個切り出したもの。

グラフというグラフ(600,600)を作る。
グラフにデータで折れ線グラフを描く。
グラフを表示。
待機。

image.png

おお~!!Zipfみがありますね!!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0