テキストマイニング|共起ネットワークの作り方(前処理と注意点)
一緒に出現する語を線で結び、テーマや文脈のまとまりを可視化します。
まずはここだけ(やさしい導入)
- 何をする?: 一緒に現れやすい語を線で結び、テーマのまとまりを可視化
- いつ使う?: レビューの論点把握、FAQ 改善、顧客の“連想”の可視化
- どう読む?: 強い共起=関係が強いとは限らない。頻度や PMI で重み付け
用語ミニ辞典(1 行で)
- 共起: 同じ文や近接ウィンドウ内で一緒に出現
- 共起行列: 語 × 語のカウント表
- PMI/PPMI: 期待よりどれだけ一緒に出るかを測る尺度
最小コード(共起行列 → ネットワーク)
from collections import Counter
import itertools
import networkx as nx
docs = [
['デザイン','使いやすい','満足'],
['価格','高い','性能','十分'],
['配送','早い','満足']
]
pairs = []
for tokens in docs:
for a,b in itertools.combinations(sorted(set(tokens)), 2):
pairs.append((a,b))
cooc = Counter(pairs)
G = nx.Graph()
for (a,b), w in cooc.items():
G.add_edge(a,b, weight=w)
print(G.number_of_nodes(), G.number_of_edges())
実務ケーススタディ(レビューの論点マップ)
目的: アプリレビューから主要論点(不具合、UI、価格、配送など)をマップ化して、優先対応を決める。
- 前処理
- 形態素解析で名詞/形容詞/動詞原形。同義語・表記ゆれを統一
- 共起の作り方
- 文単位/ウィンドウ単位で共起を作成。最低共起回数でノイズ除去
- 重み付けと可視化
- PMI や PPMI で重み付け、中心性(Degree/Betweenness)で重要語を抽出
from collections import Counter
import itertools, math
docs = [
['デザイン','使いやすい','満足'],
['価格','高い','性能','十分'],
['配送','早い','満足']
]
unigram = Counter([t for d in docs for t in set(d)])
pair = Counter()
for tokens in docs:
for a,b in itertools.combinations(sorted(set(tokens)), 2):
pair[(a,b)] += 1
N = len(docs)
def pmi(a,b):
pa = unigram[a]/N; pb = unigram[b]/N; pab = pair[(min(a,b),max(a,b))]/N
return math.log2((pab+1e-9)/(pa*pb))
weights = { (a,b): max(pmi(a,b), 0.0) for (a,b) in pair }
print(weights)
練習問題(理解を定着)
- 頻出の一般語でネットワークが埋まる。どうする?
- ヒント: 最低出現回数/共起閾値を上げ、品詞や辞書でノイズ除去
- 共起が強いが意味的に関係が弱い語が混ざる。対策は?
- ヒント: PMI/PPMI 重み、文脈ベクトル(word2vec/BERT)でフィルタ
- 可視化が複雑で読めない。どう改善?
- ヒント: サブグラフ抽出、コミュニティ検出(Louvain)でまとまりを表示
注意点
- 固有表現の統一、語の正規化(表記ゆれ)
- ウィンドウ幅や文単位で共起の定義が変わる
- 頻出語の除去でノイズ低減、重み付け(PMI など)で重要共起を強調
関連と次の一歩
よくある質問(FAQ)
- Q: ノイズが多くてネットワークが読めない
- A: 最低出現回数・共起閾値を上げ、品詞や辞書を見直す
- Q: 重要語が埋もれる
- A: PMI/PPMI など重み付けや中心性指標で抽出
テキストマイニング・共起分析についてのご相談はこちら