4 분 소요

데이터셋 준비


KorNLI - 두 문장의 관계를 entailment/neutral/contradiction 으로 분류

https://github.com/kakaobrain/KorNLUDatasets/tree/master/KorNLI 에서 받아옵니다.

import pandas as pd

path = '/content/drive/MyDrive/KorNLUDatasets-master/KorNLI/'

train_snli = pd.read_csv(path + "snli_1.0_train.ko.tsv", sep='\t', quoting=3)
train_xnli = pd.read_csv(path + "multinli.train.ko.tsv", sep='\t', quoting=3)
# 결합 후 섞기
train_data = train_snli.append(train_xnli)
train = train_data.sample(frac=1).reset_index(drop=True)
def drop_na_and_duplciates(df):
  df = df.dropna()
  df = df.drop_duplicates()
  df = df.reset_index(drop=True)
  return df
# 전제, 가설에 존재하는 한글 단어가 아닌 다른 단어들은 전부 제거해줍니다.
# train['sentence1'] = train['sentence1'].str.replace('[^ㄱ-ㅎㅏ-ㅣ가-힣 0-9]', '')
# train['sentence2'] = train['sentence2'].str.replace('[^ㄱ-ㅎㅏ-ㅣ가-힣 0-9]', '')
# 결측값 및 중복 샘플 제거
train = drop_na_and_duplciates(train)
train.head()
sentence1 sentence2 gold_label
0 군복 차림의 어린 소년이 흙길에서 빠르게 달린다. 소년이 침실로 달려가고 있다. contradiction
1 이슬람교도들은 녹색 예언자 엘리야를 팬으로 대체하면서 예배의 전통을 이어갔다. 그리... 두 건물의 폐허는 십자군 마을의 남은 전부다. neutral
2 검은 머리의 남자가 선글라스를 쓴 검은 머리의 여자 근처에 있는 구조물 위에 앉아 있다. 두 아이가 구조물 아래에서 놀고 있다. contradiction
3 오 정말 오, 우리가 댈러스에 있기 때문에 나는 네가 여기 잘 있었다고 추측했어. ... 오, 너 댈러스에 있잖아, 사실 우린 휴스턴에 있어. contradiction
4 과일 가게의 점원이 의상을 입는 사람들을 기다리고 있다. 남자가 야외에 있다. neutral

데이터 시각화

import matplotlib.pyplot as plt 
import numpy as np

label의 분포도 확인

label: neural, contradiction, entailment로 구성됨

features = train['gold_label'].value_counts()

plt.title('label')
plt.bar(features.keys(), features.values, width=0.5)
plt.show()

자연어 분석및 시각화

print('Train Label: ', train['gold_label'].value_counts(), sep='\n', end='\n\n')
Train Label: 
neutral          314148
contradiction    314130
entailment       313536
Name: gold_label, dtype: int64

premise_len_mean = np.mean(train['sentence1'].str.len()) # 자연어 길이의 평균값 계산
print('실제 Text 평균 길이 :',premise_len_mean)

hypo_len_mean = np.mean(train['sentence2'].str.len())
print('가설 Text 평균 길이 :',hypo_len_mean)
실제 Text 평균 길이 : 42.197995570250605
가설 Text 평균 길이 : 23.279179328402424
# 데이터 필터링을 위한 마스크 설정 (sentence1 부분만)
mask_true = (train.gold_label == 'entailment')
mask_false = (train.gold_label == 'contradiction')
mask_neutral = (train.gold_label == 'neutral')

df_train = train.sentence1.copy()

df_true = train.loc[mask_true,:].sentence1
df_false = train.loc[mask_false,:].sentence1 
df_neu = train.loc[mask_neutral,:].sentence1 

# 세 집합을 리스트로 묶어줍니다.
compare = [df_train, df_true, df_false, df_neu]
# 히스토그램 을 사용해서 데이터의 분포를 살펴봅니다.
plt.figure(figsize=(15,9))
plt.suptitle("Histogram: premise length", fontsize=40)
name = ['total dataset', 'entailment text', 'contradiction text', 'neutral text']

for i in range(len(compare)):
    document = compare[i]
    string_len = [len(x) for x in document]
    plt.subplot(2, 2, i+1)
    plt.title(name[i], fontsize=20)
    plt.hist(string_len, alpha=0.5, color='orange') 
    
plt.show()

각 label의 실제 문장들은 대부분 약 50자의 문장들로 구성되어 있음을 알 수 있다.

# 데이터 필터링을 위한 마스크 설정 (sentence2 부분만)
mask_true = (train.gold_label == 'entailment')
mask_false = (train.gold_label == 'contradiction')
mask_neutral = (train.gold_label == 'neutral')

df_train = train.sentence2.copy()

df_true = train.loc[mask_true,:].sentence2
df_false = train.loc[mask_false,:].sentence2
df_neu = train.loc[mask_neutral,:].sentence2 

# 세 집합을 리스트로 묶어줍니다.
compare = [df_train, df_true, df_false, df_neu]
# 히스토그램 을 사용해서 데이터의 분포를 살펴봅니다.
plt.figure(figsize=(15,9))
plt.suptitle("Histogram: premise length", fontsize=40)
name = ['total dataset', 'entailment text', 'contradiction text', 'neutral text']

for i in range(len(compare)):
    document = compare[i]
    string_len = [len(x) for x in document]
    plt.subplot(2, 2, i+1)
    plt.title(name[i], fontsize=20)
    plt.hist(string_len, alpha=0.5, color='orange') 
    
plt.show()

각 label의 가설 문장은 대부분이 약 25자 정도에 많이 분포되어 있습니다.

Word cloud


wordcloud란 메타 데이터에서 얻어진 태그들을 분석하여 중요도나 인기도 등을 고려하여 시각적으로 늘어놓아 표시하는 것이다. 중요도(혹은 인기도)에 따라 글자의 색상이나 굵기 등 형태가 변한다.

  1. KoNLPy와 nltk lib를 사용해서 문서에서 각각의 형태소(≒ 주로 명사인 단어)로 추출

  2. Collection Counter() 모듈을 사용해서 명사가 언급된 횟수를 계산

  3. WordCloud Lib를 사용하여 형태소(단어) 빈도에 따른 WordCloud 이미지 생성 및 저장

import wordcloud
#패키지 불러오기 및 각종 설치 & 폰트 설정 한방에 
import matplotlib
%matplotlib inline

import matplotlib.pyplot as plt 
import matplotlib.font_manager as fm  

!apt-get update -qq
!apt-get install fonts-nanum* -qq

font_path = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf'
font_name = fm.FontProperties(fname=font_path, size=10).get_name()
print(font_name)
plt.rc('font', family=font_name)

fm._rebuild()
matplotlib.rcParams['axes.unicode_minus'] = False
NanumBarunGothic
!pip install konlpy
Requirement already satisfied: konlpy in /usr/local/lib/python3.7/dist-packages (0.6.0)
Requirement already satisfied: JPype1>=0.7.0 in /usr/local/lib/python3.7/dist-packages (from konlpy) (1.3.0)
Requirement already satisfied: lxml>=4.1.0 in /usr/local/lib/python3.7/dist-packages (from konlpy) (4.2.6)
Requirement already satisfied: numpy>=1.6 in /usr/local/lib/python3.7/dist-packages (from konlpy) (1.21.5)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from JPype1>=0.7.0->konlpy) (3.10.0.2)
from konlpy.tag import Okt
from collections import Counter
from wordcloud import WordCloud
def df2str(df):
    #전체 문장들을 하나의 문자열로 만듦
    s = [s for s in df]
    document = ""
    for i in range(len(s)):
        document += s[i]
    return document

def tokenizer_konlpy(text):
    okt = Okt()
    return [word for word in okt.nouns(text) if len(word) >1]
## train_data는 너무 오래 걸려 검증 데이터로 대신 사용
val = pd.read_csv(path + "xnli.dev.ko.tsv", sep='\t', quoting=3)   
texts = df2str(val['sentence1'])
noun = tokenizer_konlpy(texts)
# count word
count = Counter(noun)

noun_list = count.most_common(100)
noun_list[:10]       ## 가장 많이 쓰인 단어 출력
[('우리', 294),
 ('당신', 204),
 ('대한', 189),
 ('그것', 162),
 ('위해', 138),
 ('그녀', 126),
 ('사람', 126),
 ('미국', 120),
 ('가지', 114),
 ('다른', 112)]
# Generate a word cloud image
wc = WordCloud(font_path = font_path,
                    background_color = 'white',
                    width=512, height=512,
                    max_font_size=500,
                    max_words=1000)
wc.generate_from_frequencies(dict(noun_list))
plt.figure(figsize=(10,10)) #이미지 사이즈 지정
plt.title('text_rate', fontsize=20)
plt.imshow(wc, interpolation='lanczos') #이미지의 부드럽기 정도
plt.axis('off') #x y 축 숫자 제거
plt.show()  # 워드클라우드 이미지 확인

texts = df2str(val['sentence2'])
noun = tokenizer_konlpy(texts)
# count word
count = Counter(noun)

noun_list = count.most_common(100)
noun_list[:10]       ## 가장 많이 쓰인 단어 출력
[('사람', 176),
 ('우리', 172),
 ('당신', 87),
 ('그것', 86),
 ('그녀', 85),
 ('가지', 79),
 ('모든', 75),
 ('때문', 72),
 ('대해', 71),
 ('다른', 69)]
# Generate a word cloud image
wc = WordCloud(font_path = font_path,
                    background_color = 'white',
                    width=512, height=512,
                    max_font_size=500,
                    max_words=1000)
wc.generate_from_frequencies(dict(noun_list))
plt.figure(figsize=(10,10)) #이미지 사이즈 지정
plt.title('text_rate', fontsize=20)
plt.imshow(wc, interpolation='lanczos') #이미지의 부드럽기 정도
plt.axis('off') #x y 축 숫자 제거
plt.show()  # 워드클라우드 이미지 확인

댓글남기기