ギークなエンジニアを目指す男

機械学習系の知識を蓄えようとするブログ

自然言語を簡単に可視化・分析できるライブラリ「nlplot」を公開しました

こんにちは。たかぱい(@takapy0210)です。

本日は自然言語の可視化を手軽にできるようにしたパッケージnlplotをPyPIに公開したので、これのご紹介です。

nlplotとは?

自然言語の基本的な可視化を手軽にできるようにしたパッケージです。

現在は日本語と英語で動作確認済みです。
基本的な描画はplotlyを用いているため、notebook上からインタラクティブにグラフを操作することができます。

github.com (スター★お待ちしております🙇‍♂️)

pypi.org

nlplotで何ができるか

現時点(ver 1.6.0)では下記のグラフをプロットできます。(リンク先で動的なグラフを表示できます)

以降で簡単に使い方をご紹介します。

使い方

詳しい使用方法のコード・今回使用したデータはGithubにあげてあります。
また、Tweet Sentiment Extractionコンペのカーネルも公開しておきました。

使用データ

今回は、Twitterからハッシュタグ「#kaggle」と「#データサイエンティスト」がついているツイートをスクレイピングし、そのタグを分析してみました。

データの形式は下記のようなデータフレームを想定しています。
textのカラムはスペース区切りの文字列 or リスト型のカラムを想定しています。

日本語の場合はお好きな形態素解析器で事前にtokenizeをお願いします。
(このパッケージにtokenizerも含めるか迷いましたが、あくまで可視化のみを責務としているので、含めていません)

searched_for hashtags
0 #データサイエンティスト データマイニング データサイエンス データサイエンティスト
1 #データサイエンティスト 統計学 人工知能 ダイヤモンド データサイエンティスト プログラミング
2 #データサイエンティスト 筋トレ 今日の積み上げ 駆け出しエンジニアと繋がりたい データサイエンティスト
... ... ...
N #kaggle python kaggle タイタニック

事前準備

インストールはpipで可能です。

pip install nlplot

事前にデータを読み込み、nlplotのインスタンスを生成しておきます。

import nlplot
import pandas as pd
import plotly
from plotly.subplots import make_subplots
from plotly.offline import iplot
import matplotlib.pyplot as plt
%matplotlib inline

df = pd.read_csv('sample_twitter.csv')

# 全データ・#データサイエンティスト・#kaggleをそれぞれインスタンス化
npt = nlplot.NLPlot(df, target_col='hashtags')
npt_ds = nlplot.NLPlot(df.query('searched_for == "#データサイエンティスト"'), target_col='hashtags')
npt_kaggle = nlplot.NLPlot(df.query('searched_for == "#kaggle"'), target_col='hashtags')

ストップワードの計算

下記のようにストップワードの計算ができます。

# top_nで頻出上位単語, min_freqで頻出下位単語を指定できる
# 今回は上位2単語(データサイエンティスト・kaggle)をストップワードに指定
stopwords = npt.get_stopword(top_n=2, min_freq=0)

N-gram bar chart

よく見聞きするアレです。

ngramの引数に与える数値により、いくつ隣り合わせの単語までを考慮するかを指定できます。

fig_unigram = npt.bar_ngram(
    title='uni-gram',
    xaxis_label='word_count',
    yaxis_label='word',
    ngram=1,
    top_n=50,
    width=800,
    height=1100,
    color=None,
    horizon=True,
    stopwords=stopwords,
    verbose=False,
    save=False,
)
fig_unigram.show()

下記のようにすることで、データをラベルごとに比較することもできます。

# #データサイエンティストのfigを取得
fig_unigram_ds = npt_ds.bar_ngram(
    title='uni-gram',
    xaxis_label='word_count',
    yaxis_label='word',
    ngram=1,
    top_n=50,
    stopwords=stopwords,
)

# #kaggleのfigを取得
fig_unigram_kaggle = npt_kaggle.bar_ngram(
    title='uni-gram',
    xaxis_label='word_count',
    yaxis_label='word',
    ngram=1,
    top_n=50,
    stopwords=stopwords,
)

# subplot
trace1 = fig_unigram_ds['data'][0]
trace2 = fig_unigram_kaggle['data'][0]

fig = make_subplots(rows=1, cols=2, subplot_titles=('#データサイエンティスト', '#kaggle'), shared_xaxes=False)
fig.update_xaxes(title_text='word count', row=1, col=1)
fig.update_xaxes(title_text='word count', row=1, col=2)

fig.update_layout(height=1100, width=1900, title_text='unigram #データサイエンティスト vs. #kaggle')
fig.add_trace(trace1, row=1, col=1)
fig.add_trace(trace2, row=1, col=2)

plotly.offline.plot(fig, filename='unigram #データサイエンティストvs#kaggle.html', auto_open=False)

fig.show()

以降のグラフも上記のようにコーディングすることで、特定のラベルごとに比較することができます。

N-gram tree Map

こちらも同様、ngramの引数に与える数値により、いくつ隣り合わせの単語までを考慮するかを指定できます。

fig_treemap = npt.treemap(
    title='Tree map',
    ngram=1,
    top_n=50,
    width=1300,
    height=600,
    stopwords=stopwords,
    verbose=False,
    save=False
)
fig_treemap.show()

Histogram of the word count

単語の出現頻度のヒストグラムです。

# 単語数の分布
fig_histgram = npt.word_distribution(
    title='word distribution',
    xaxis_label='count',
    yaxis_label='',
    width=1000,
    height=500,
    color=None,
    template='plotly',
    bins=None,
    save=False,
)
fig_histgram.show()

wordcloud

みんな大好きwordcloudです。日本語でもそのままプロットできます。

fig_wc = npt.wordcloud(
    width=1000,
    height=600,
    max_words=100,
    max_font_size=100,
    colormap='tab20_r',
    stopwords=stopwords,
    mask_file=None,
    save=False
)
plt.figure(figsize=(15, 25))
plt.imshow(fig_wc, interpolation="bilinear")
plt.axis("off")
plt.show()

co-occurrence networks

共起ネットワークです。

このネットワークとサンバーストチャートを描画する場合は、事前にビルド処理が必要です。
このビルド処理のmin_edge_frequency引数でプロットするノードの数を制限します。
(指定数以下のエッジ(辺)しか存在しないノードはプロット対象から除外することができます)

# ビルド(データ件数によっては処理に時間を要します)
npt.build_graph(stopwords=stopwords, min_edge_frequency=25)

# ビルド後にノードとエッジの数が表示される。ノードの数が100前後になるようにするとネットワークが綺麗に描画できる
>> node_size:63, edge_size:63

fig_co_network = npt.co_network(
    title='Co-occurrence network',
    sizing=100,
    node_size='adjacency_frequency',
    color_palette='hls',
    width=1100,
    height=700,
    save=False
)
iplot(fig_co_network)

ノードの色は、networkxのcommunitiesで計算したコミュニティを表しています。
networkx.github.io

ノードの大きさは、networkxのGraph.adjacencyで算出した値の大きさに比例しています。(隣接エッジが多ければ多いほど大きくなります) networkx.github.io

ちなみにビルド処理で生成されたデータフレーム にもアクセスできます。

display(
    npt.node_df.head(), npt.node_df.shape,
    npt.edge_df.head(), npt.edge_df.shape
)

sunburst chart

上記共起ネットワークのコミュニティと、それに属する単語をサンバーストチャートで表示しています。

fig_sunburst = npt.sunburst(
    title='sunburst chart',
    colorscale=True,
    color_continuous_scale='Oryel',
    width=1000,
    height=800,
    save=False
)
fig_sunburst.show()

色の濃さはnetworkxのbetweenness_centralityで算出した値が大きいほど濃い色で表示されています。(ネットワークの媒介中心性が高ければ高いほど濃い色になります)
幅は、前述したnetworkxのGraph.adjacencyで算出した値に比例しています。(隣接エッジが多ければ多いほど大きくなります)

networkx.github.io

まとめ

不便な部分はどんどん更新していこうと思っていますので、気になる部分や要望などあれば、PR/ISSUEお待ちしております!

業務でもKaggleなどのコンペでも短時間でデータの全体像を把握したい時に使っていただければと思います。