Pythonですばやくクロス集計してヒートマップつくるにはどうしたらいいかな?
目次
こんなことを書くよ
Pythonだけでクロス集計とヒートマップを表示したいんや
ただ単に「クロス集計したい」というだけならば、ExcelかGoogle Spreadsheetを使うのが最速だと思う。
クリックだけで終わる。これにまさる簡単さはない。
でも、「Pythonでクロス集計を完結させたい」というときもある。
たとえば、Jupyter Notebookで分析ノートを作っている時。
いちいちcsvに書き出して、Excelでクロス集計して、Pythonで読み込んで・・・なんてめんどいことする?しないでしょ!
で、調べてみた。
例えば、今回はアノテーション結果の「ラベル」があって、この「ラベル」を集計したい場合(自然言語処理の話ばっかりになるな、このブログ)
クロス集計処理
pandasでおしまい。
まずは、こんな感じのテーブルを作る
文書ID | ラベル |
000000001 | label-name |
上の記事ではちがうデータ・タイプを2種類のクロス集計するときの話をしている。
でも、アノテーション結果のラベル集計になると、「ラベルA」と「ラベルB」の共起頻度みたいな集計をしたい(要するに、共起頻度行列を作りたい)
こういうときは、1軸の頻度カウントするクロス集計操作をすればいい。
1 2 |
import pandas as pd pd.pivot_table(df, values="", index="[ラベル列名]", columns="[ラベル列名]", aggfunc=len) |
Stackover flowにも似たような質問が出てる。
(違うパターン)いやいや、共起頻度を文書数でカウントしたいねん
言語処理やっていると、「ラベルそのものの共起頻度ではなくて、共起が発生した文書数を知りたいねん」というニーズもあったりする。
つまり、カウントの基準が「ラベルの共起」ではなくて「文書内でラベルが共起したら+1」になる。
言語処理には、1データがめっちゃ長いことがある。そういうときには、1文書内に同じラベルが頻出することもある。
一方、分析の観点では「入力文書のうち、どれくらいの文書でこの共起が起きるのか?」を知りたいこともある。
こういう時に、この集計は必要。
で、どうするかというと、pandasに頼るよりも、自分で集計処理を書いてしまったほうが早い(と思う)
3重ループを使ったうんこードを置いておきますね〜。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from collections import OrderedDict def generate_occurence_matrix(names, document): occurrences = OrderedDict((name, OrderedDict((name, 0) for name in names)) for name in names) # Find the co-occurrences: for l in document: for i in range(len(l)): for item in l[:i] + l[i + 1:]: occurrences[l[i]][item] += 1 return occurrences __document = [['A', 'B'], ['C', 'B'], ['A', 'B', 'C', 'D']] __names = ['A', 'B', 'C', 'D'] test_matrix = generate_occurence_matrix(__names, __document) |
ヒートマップ作成
pandas.Dataframeからヒートマップは簡単に実現できる。on Stackover flow
でも、このままではちょっと不都合。
1軸のクロス集計してしまっているので、対角要素の数が多くなってしまう(当たり前)
これでは、うまくヒートマックが機能しないので、対角要素を消す(つまり、三角行列化する)やり方
これとpandas.Dataframeの入力を組み合わせるとこんな感じ。
1 2 3 4 5 6 |
__df = pandas.DataFrame(np.triu(df, k=1), index=df.index, columns=df.columns) __df = pandas.DataFrame(np.triu(df, k=1), index=df.index, columns=df.columns) plt.pcolor(__df) plt.yticks(np.arange(0.5, len(__df.index), 1), __df.index) plt.xticks(np.arange(0.5, len(__df.columns), 1), __df.columns) plt.show() |
__dfが三角行列化された状態のデータフレームになってる。
共起頻度を文書数でカウントした場合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from collections import OrderedDict def generate_occurence_matrix(names, document): occurrences = OrderedDict((name, OrderedDict((name, 0) for name in names)) for name in names) # Find the co-occurrences: for l in document: for i in range(len(l)): for item in l[:i] + l[i + 1:]: occurrences[l[i]][item] += 1 return occurrences __document = [['A', 'B'], ['C', 'B'], ['A', 'B', 'C', 'D']] __names = ['A', 'B', 'C', 'D'] test_matrix = generate_occurence_matrix(__names, __document) df = pandas.DataFrame(test_matrix) __df = pandas.DataFrame(np.triu(df, k=1), index=df.index, columns=df.columns) plt.pcolor(__df) plt.yticks(np.arange(0.5, len(__df.index), 1), __df.index) plt.xticks(np.arange(0.5, len(__df.columns), 1), __df.columns) plt.show() |
ディスカッション
コメント一覧
まだ、コメントがありません