Google Search Console の
結論を
以下は、TfidfVectorizer
で
共起ネットワーク図に ついて
共起語に
共起語SEOを
例えば、python
だったらdjango
とかflask
文書上一緒に
この
一般的に、
これは、
処理の 流れ
実装は
キーワード文字列を
取得
Google Search Console からキーワードを 取得します。
キーワードのデータは、 Search Analytics for Sheets - Google スプレッドシート アドオン を 使って 取得、 スプレッドシートの 取得には、 gspread
を使っています。 共起単語行列を
作成する
キーワードをINPUTに、 共起単語行列を 作成します。
sklearn
のCountVectorizer と、 TfidfVectorizer を 使った 処理を 作成しました。 networkx で、
ネットワーク図を 描画
networkx
を使って、 ネットワーク図を 描画します。
前提
python の verison
% python -V Python 2.7.10
必要な ライブラリの インストール
スクリプトを
実行する
pip install networkx pip install matplotlib pip install sklearn
実装
以下作成した
2ファイルです。
search_console_plot_keyword_network.py
# -*- coding: utf-8 - import networkx as nx import matplotlib.pyplot as plt import search_console_classifier_utils as utils def __create_keywords_data(): keywords = [] # CSVからキーワードを取得 for line in utils.parse_report_tsv(): keywords.append(line) return keywords def __get_co_occurrence_matrix_from(keywords): # ----------------------------------------------------- # 以下、CountVectorizer で共起単語行列を作る # ---------------------------------- # from sklearn.feature_extraction.text import CountVectorizer # count_model = CountVectorizer(ngram_range=( # 1, 1), stop_words=utils.stop_words) # default unigram model # X = count_model.fit_transform(keywords) # # normalized co-occurence matrix # import scipy.sparse as sp # Xc = (X.T * X) # g = sp.diags(2. / Xc.diagonal()) # Xc_norm = g * Xc # import collections # splited_keywords = [] # for keyword in keywords: # splited_keywords.extend(utils.split_keyword(keyword)) # counter = collections.Counter(splited_keywords) # return Xc_norm, count_model.vocabulary_, counter # ----------------------------------------------------- # 以下、TfidfVectorizer で共起単語行列を作る # ---------------------------------- from sklearn.feature_extraction.text import TfidfVectorizer tfidf_vectorizer = TfidfVectorizer(ngram_range=( 1, 1), stop_words=utils.stop_words, max_df=0.5, min_df=1, max_features=3000, norm='l2') X = tfidf_vectorizer.fit_transform(keywords) # normalized co-occurence matrix import scipy.sparse as sp Xc = (X.T * X) g = sp.diags(2. / Xc.diagonal()) Xc_norm = g * Xc import collections splited_keywords = [] for keyword in keywords: splited_keywords.extend(utils.split_keyword(keyword)) counter = collections.Counter(splited_keywords) return Xc_norm, tfidf_vectorizer.vocabulary_, counter def main(): # ------------------------- # 1. キーワード文字列を取得 # ------------------------- keywords = __create_keywords_data() # ------------------------- # 2. 共起単語行列を作成する # ------------------------- Xc_norm, vocabulary, counter = __get_co_occurrence_matrix_from(keywords) # ------------------------- # 3. networkx で、ネットワーク図を描画 # ------------------------- # 3-1.初期ノードの追加 G = nx.from_scipy_sparse_matrix( Xc_norm, parallel_edges=True, create_using=nx.DiGraph(), edge_attribute='weight') # 3-2.nodeに、count にcount属性を設定 value_key_dict = {} for key, value in vocabulary.items(): count = counter.get(key, 0) nx.set_node_attributes(G, "count", {value: count}) value_key_dict.update({value: key}) # 3-3.エッジと、ノードの削除 # 出現回数の少ないエッジを削除 for (u, v, d) in G.edges(data=True): if d["weight"] <= 0.15: G.remove_edge(u, v) # 出現回数の少ないノードを除去 for n, a in G.nodes(data=True): if a["count"] <= 125: G.remove_node(n) # 3-4 ラベルの張り替え、from_scipy_sparse_matrix 設定時はラベルとして1,2,3 等の数値が設定されている G = nx.relabel_nodes(G, value_key_dict) # 3-5 描画のために調整 # figsize で 図の大きさを指定 plt.figure(figsize=(10, 10)) # 反発力と吸引力の調整 pos = nx.spring_layout(G, k=0.1) # ノードサイズの調整 node_size = [d['count'] * 20 for (n, d) in G.nodes(data=True)] nx.draw_networkx_nodes(G, pos, node_color='lightgray', alpha=0.3, node_size=node_size) # フォントサイズ、使用するフォントの設定 nx.draw_networkx_labels(G, pos, fontsize=8, font_family="IPAexGothic", font_weight="bold") # エッジの線の調整 edge_width = [d['weight'] * 2 for (u, v, d) in G.edges(data=True)] nx.draw_networkx_edges(G, pos, alpha=0.4, edge_color='c', width=edge_width) # 枠線の表示/非表示 on:表示 off:非表示 plt.axis("off") plt.show() if __name__ == '__main__': main()
search_console_classifier_utils.py
# -*- coding: utf-8 - import gspread from __builtin__ import unicode from oauth2client.service_account import ServiceAccountCredentials from sets import Set from sklearn.feature_extraction import text extra_words = Set(['name', 'not', 'the', 'usr', 'you', 'version', 'this']) stop_words = text.ENGLISH_STOP_WORDS.union(extra_words) key_file = "your_api_key.json" scope = ['https://spreadsheets.google.com/feeds'] def __check_stop_word(word): """ stop word のチェック 2文字以下の文字列を除去と、英語のstopwords を除去を行う """ if word in stop_words: return False if len(word) <= 2: return False return True def split_keyword(text): """ キーワードを区切り、stopwordsを除外する """ keywords = text.split(" ") return [keyword for keyword in keywords if __check_stop_word(keyword)] # report csv を parse する def parse_report_tsv(): lines = [] row_count = 1 credentials = ServiceAccountCredentials.from_json_keyfile_name( key_file, scope) gc = gspread.authorize(credentials) # スプレッドシート名は、Google Search Console Analyze シート名は[Merge] をOpen wks = gc.open("Google Search Console Analyze").worksheet("Merge") for line in wks.export(format='tsv').split("\n"): if row_count != 1: arr = line.split("\t") # キーワードカラムを取り出す lines.append(arr[1]) row_count += 1 return lines
説明
以下、
1. キーワード文字列を 取得 に ついて
キーワード文字列を、
tsv
tsv でも
スプレッドシートから
2. 共起単語行列を 作成処理に ついて
CountVectorizer と
TfidfVectorizer
CountVectorizer、TfidfVectorizer で それぞれ 作成しました。
どちらもそれっぽい 図が 出力されたので、 うまく いっているのではないかと 思います。
CountVectorizer、TfidfVectorizer の 説明は、 テキスト分類問題その 1 チュートリアル|ビッグデータ大学(β) が わかりやすかったです。
共起単語行列の作成方法は、 python - word-word co-occurrence matrix - Stack Overflow を 参考に 作成しました。
CountVectorizer、TfidfVectorizer の 出力結果も それほど 変わらないですが、 個人的には TfidfVectorizer の 出力結果の ほうが しっくりきました。
ただ、TfidfVectorizer に 与えている パラメータは stopwords以外、 意味も わからず 設定しているので その あたり チューニングの 余地は あるのかと 思います。 stopword
stopwords は、キーワードと して 検索されているのが 英単語が ほとんどだったので、 sklearn.feature_extraction.text の ENGLISH_STOP_WORDS と 個人的に 気になった 単語を 以下のように union して それを 使用しました。 extra_words = Set(['name', 'not', 'the', 'usr', 'you', 'version', 'this']) stop_words = text.ENGLISH_STOP_WORDS.union(extra_words)
メソッドの
戻り値
戻り値に ついてですが、 共起単語行列 Xc_norm
とラベルと 単語の 紐付け 辞書 vocabulary_
以外に、単語数を 返すようにしました。
これは、後続処理で Node の 大きさを 単語数に より 指定した ためです。
CountVectorizer、TfidfVectorizer の 戻りで 代替となる 値を とれれば それを 使うのですが、 見つけられませんでした。
3. networkx で、 ネットワーク図を 描画
[Python]NetworkXで
変えた
3-1.初期ノードの
追加
Xc_norm
をLoop で 設定しようかと 思ったのですが、 なかなかcsr_matrix を 変換する 実装サンプルが 見つからず、 メソッドと して from_scipy_sparse_matrix
が存在したので、 そちらを 使うようにしました。
以下を参考に しました。
python - Transform csr_matrix into networkx graph - Stack Overflow
from_scipy_sparse_matrix — NetworkX 1.11 documentation3-2.nodeに、
count に count属性を 設定
Nodes に文字の カウント数設定しています。
Nodeサイズを これを 元に 設定します。 ここでついでに、count = counter.get(key, 0) nx.set_node_attributes(G, "count", {value: count})
value と、 key を 入れ 替えています。 value_key_dict.update({value: key})
3-3.エッジと、
ノードの 削除
出現回数の少ない、 エッジと、 ノードの 除去を しています。
ここは、サイトの アクセス数で 変わってくるのかと 思います。 # 出現回数の少ないエッジを削除 for (u, v, d) in G.edges(data=True): if d["weight"] <= 0.15: G.remove_edge(u, v) # 出現回数の少ないノードを除去 for n, a in G.nodes(data=True): if a["count"] <= 125: G.remove_node(n)
3-4 ラベルの
張り替え
value とkey を 入れ替えた dictionary を 使って、 ノードに 名称を 設定します。 G = nx.relabel_nodes(G, value_key_dict)
説明は
TODO
動くものを
click 数とか、
impression数を 勘案して 図に 反映する
キーワードのclick 数、 impression数 を 勘案した 描画が できていないので、 その あたりを 勘案して 描画したいです。 グラフツールを
変えてみる
調べていたらいろいろ存在すると いう ことが わかりました。
graph-tool: Efficent network analysis with python やCytoscape / cyRESTと py2cytoscapeを 用いたIPython Notebook上での グラフ解析と 可視化 Part 1 - Qiita でも、 ネットワーク図が 描けるようなので、
他のグラフツールで 描いてみたいなと 思いました。
参考
以下、
以上です。
コメント