mai_Nのプログラミング勉強メモ

Python or R × マーケティング

Janomeを使った形態素解析④

※使用したデータ:カップヌードルミュージアムの口コミ500件
じゃらんの口コミをスクレイピングで取得したもの。 )

■Jaccard係数を計算する

まずはレビューごとのtermリストのリスト(つまり二次元リスト)を作る
terms_list= []

from janome.tokenizer import Tokenizer
t = Tokenizer()
for i in range(500):
    text = DF['本文'][i]
    terms = []
    token_list = t.tokenize(text)
    for token in token_list:
        if token.part_of_speech.split(',')[0] in ['名詞']: #品詞は名詞に限定
            terms.append(token.base_form)
    terms_list.append(terms)


次に頻出termのみ抽出してtermの組み合わせリストを作る
from collections import defaultdict
term_freq = defaultdict(lambda: 0)
for term in sum(terms_list, []):
    term_freq[term] += 1
term_freq_sort = sorted(term_freq.items(), key=lambda x:x[1], reverse=True)
term_freq_20 = term_freq_sort[:20] #ここで頻出単語Top20にした
term_uni = [tupple[0] for tupple in term_freq_20]
term_combis = list(itertools.combinations(term_uni, 2))


Jaccard係数を計算する
def Jaccard(x,y,terms_list): #x,y=2つのterm
    seki = sum(((x in terms) & (y in terms)) for terms in terms_list)
    wa = sum(((x in terms) or (y in terms)) for terms in terms_list)
    return seki/wa

Jaccard_list = []
for term_combi in term_combis:
    data = dict(term1=term_combi[0], term2=term_combi[1], Jaccard=Jaccard(term_combi[0], term_combi[1], terms_list))
    Jaccard_list.append(data)


termの組み合わせとJaccard係数をまとめたデータフレームを作る
import pandas as pd
DF_Jaccard = pd.DataFrame(Jaccard_list)
DF_Jaccard = DF_Jaccard.sort_values(by='Jaccard', ascending=False).reset_index()[:30] 
 #Jaccard係数が大きい順に並べ替えてTop30を抽出

f:id:ma__i:20210727165754p:plain


■ NetworkXで描画する

import networkx as nx
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline

DF = DF_Jaccard

term_combi = [(DF['term1'][i], DF['term2'][i]) for i in range(len(DF))]
G = nx.Graph()
G.add_edges_from(term_combi)
G.remove_nodes_from(['ラーメン', '体験', '大人', 'チキン']) #適宜ノードやエッジを削除して見た目をよくする

width = DF['Jaccard']*10
node_size = [term_freq[term]*7 for term in G.nodes]
pos = nx.spring_layout(G, k=0.5) #エッジの大きさによる吸引力でノードの位置を決定する(kの値が大きいと全体的に丸くなる)

nx.draw(G, pos, with_labels=True, font_family='IPAexGothic', width=width, node_size=node_size,\
        node_color='skyblue',alpha=0.6, edge_color='gray')

f:id:ma__i:20210727170303p:plain

■おまけ:pyfpgrowthを使った組み合わせパターンの抽出

import pyfpgrowth
kyoki = pyfpgrowth.find_frequent_patterns(wakati_list1, 30) #頻度の高い組み合わせを抽出。「30回以上」と指定。
pair = []
for kyoki_set in kyoki.items():
    if len(kyoki_set[0]) == 2:  #2つの単語の組み合わせのみ抽出し、単語3つ以上の組み合わせは除く。
        pair.append(kyoki_set)
sorted_pair = sorted(pair, key=lambda x:x[1], reverse=True) #出現頻度で並び替え
sorted_pair_30 = sorted_pair[:30] #Top30を抽出
sorted_pair_30

[(('カップ', 'ヌードル'), 636),
(('する', 'カップ'), 274),
(('できる', 'カップ'), 244),
(('オリジナル', 'ヌードル'), 228),
(('こと', 'できる'), 228),
(('いる', 'する'), 193),
(('カップ', '作る'), 180),
(('ある', 'カップ'), 177),
(('カップ', '自分'), 161),
(('カップ', '楽しい'), 140),
(('カップ', '作れる'), 132),
(('ヌードル', '歴史'), 131),
(('ヌードル', 'ヌードル'), 127),
(('カップ', 'カップ'), 127),
(('する', 'ラーメン'), 125),
(('する', 'の'), 118),
(('カップ', '楽しめる'), 117),
(('の', 'カップ'), 110),
(('する', '体験'), 98),
(('なる', 'カップ'), 94),
(('する', 'れる'), 89),
(('カップ', '子供'), 84),
(('ヌードル', '子供'), 80),
(('する', 'カップラーメン'), 79),
(('カップ', '具'), 76),
(('カップ', '食べる'), 76),
(('ヌードル', '食べる'), 73),
(('する', '行く'), 73),
(('カップ', 'ラーメン'), 73),
(('する', 'チキン'), 71)]