import MeCab from wordcloud import WordCloud import collections import csv as c from tqdm import tqdm import seaborn as sns import matplotlib.pyplot as plt import re def _mecab_wakati(text): # 形態素解析を行う(分かち書き) wakati_tagger = MeCab.Tagger("-Owakati") # 分かち書き parse = wakati_tagger.parse(text) return parse def _mecab(text): # 形態素解析を行い品詞リストを返す tagger = MeCab.Tagger() tagger.parse("") node = tagger.parseToNode(text) node_list = [] while node: # 例: ['吾輩', '名詞', '代名詞', '一般', '*', '*', '*', '吾輩', 'ワガハイ', 'ワガハイ'] node_list.append([node.surface]+node.feature.split(",")) node = node.next node_list = node_list[1:-1] # BOS/EOSタグを除外 return node_list # キーワード解析 def keyword_analy(text): key_out = [] key_list = ["ように", "修正", "追加", "削除", "作成", "設定", "保存", "変更", "編集", "更新", "整理", "調整", "実装", "表示", "化"] for key in key_list: if key in text: key_out.append(key) return key_out class WordCloudGenerator: """ WordCloud """ out_file_name = "" def __init__(self, font_path, background_color, width, height, collocations, stopwords, max_words, regexp): """ 出力パラメータ初期化 """ self.font_path = font_path self.background_color = background_color self.width = width self.height = height self.collocations = collocations self.stopwords = stopwords self.max_words = max_words self.regexp = regexp def wordcloud_draw(self, parse): """ wordcloud画像を出力 @param parse 形態素解析結果 """ self.wordcloud = WordCloud(font_path=self.font_path, background_color=self.background_color, width=self.width, height=self.height, collocations=self.collocations, stopwords=self.stopwords, max_words=self.max_words, regexp=self.regexp, repeat=False) self.wordcloud.generate(parse) self.wordcloud.to_file(self.out_file_name) def frequency_count(self, wakati_text): """ 単語の頻出頻度算出 @param wakati_text str 分かち書きテキスト """ words = wakati_text.split(" ") words = [word for word in words if word not in self.stopwords] word_freq = collections.Counter(words) return word_freq def frequency_count_jp(self, wakati_text): """ 日本語の単語頻出頻度算出 @param wakati_text str 分かち書きテキスト """ words = wakati_text.split(" ") compile_words = re.compile('[!"#$%&\'\\\\()*+,-./:;<=>?@[\\]^_`{|}~「」〔〕“”〈〉『』【】&*・()$#@。、?!`+¥%]') compile_abc_123 = re.compile(r'[a-zA-Z0-90-9]') words_jp = [] for word in words: if not bool(compile_words.search(word)): if not bool(compile_abc_123.search(word)): words_jp.append(word) word_freq = collections.Counter(words_jp) return word_freq def _get_all_commit_message(repo): """ すべてのcommit messageを取得する """ all_commit_message = "" with open("log/eliminate_message.txt", "w", encoding="utf-8") as f: for commit in repo.iter_commits(): # Mergeから始まるcommit messageは除外 if not commit.message.startswith('Merge'): all_commit_message += commit.message try: f.write(commit.author) except TypeError: pass f.write(","+commit.message+"\n") return all_commit_message def _get_commit_message_by_author(repo, author): """ 指定したauthorのcommit messageを取得する """ commit_message = "" for commit in repo.iter_commits(): if commit.author == author: # Mergeから始まるcommit messageは除外 if not commit.message.startswith('Merge'): commit_message += commit.message return commit_message def _wordcloud_all_messages(repo, wordCloudGenerator): """ すべてのcommit messageでwordcloudを作成する """ # 入力テキストファイル OUT_FILE_NAME = "pic/wordcloud_message.png" # 形態素解析 text = _get_all_commit_message(repo) mecab_all = _mecab(text) # 形態素解析 # 名詞及び名詞連結を取得# """ 名詞連結は,現状うまく動かないので,一旦コメントアウト """ # mecab_linking_noun = [] # for m in range(len(mecab_all)-1): # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": # mecab_linking_noun.append( # mecab_all[m][0]+mecab_all[m+1][0]) # elif mecab_all[m][1] == "名詞": # mecab_linking_noun.append(mecab_all[m][0]) # else: # pass mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 wakati = " ".join(mecab_only_noun) # 分かち書き wordCloudGenerator.out_file_name = OUT_FILE_NAME # 出力ファイル名 wordCloudGenerator.wordcloud_draw(wakati) # 出力 print(f"{wordCloudGenerator.out_file_name}に画像を出力しました") print() def _wordcloud_by_author(repo, wordCloudGenerator): """ authorごとにwordcloudを作成する """ # 入力テキストファイル OUT_FILE_NAME = "pic/wordcloud_message_author/{}.png" # すべてのauthorを取得 #この方法はちょっと時間がかかるかも.最適化の余地あり. authors = set() for commit in repo.iter_commits(): authors.add(commit.author) # 各authorのcommit messageを取得 authors_text = dict() for author in authors: # authorの名前は一緒だが,メアドが違う場合があるとき,同じauthorとみなしてmessageを結合する if author.name in authors_text: authors_text[author.name] += _get_commit_message_by_author( repo, author) else: authors_text[author.name] = _get_commit_message_by_author( repo, author) for author, text in authors_text.items(): # 形態素解析 mecab_all = _mecab(text) # 形態素解析 # リストが空の場合はスキップ if len(mecab_all) == 0: continue # 名詞及び名詞連結を取得# """ 名詞連結は,現状うまく動かないので,一旦コメントアウト """ # mecab_linking_noun = [] # for m in range(len(mecab_all)-1): # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": # mecab_linking_noun.append( # mecab_all[m][0]+mecab_all[m+1][0]) # elif mecab_all[m][1] == "名詞": # mecab_linking_noun.append(mecab_all[m][0]) # else: # pass mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 wakati = " ".join(mecab_only_noun) # 分かち書き wordCloudGenerator.out_file_name = OUT_FILE_NAME.format(author) # 出力ファイル名 wordCloudGenerator.wordcloud_draw(wakati) # 出力 print(f"{wordCloudGenerator.out_file_name}に画像を出力しました") print("すべてのcontributorのwordcloudを出力しました") print() def run(repo): # message.csv f = open("./log/message.csv", "w+", encoding="utf_8_sig", newline='') csv = c.writer(f) # csvヘッダー追加 csv.writerow([ 'commit_no', 'message', 'len', 'key_flag', 'keyword', 'marp_flag' 'morpheme']) sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 commit_count = 0 sum_message_len = 0 # メッセージの文字数合計 key_match_count = 0 # キーワードの一致回数合計 # commit message を取得 with tqdm(total=int(sum_commits), desc='message.csv') as pbar: # プログレスバーの設定 for commit in repo.iter_commits(): commit_no = int(sum_commits) - commit_count message_len = int(len(commit.message)) - 1 sum_message_len += message_len keyword = keyword_analy(commit.message) key_flag = len(keyword) if key_flag == 0: keyword = "none" else: key_match_count += 1 # message.csvに書き込み csv.writerow([ commit_no, commit.message, message_len, key_flag, keyword, 0, "none"]) commit_count += 1 pbar.update(1) # プログレスバーの進捗率を更新 """ wordcloud生成処理 """ #### パラメータ #### STOP_WORDS = [" ", " "] # ストップワード MAX_WORDS = 2000 # 出力個数の上限 WIDTH = 500 # 出力画像の幅 HEIGHT = 500 # 出力画像の高さ FONT_FILE = "font/ipaexg.ttf" # フォントファイルのパス wordCloudGenerator = WordCloudGenerator(font_path=FONT_FILE, background_color="white", width=WIDTH, height=HEIGHT, collocations=False, stopwords=STOP_WORDS, max_words=MAX_WORDS, regexp=r"[\w']+") # WordCloud初期化 _wordcloud_by_author(repo, wordCloudGenerator) # authorごとにwordcloudを作成 # _wordcloud_all_messages(repo, wordCloudGenerator) # 全メッセージをwordcloudにして出力 # 単語の頻出頻度 wordCloudGenerator.out_file_name = "./pic/word_frequency.png" """マージ前の処理と同じはず""" mecab_all = _mecab(_get_all_commit_message(repo)) # 形態素解析 mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 wakati = " ".join(mecab_only_noun) # 分かち書き frequency_words = wordCloudGenerator.frequency_count_jp(wakati).most_common(30) sns.set(context="talk", font='Yu Gothic') fig = plt.subplots(figsize=(18, 8)) sns.countplot(y=mecab_only_noun, order=[i[0] for i in frequency_words]) plt.subplots_adjust(left=0.175, right=0.95, bottom=0.12, top=0.95) plt.savefig("pic/frequency_words.png") print("pic/frequency_words.pngに画像を出力しました") print("---メッセージ解析結果---") print("総メッセージ数:" + sum_commits) print("文字数の平均:{:.1f}".format(sum_message_len/int(sum_commits))) print("キーワード一致回数:" + str(key_match_count)) print() f.close() if __name__ == "__main__": OUT_FILE_NAME = "pic/wordcloud_message.png" TEXT = "吾輩は吾輩である.名前はスーパー吾輩である.Yes, I am wagahai." mecab_all = _mecab(TEXT) # 形態素解析 # 名詞及び名詞連結を取得# """ 名詞連結は,現状うまく動かないので,一旦コメントアウト """ # mecab_linking_noun = [] # for m in range(len(mecab_all)-1): # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": # mecab_linking_noun.append( # mecab_all[m][0]+mecab_all[m+1][0]) # elif mecab_all[m][1] == "名詞": # mecab_linking_noun.append(mecab_all[m][0]) # else: # pass mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 #### パラメータ #### STOP_WORDS = [" "] # ストップワード MAX_WORDS = 2000 # 出力個数の上限 WIDTH = 500 # 出力画像の幅 HEIGHT = 500 # 出力画像の高さ FONT_FILE = "data/ipaexg.ttf" # フォントファイルのパス wakati = " ".join(mecab_only_noun) # 分かち書き wordCloudGenerator = WordCloudGenerator(font_path=FONT_FILE, background_color="white", width=WIDTH, height=HEIGHT, collocations=False, stopwords=STOP_WORDS, max_words=MAX_WORDS, regexp=r"[\w']+") # WordCloud初期化 wordCloudGenerator.out_file_name = OUT_FILE_NAME # 出力ファイル名 wordCloudGenerator.wordcloud_draw(wakati) # 出力