본문 바로가기
Study/NLP

Fasttext 이용해서 분류 모델 만들기

by uiydlop 2023. 5. 17.

✔ google colab에서 실행

✔ fasttext text classification (텍스트 분류) 사용
https://uiydlop.tistory.com/22

 

Fasttext classification (텍스트 분류)

Facebook's AI Research (FAIR) lab 에서 만든wordembdding과 text classification을 위한 library 294개 언어에 대해서 pretrained model을 제공 레이블이 많고 일부 레이블로 분류해야 하는 짧은 텍스트가 많을 때 정말 잘

uiydlop.tistory.com

✔ 학습데이터로는 https://dacon.io/competitions/open/235597/data 청와대 청원 주제 데이터 이용


 

1. fattext 설치

 

!pip install fasttext

 

➕ 그 외 필요한 라이브러리 불러오기

 

import fasttext
import pandas as pd
import numpy as np
import os

 


2. 학습 데이터 불러오기

 

train = pd.read_csv(os.path.join(path,"train.csv"))

 


3. 학습 데이터 가공

 

input data는 전처리 (특수문자 제거, 형태소분석, 불용어제거) 해줘야 모델 성능을 더 좋게 만듦

 

1) 특수문자 제거

 

train['data'] = train['data'].str.replace(r'[-=+,#/\?:^$.@*\"※~&%ㆍ!』\‘|\<\>`\'…》\n\t]+', " ", regex=True)

train['data'] = train['data'].str.replace(r'\t+', " ", regex=True)
train['data'] = train['data'].str.replace(r'[\n]+'," ", regex=True)

 

2) 불용어 제거, 형태소 분석

- mecab을 이용하여 깨끗한 토큰 형태로 만들어준다.

stop_file = pd.read_csv('불용어사전.csv', encoding='utf-8')
stopword = []
stopword.extend(stop_file['불용어'])

text =  labeling['data'].values.tolist()
Merge = [(n, text[n]) for n in range(0,len(text))]
nouns = ['NNG', 'NNP', 'NNB', 'VA', 'VV', 'XSV+EP',  'NNBC', 'NR', 'SL', 'NP']
for (i, text) in tqdm(Merge):
    text = mecab.pos(text)
    clean_text = [word for word, token in text if token in nouns and word not in stopword] #불용어 제거
    clean_text= ' '.join([word for word in clean_text if len(word) > 1]) #한글자 제거
    train.at[i, 'data'] = clean_text

 

before after
신혼부부위한 주택정책 보다 보육시설 늘려주세요.. 국민세금으로 일부를 위한 정책펴지 마시고\n보편적으로 모든국민이 수긍할  수 있는 복지정책 펴 주시길 바랍니다.\n저도 신혼부부이지만 당첨되는 사람 로또되는 이런주택정책 반대합니다.\n국민세금을 일부 사람들에게 퍼주기식이 되면 안되죠..\n그 세금으로 우리아이 안전하게 맡길 수 있는 보육시설을 전국에 설치해 주세요..\n대기업들은 솔선수범해서 모든 사업장에 의무설치 할 수 있도록 하시구요..\n집 보다 애 맡길데가 없어 경력단절 되는게 더 괴롭습니다.!\n집은 개인의 능력을 키워 사는게 맞습니다.\n그 능력을 키울수 있도록 육아 전담에 힘을 기울이는게 맞습니다.\n우리아이 부모가 키우는거 맞지만 이제는 국가가\n책임지는 시대로 가는게 맞다고 봅니다.\n그렇잖아도 부동산 가격 자꾸 올라가는게 정부정책이 잘못 되었다고 봅니다.\n부동산은 그냥 내버려 두세요!  좀!\n건들수록 역효과네요.. 신혼 부부 주택정책 보육 시설 국민 세금 일부 정책 마시 보편 국민 수긍 복지 정책 신혼 부부 당첨 로또 주택정책 반대 국민 세금 일부 세금 전하 보육 시설 전국 설치 기업 솔선수범 사업장 의무 설치 경력 단절 괴롭 개인 능력 능력 육아 전담 기울이 아이 부모 키우 이제 국가 책임지 시대 부동산 가격 올라가 정부 정책 부동산 건들 역효과
학교이름에 '남자'도 붙여주세요. 울산여자중학교에 재학중인 학생입니다 최근 양성평등 글짓기를 하다 생각했습니다 우리 울산엔 '울산중학교'는 두개입니다 하나는 남중,하나는 여중인데 어째서 우리학교만 '여자'를 붙여야하는가 하고요 남자가 우위였던 때 지어졌던 학교라 그런진 모르겠지만 울산중학교(남중)에도 '남자'를 붙여 울산남자중학교가 되게 해주세요\n평소에 학교이름을 줄여 부를때에도 우리학교는 울여중,남중은 그냥 울중 이라 부릅니다 몇년동안 그리 불러온, 너무나 익숙해진 이 현실을 이젠 바꿀때가 되지않았나 싶네요,,지금은 조선시대가 아니니까요\n국내에 이런 학교는 널렸습니다 울산뿐만이 아니라 국내 다른 중/고등학교에 있는 똑같은 문제들을 해결해주셨으면 합니다... 학교 남자 울산 중학교 재학 학생 최근 양성 평등 글짓기 울산 울산 중학교 남중 여중 학교 남자 우위 학교 울산 중학교 남중 남자 울산 남자 중학교 평소 학교 학교 여중 남중 동안 현실 조선 시대 국내 학교 울산 국내 고등학교 똑같 해결
빙상연맹, 대한축구협회등 각종 체육협회의 비리를 철저하게 밝혀주세요.. 최근 동계올림픽에서 김보름, 박지우 선수와 관련해서 큰 논란거리가 되고 있는데요. 선수 개개인의 문제를 떠나서 이번일에 대해 대한빙상연맹의 불합리한 행정에 불신을 갖고있는 사람들이 많습니다. 이제 동계올림픽도 폐막일이 다가오고, 6월이 되면 러시아에서 4년마다 열리는 월드컵 축구대회가 열리는데요.  월드컵이 시작도 하기전부터 감독선임, 선수선발에 대해 우려의 목소리를 내는 사람들이 정말 많습니다.\n아시아 최종예선 내내 기대이하의 경기력으로 실망스러운 모습을 보인건 둘째 치더라도 슈틸리케 감독을 경질하고, 2016 리우 올림픽 감독을 맡았던 신태용 감독을 A대표팀 감독에 앉히는 모습이 마치 2014 브라질 월드컵때 2012 런던 올림픽 감독이었던 홍명보 감독을 앉히는 모습과 모양새가 너무도 흡사하구요. 최근 평가전에서 김영권, 장현수등등 일부 경기력에 논란이 많은 선수들을 계속해서 기용하는 모습까지 4년전 실패와 아픔(선수단 귀국후 공항에서 엿세례)을 그대로 되풀이 하려는건가? 싶을 정도로 4년전과 모습이 너무나도 흡사합니다.\n빙상연맹과 관련해서는 최근 많은 논란이 되고있고, 다른분들께서 많이 이야기해 주셨으니 더 이상 언급하지는 않겠습니다. 제가 하고 싶은 이야기는 이번일을 계기로 대한빙상연맹, 대한축구협회를 비롯한 각종 체육협회의 잘못된 비리, 부조리들을 철저하게 밝혀서 모든 스포츠에 있어서 감독선임부터 선수선발까지 모든 과정들이 인맥,파벌에 의하지 않고 공정하고 투명하게 이뤄질 수 있도록 힘써 주셨으면 합니다. 빙상 연맹 대한축구협회 각종 체육 협회 비리 철저 최근 동계 올림픽 김보름 박지우 선수 관련 논란거리 선수 개개인 떠나 이번 빙상 연맹 합리 행정 불신 동계 올림픽 폐막 다가오 러시아 열리 월드컵 축구 대회 열리 월드컵 시작 감독 선임 선수 선발 우려 목소리 아시아 최종 예선 기대 경기력 실망 모습 둘째 슈틸리케 감독 경질 리우 올림픽 감독 신태용 감독 대표 감독 앉히 모습 브라질 월드컵 런던 올림픽 감독 홍명보 감독 앉히 모습 모양새 최근 평가전 김영권 장현수 등등 일부 경기력 논란 선수 계속 기용 모습 실패 아픔 선수단 귀국 공항 세례 되풀이 모습 빙상 연맹 관련 최근 논란 이야기 언급 이야기 이번 계기 빙상 연맹 대한축구협회 각종 체육 협회 잘못 비리 부조리 철저 스포츠 감독 선임 선수 선발 과정 인맥 파벌 의하 공정 투명

 

3) category 텍스트 변환

추가로 현재 정수값으로 이루어진 category를 나중에 확인하기 쉽게 텍스트 형태로 바꿔주었다.

(원래 텍스트값이면 변환 필요 x)

 

0 인권/성평등
1 문화/예술/체육/언론
2 육아/교육

 

label = {'인건/성평등' : 0, '문화/예술/체육/언론' : 1, '육아/교육' : 2}
for (key, value) in label.items():
  a = train[train['category'] == value].index
  train.loc[a, 'category'] = key

 

4) 학습데이터 준비

 

df2 = pd.DataFrame(columns=['category','data'])
df2['category'] = '__label__' + train['category']
df2['data'] = train['data']

 

 category data
__label__육아/교육 신혼 부부 주택정책 보육 시설 국민 세금 일부 정책 마시 보편 국민 수긍 복지 정책...
__label__인건/성평등 학교 남자 울산 중학교 재학 학생 최근 양성 평등 글짓기 울산 울산 중학교 남중 여...
__label__문화/예술/체육/언론 빙상 연맹 대한축구협회 각종 체육 협회 비리 철저 최근 동계 올림픽 김보름 박지우 ...

.txt 파일로 저장

 

df2.to_csv(os.path.join(path,'labelingtrain.txt'), sep = '\t', index = False)

 

✔ category 값이 다음과 같이 __label__category이름 형식인, .txt 파일 이여야함.

(-> 모델 학습 시 txt파일로 들어가므로)

 


4. 모델 학습

 

model = fasttext.train_supervised(os.path.join(path, 'labelingtrain.txt'), wordNgrams=3, epoch=25, lr=0.35)
  • wordNgram : 단어 n-gram (모델의 성능을 향상할 수 있음. 감정 분석과 같이 어순이 중요한 분류 문제에 특히 중요) [1 ~ 5]
  • epoch : 에포크 수(각 예제가 표시되는 횟수) [5 ~ 50]
  • learning late : 학습률 (학습 속도를 높이거나 낮춤) [0.1 ~ 1.0]

5. Test ⭐

 

model.predict('text')

 

model.predict('소년법 폐지해주세요 법 아래에서 보호')

(('__label__인건/성평등',), array([0.99880129]))

 

model.predict('방과후 유치원 어린이집 영어교육을 유지시켜주세요')

(('__label__육아/교육',), array([1.00001001]))

 

model.predict('축구장에 있는 천연 잔디좀 신경 써주세요!!')

(('__label__문화/예술/체육/언론',), array([0.60879034]))

 

 

➕ test 데이터 이용하여 평가

 

test = pd.read_csv(os.path.join(path, "test.csv"))

test['data'] = test['data'].str.replace(r'[-=+,#/\?:^$.@*\"※~&%ㆍ!』\‘|\<\>`\'…》]', " ", regex=True)
test['data'] = test['data'].str.replace(r'\t+', " ", regex=True)
test['data'] = test['data'].str.replace(r'[\n]+'," ", regex=True)
predictions = []
for line in test['data']:
  pred_label = model.predict(line, threshold=0.5)[0]
  predictions.append(pred_label)

6. 모델 저장

model.save_model(os.path.join(path,'model.bin'))

 

 

 


📍  모델 불러와서 사용 시, predict 함수에 문자열 토큰을 넣어줌

 

model = fasttext.load_model("model.bin")
for token in token_list:
	pred_label = model.predict(str(token))[0]
    pred_label = re.sub(r"[\(\)\'\,]", "", str(pred_label))
    pred_label = pred_label.lstrip('__label__')

 


 

 

💡 확장성

학습 속도는 빠르지만, 일반적인 학습보다 결괏값은 좋지 않음 ❌

 

1. loss='hs' 

model = fasttext.train_supervised(os.path.join(path, 'labelingtrain.txt'), **wordNgrams=3, epoch=25, lr=0.35, bucket=200000, dim=50, loss='hs'**)

loss='hs' : 계층적 소프트맥스, 훨씬 더 빠른 계산으로 소프트맥스를 근사화하는 손실 함수

 

2. loss=’ova’ 

model = fasttext.train_supervised(os.path.join(path, 'labelingtrain.txt'), **wordNgrams=3, epoch=25, lr=0.35, bucket=200000, dim=50, loss='hs'**)

loss=’ova’ : 여러 레이블을 처리하는 편리한 방법은 각 레이블에 대해 독립적인 이진 분류기를 사용

 

 

 


좋은 학습데이터만 있다면 (category와 data 잘 분리된), fasttext를 이용하여 여러 개의 카테고리를 가지는 다중 분류모델도 만들 수 있다.

 

 

댓글