[텍스트 마이닝-분석] 단어동시출현행렬 및 CONCOR 분석
SNS 텍스트 분석을 하다 보면 텍스트 데이터에서 네트워크 분석이 필요할 때가 있습니다.
여러 개의 네트워크 분석 기법 중, 전체 데이터 내에서 유사한 맥락과 연결구조패턴을 갖고 있는 단어들끼리 그룹화하는 기법을 CONCOR 분석이라고 합니다.
https://www.kipa.re.kr/site/kipa/research/selectPublishView.do?gubun=KI&pblcteId=PUBL_000000000000572
KIPA조사포럼(~2022) - 한국행정연구원
초연결사회에서 사회조사가 나아갈 방향 주제 심층분석 ㆍ인포그래픽스 - 초연결사회란 무엇인가 - 초연결사회에서의 소셜 커넥션 - 초연결사회에서의 정보원 - 초연결사회에서의 생
www.kipa.re.kr
이번에는 CONCOR 분석에 필요한 단어동시출현행렬을 만들어 보겠습니다.
우선 분석에 필요한 모듈과 패키지를 임포트해줍니다.
import pandas as pd
import numpy as np
import re
from tqdm.notebook import tqdm
import os
from collections import Counter
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer, TfidfTransformer
# 단어동시출현행렬 생성 후 확인하기 위해 모든 컬럼이 출력되도록 설정하는 코드입니다.
pd.set_option('display.max_columns', None)
분석에 사용할 파일을 불러옵니다.
이때 단위는 문서 기준이며, 각 문서를 형태소로 치환한 데이터를 사용해야 합니다.
df = pd.read_csv("파일경로", encoding='UTF-8')
print(df.shape, df.columns)
docs = df['칼럼명'].to_list()
print(len(docs))
본문이 str타입으로 되어있을 경우 split을 통해 본문을 list of str으로 바꿔줍니다. (각각의 형태소가 str 타입으로)
#### 각각의 본문이 str타입('나는 어제 밥을 먹었다')일 경우 list(['나', '는', '어제', '밥', '을' '먹다', '이다'])로 바꿔줌
docs2 = docs.copy()
for i in tqdm(range(len(docs))):
docs2[i] = docs2[i].split()
단어 간의 문서 내 동시 출현 빈도를 계산할 단어 목록 파일을 불러옵니다.
이때 단어 목록 선정 기준은 보통 단어 빈도 내림차순 기준 상위 50개를 사용합니다.
(이수상. 네트워크 분석 방법론. 서울: 논형, 2012)
topwords_df = pd.read_csv("파일경로", encoding='UTF-8')
print(topwords_df.shape, topwords_Df.columns)
topwords50 = topwords_df['칼럼명'].to_list()
# print~는 단어가 잘 불러와졌는지 확인하는 코드이므로 선택에 따라 실행하시면 됩니다.
# print(len(topwords50))
# print(topwords50)
단어 동시 출현 빈도는 하나의 문서에 a와 b 단어가 세 번씩 쓰였더라도 1로 카운트하기 때문에
문서 내 형태소들의 중복을 제거해줍니다.
# list comprehension에서 set으로 중복을 제거해줍니다.
unique_lines = [list(set(line)) for line in tqdm(docs2)]
# 중복 제거 잘 됐나 개수로 확인
print(len(docs[0])) # 형태소 변환한 문서 원본
print(len(unique_lines[0])) # 중복 제거한 문서
print(unique_lines[0][0:10]) # 형태소 확인
이제 단어 빈도를 계산합니다.
# 전체 단어쌍 빈도 dict 형식으로 생성
freq_count = {} #동시출현 빈도가 저장될 dict
for words in tqdm(unique_lines):
# 전체 단어에 대한 동시 출현 빈도
for i, a in enumerate(words):
for b in words[i+1:]:
if a == b: continue
elif a>b:
freq_count[b, a] = freq_count.get((b, a),0) + 1
else :
freq_count[a, b] = freq_count.get((a, b),0) + 1
데이터 양이 많을 경우 단어쌍 빈도 계산에 시간이 오래 걸릴 수 있습니다.
업무 시간 내에 작업이 끝나지 않을 경우 딕셔너리를 데이터프레임에 담아 저장하고 다음날 다시 작업하면 되겠습니다.
물론, 퇴근 후에도 작업 중인 컴퓨터를 켜놓을 수 있다면 굳이 거치지 않아도 되는 단계입니다.
# 딕셔너리를 데이터프레임에 담기
tt_freq_df=pd.DataFrame.from_dict(tt_freq_count, orient='index')
# 딕트to데이터프레임 저장
freq_df.to_csv("파일저장경로/파일명.txt", encoding='UTF-8')
딕셔너리를 컬럼명을 지정해서(단어쌍 첫 번째 단어, 단어쌍 두 번째 단어, 동시출현빈도) 데이터프레임으로 변환해줍니다.
이렇게 만든 데이터프레임은 추후 다른 단어를 기준으로 concor 분석을 할 때 필요한 단어만 골라서 꺼내 쓰면 편리하므로 파일로 저장해줍니다.
# dictionary에 컬럼명을 지정해서 데이터프레임으로 변환해줍니다.
list1 = [(freq_df.index[i][0], freq_df.index[i][1], freq_df[0][i]) for i in tqdm(range(len(freq_df)))]
freq_df2 = pd.DataFrame(list1, columns=["term1","term2","freq"])
print(freq_df2.shape)
freq_df2.head()
# 컬럼명 지정한 dict_to_데이터프레임 저장
freq_df2.to_csv("파일저장경로/파일명.txt", index=False, encoding='UTF-8')
이제 거의 다 끝났습니다.
전체 단어의 단어쌍빈도에서 단어빈도 상위 50개의 단어만 추출해줍니다.
list2 =[(freq_df2.loc[i][0], freq_df2.loc[i][1], freq_df2.loc[i][2]) for i in tqdm(range(len(freq_df2))) if (freq_df2['term1'][i] in topwords50) &(freq_df2['term2'][i] in topwords50)]
freq_df3 = pd.DataFrame(list2, columns=["term1","term2","freq"])
freq_df3
# 상위50위 단어들로 이루어진 단어쌍 데이터프레임 저장
freq_df3.to_csv("파일저장경로/파일명.txt", index=False, encoding='UTF-8')
컬럼과 인덱스를 동일하게 지정해서 대칭 형식의 단어동시출현행렬을 만들어줍니다.
# 공출현빈도(1-mode matrix) 만들기
word_co_matx = np.zeros((50,50))
mat_idx = topwords50 # 단어동시출현행렬이니까 인덱스와 칼럼을 동일하게 지정
mat_col = topwords50
word_co_matx = pd.DataFrame(word_co_matx, index=mat_idx, columns=mat_col)
print(word_co_matx.shape)
# 단어쌍의 첫 번째 단어가 인덱스와 같다 and 두 번째 단어가 칼럼과 같다 → 단어쌍빈도를 해당 셀 값에 삽입
for n in tqdm(range(len(freq_df3))):
for idx in mat_idx:
if idx == freq_df3['term1'][n]:
for col in mat_col:
if col == freq_df3['term2'][n]:
word_co_matx.loc[idx, col] = freq_df3['freq'][n]
word_co_matx.loc[col, idx] = freq_df3['freq'][n]
# 1-mode 매트릭스 확인하기
tt_word_co_matx
잘 만들어졌다면 엑셀 파일로 저장해주면 끝! 입니다.
#### 공출현빈도 데이터프레임 저장하기~~
#### ※ 인덱스가 저장돼야 하므로 index 파라미터 지정하지 말 것.
word_co_matx.to_csv("파일저장경로/파일명.txt", encoding='UTF-8') # 혹시 몰라 텍스트 파일로도 저장. 이건 취사선택.
word_co_matx.to_excel("파일저장경로/파일명.xlsx", encoding='UTF-8')
다른 기술 블로그들이 그렇듯,
코드를 블로그에 공유하는 것은 기록과 '공유'를 위해서입니다.
만약 제 글의 도움을 받아 본인의 글을 작성하신다면 출처를 남겨주시길 바랍니다.
문의는 댓글로 남겨주시면 확인 후 답변드리겠습니다.