-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathfrequency_analysis.py
More file actions
155 lines (119 loc) · 6.07 KB
/
Copy pathfrequency_analysis.py
File metadata and controls
155 lines (119 loc) · 6.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
""" 각 행에 전처리된 문서가 기록된 엑셀파일에서, 전체 문서에 대해 단어 빈도분석 실시 -> 결과를 csv로 저장
"""
import os
os.environ.setdefault('MPLCONFIGDIR', os.path.join('.runtime', 'matplotlib'))
os.makedirs(os.environ['MPLCONFIGDIR'], exist_ok=True)
import pandas as pd
from wordcloud import WordCloud
import util.recorder as recorder
import util.token_parser as token_parser
def _setting():
setting = {
'xlsx_name': 'test/input/data.xlsx',
'sheet_name': 'preprocessed',
'column_name': 'article',
'result_csv_name': 'test/output/frequency_analysis.csv',
'result_word_cloud_name': 'test/output/word_cloud.png',
'word_cloud_font': 'font/NanumGothic.ttf',
'min_word_count': 10
}
excel_data = pd.read_excel(setting['xlsx_name'], sheet_name=setting['sheet_name'])[setting['column_name']]
tokenized_article_series = token_parser.parse_tokenized_series(excel_data)
return setting, tokenized_article_series
def _get_available_word_cloud_font(my_font: str = 'font/NanumGothic.ttf'):
if my_font is not None and os.path.isfile(my_font):
return my_font
if my_font is not None:
print(f'-- 워드클라우드용 폰트({my_font})가 없음')
# 설정 폰트가 없을 때 한글이 네모로 깨지지 않도록 흔한 시스템 폰트를 사용한다.
fallback_fonts = [
'/System/Library/Fonts/AppleSDGothicNeo.ttc',
'/System/Library/Fonts/Supplemental/AppleGothic.ttf',
'/System/Library/Fonts/Supplemental/NotoSansGothic-Regular.ttf',
'C:/Windows/Fonts/malgun.ttf',
'/usr/share/fonts/truetype/nanum/NanumGothic.ttf',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
'/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc'
]
for font_path in fallback_fonts:
if os.path.isfile(font_path):
print(f'-- 대체 한글 폰트({font_path})를 사용합니다.')
return font_path
print('-- 대체 한글 폰트를 찾지 못해 기본 폰트로 워드클라우드를 생성합니다.')
return None
def count_frequency(tokenized_article_series: pd.Series, min_word_count: int = 10) -> pd.Series:
""" 단어(토큰)와 빈도수를 내림차순으로 반환
Args:
tokenized_article_series(pd.Series): 각 줄은 토큰으로 구성된 리스트 예: [키워드, 키워드, 키워드 ... ]
min_word_count: 적게 등장한 단어를 결과에서 제거할 때 그 기준
Returns:
(pd.Series) 각 열마다 단어와 빈도수
"""
words = tokenized_article_series.explode().dropna()
word_count_series = words[words != ''].value_counts(ascending=False).rename('word_count')
# min_word_count 보다 많이 등장한 단어만 제시
return word_count_series[word_count_series > min_word_count]
def word_cloud_analysis(csv_location: str, save_graph_to: str = None, my_font: str = 'font/NanumGothic.ttf'):
""" frequency_analysis() 결과로 저장된 csv 파일을 읽어와서 워드클라우드 작성
"""
df = pd.read_csv(csv_location, index_col=0)
if df.empty:
print('-- 빈도분석 결과가 비어 있어 워드클라우드를 생성하지 않습니다.')
return
my_dict = dict(zip(df.index, df.iloc[:, 0]))
my_dict = {word: count for word, count in my_dict.items() if pd.notna(word) and pd.notna(count) and count > 0}
if not my_dict:
print('-- 워드클라우드에 사용할 단어가 없어 생성하지 않습니다.')
return
# 폰트 확인
my_font = _get_available_word_cloud_font(my_font)
# wordcloud에 대한 세부설정은 아래 웹사이트 참조
# https://amueller.github.io/word_cloud/generated/wordcloud.WordCloud.html
wordcloud = WordCloud(font_path=my_font, width=3200, height=1600, background_color='white').fit_words(my_dict)
if save_graph_to is None or save_graph_to == 'none':
import matplotlib.pyplot as plt
plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout()
plt.show()
plt.clf()
else:
recorder.ensure_parent_dir(save_graph_to)
wordcloud.to_file(save_graph_to)
def frequency_analysis_by_group():
# TODO 그룹으로 나눈 것(예: time_slice) 기준으로 빈도수 분석
pass
def frequency_analysis(setting: dict = None, tokenized_article_series: pd.Series = None):
""" 전처리된 문서들에 대해 빈도분석을 하여 csv로 저장
Args:
setting: 설정값 불러오기
setting['result_csv_name']: str = 빈도분석 결과를 저장할 csv파일, 예: 'where/filename.csv'
setting['min_word_count']: int = 적게 등장한 단어를 결과에서 표시하지 않을 때 그 기준
tokenized_article_series: 한 줄에 토큰화된 문서 하나씩
"""
if setting is None:
setting, default_tokenized_article_series = _setting()
if tokenized_article_series is None:
tokenized_article_series = default_tokenized_article_series
elif tokenized_article_series is None:
excel_data = pd.read_excel(setting['xlsx_name'],
sheet_name=setting['sheet_name'])[setting['column_name']]
tokenized_article_series = token_parser.parse_tokenized_series(excel_data)
token_parser.log_empty_documents(
tokenized_article_series,
'분석 입력',
'-- 빈 문서를 포함한 상태로 빈도분석을 계속 진행합니다.'
)
# frequency analysis
frequency_result = count_frequency(tokenized_article_series, setting['min_word_count'])
# save result
recorder.ensure_parent_dir(setting['result_csv_name'])
frequency_result.to_csv(setting['result_csv_name'], mode='w', encoding='utf-8',
header=['count'], index_label='word')
# word cloud
word_cloud_analysis(setting['result_csv_name'], setting['result_word_cloud_name'], setting['word_cloud_font'])
def main():
with recorder.WithTimeRecorder('빈도분석'):
frequency_analysis()
if __name__ == '__main__':
main()