Pythonのjanomeで形態素解析したデータをパレート図にして頻出ワードを調べる方法

2020年9月1日

今日は、形態素解析したデータをパレート図にして頻出ワードを調べる方法を紹介します。

形態素解析の方法は過去の記事を参考にしてください。

このページで分かること

1.pandasでcsvファイルを開く方法
2.パレート図の作成方法

pandasでcsvファイルを開く方法

以下のソースコードを見てください。

import pandas as pd
# csvデータの読み込み(encodingに注意, デフォルトはutf-8, その他は cp932, shift_jis)
df = pd.read_csv('./janome/output_2.csv', header=None, encoding='cp932')
print(df)
# loc[行、列]でデータ読み込み。
x0 = df.loc[:, 0]  # 全行の0列の値を読み込む
y0 = df.loc[:, 1]  # 全行の1列の値を読み込む

最初に pandas を import してください。

次に、pd.read_csv( ) で 所定のフォルダに入っている csv ファイルを読み込んでください。

カッコの中の第一引数は、csv ファイルが置いてあるパスです。

第二引数に header = None と書くことで、読み込んだ csv データの列の頭にインデックス(0や1など)が自動で付きます。

表示例

   0    1 ← インデックス
0  カメラ   85
1  フィルム  27
2  写真    18

第三引数は、csv データを読み込む際にどんなルールで読み込むかを指定するものです。

これはデータの種類に依ります。ソースコードの注記にも書いたように、通常の日本語テキストなら utf-8 でよいと思います。もし、うまく文字が表示されなかったりエラーが出るようなら、cp932 や shift_jis で試してください。

次に、パレート図を作成するに当たり、x軸用とy軸用にデータを分けておきます。

pandasで読み込んだデータを分ける際は、df.loc[ ] を使います。

これにより、x0 には全行のインデックス0番目のデータが代入されます。

同様に y0 には全行のインデックス1番目のデータが代入されます。

代入例

x0= 0  カメラ
  1  フィルム
  2  写真

y0= 0  85
  1  27
  2  18

続いて、パレート図の作成方法について説明します。

パレート図の作成方法

以下のソースコードを見てください。

import numpy as np
import matplotlib.pyplot as plt
# x軸ラベルが日本語でも文字化けしないように設定
import japanize_matplotlib
# パレート図作成の準備
# np.cumsumは配列内の要素を足し合わせていったものを順次配列に記録していく
y1 = np.cumsum(y0)
# 先ほどのy1の各値をy0の総数で割って100を掛けたもの(パーセント)にしてリスト化(内包表記)
y2 = [y1[i]/sum(y0)*100 for i in range(len(y0))]
print('y1=', y1)
print('y2=', y2)
# グラフの定義
fig, ax_1 = plt.subplots(figsize=(16, 9))
# 1軸目のy軸の範囲を指定
ax_1.set_ylim([0, np.amax(y0)+5])
# 1軸目のy軸のラベルとタイトルを指定
ax_1.set_ylabel('counts', size=15)
ax_1.set_title('Pareto chart', size=20)
# x軸の文字の向きを調整(今は90度回転)
plt.xticks(rotation=90)
# グラフを2軸表示とする
ax_2 = ax_1.twinx()
# 2軸目のy軸の範囲を指定
ax_2.set_ylim([0, 100])
# 2軸目のy軸の目盛りを指定
ax_2.set_yticks(np.arange(0, 100+1, 10))
# 2軸目のy軸のラベルを作成して指定
percent_labels = [str(i) + "%" for i in np.arange(0, 100+1, 10)]
ax_2.set_yticklabels(percent_labels)
# 2軸目のグリッド線を指定
ax_2.grid(True, which='both', axis='y')
# グラフを描画
# 1軸目は棒グラフ、2軸目はプロットグラフ
ax_1.bar(x0, y0, label='bar')
ax_2.plot(x0, y2, 'rp-', linewidth=3, markersize=10, label='line')
# 凡例を表示(必要に応じて)
#ax_1.legend(fontsize=15)
# グラフを保存
fig.savefig('./janome/plot/results.png')
plt.show()

ソースコードの意味を順に説明します。

必要なパッケージのインポート

最初に numpy と matplotlib.pyplot と japanize_matplotlib を import してください。

ここでのポイントは、japanize_matplotlib を importすることです。

理由は、matplotlib で日本語を表示させるためです。これを import しておかないと文字化けします。

要素の累積記録

要素の累積記録には、np.cumsum( ) を使います。

これを使うと、配列内の要素を足し合わせていったものを順番に配列に記録することができます。

例えば、y1 = np.cumsum(y0) とすると y1 に記録される値は以下となります。

要素の累積記録の例

y1= 0  85
  1  112 ← 85+27
  2  130 ← 112+18

y軸(2軸目)の値を計算

以下のソースコードでy軸(2軸目)の値を計算します。

y2 = [y1[i]/sum(y0)*100 for i in range(len(y0))]

y2 は内包表記となっており、処理内容は以下と同じです。

y2 = []
for i in range(len(y0)):
   y2.append(y1[i]/sum(y0)*100)

違うのは処理速度です。内包表記の方がかなり早いためこちらを採用しています。

実行するとy2には以下のような値が代入されます。

y2= [18.398268398268396, 24.242424242424242, 28.13852813852814, ・・・]

これは、先ほどのy1の各値をy0の総数で割って100を掛けたもの(パーセント)にしてリスト化したものです。

ちなみに、y2リストの一番最後の値は100.0になります。

グラフ作成の準備

ポイントのみ説明します。

グラフを2軸表示とするため以下のコードを記載します。

# グラフを2軸表示とする
ax_2 = ax_1.twinx()

2軸目のy軸ラベルを作成

内包表記でラベルを作成します。

作成したラベルを ax_2.set_yticklabels( ) でセットします。

# 2軸目のy軸のラベルを作成して指定
percent_labels = [str(i) + "%" for i in np.arange(0, 100+1, 10)]
ax_2.set_yticklabels(percent_labels)

グラフの保存

fig.savefig( ) で作成したグラフを指定したパスのフォルダ内に保存します。

# グラフを保存
fig.savefig('./janome/plot/results.png')

ソースコード全体

全体のソースコードを示します。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# x軸ラベルが日本語でも文字化けしないように設定
import japanize_matplotlib
# csvデータの読み込み(encodingに注意, デフォルトはutf-8, その他は cp932, shift_jis)
df = pd.read_csv('./janome/output_2.csv', header=None, encoding='cp932')
print(df)
# loc[行、列]でデータ読み込み。
x0 = df.loc[:, 0]  # 全行の0列の値を読み込む
y0 = df.loc[:, 1]  # 全行の1列の値を読み込む
# パレート図作成の準備
# np.cumsumは配列内の要素を足し合わせていったものを順次配列に記録していく
y1 = np.cumsum(y0)
# 先ほどのy1の各値をy0の総数で割って100を掛けたもの(パーセント)にしてリスト化(内包表記)
y2 = [y1[i]/sum(y0)*100 for i in range(len(y0))]
print('y1=', y1)
print('y2=', y2)
# グラフの定義
fig, ax_1 = plt.subplots(figsize=(16, 9))
# 1軸目のy軸の範囲を指定
ax_1.set_ylim([0, np.amax(y0)+5])
# 1軸目のy軸のラベルとタイトルを指定
ax_1.set_ylabel('counts', size=15)
ax_1.set_title('Pareto chart', size=20)
# x軸の文字の向きを調整(今は90度回転)
plt.xticks(rotation=90)
# グラフを2軸表示とする
ax_2 = ax_1.twinx()
# 2軸目のy軸の範囲を指定
ax_2.set_ylim([0, 100])
# 2軸目のy軸の目盛りを指定
ax_2.set_yticks(np.arange(0, 100+1, 10))
# 2軸目のy軸のラベルを作成して指定
percent_labels = [str(i) + "%" for i in np.arange(0, 100+1, 10)]
ax_2.set_yticklabels(percent_labels)
# 2軸目のグリッド線を指定
ax_2.grid(True, which='both', axis='y')
# グラフを描画
# 1軸目は棒グラフ、2軸目はプロットグラフ
ax_1.bar(x0, y0, label='bar')
ax_2.plot(x0, y2, 'rp-', linewidth=3, markersize=10, label='line')
# 凡例を表示(必要に応じて)
#ax_1.legend(fontsize=15)
# グラフを保存
fig.savefig('./janome/plot/results.png')
plt.show()

実行結果

wikipedia で 最近流行りの「鬼滅の刃」を検索し、概要の部分をコピーしてテキストファイルを作成しました。

これを過去の記事で紹介したjanomeを使った形態素解析で名詞数を数えcsvファイル化し、今回のプログラムでパレート図を作成しました。

頻出ワードは「鬼」のようです。そりゃそうだ。

次に、「大正」「時代」と続き「ジャンプ」「舞台」「主人公」「敵」「人間」と続きます。

つまり、鬼が敵で主人公の人間が大正時代を舞台にして戦う話だと推測できます。

またジャンプに掲載されている少年漫画だと推測できます。

このように、頻出ワードを調べるだけでどのような内容なのか大まかな推測が可能になります。

使い方によっては結構使えそうです。

まとめ

  • 形態素解析で名詞をカウントし、パレート図にすることで頻出ワードを調べることができる
  • 頻出ワードを調べることで、テキスト内容を大まかに推測できる