카테고리 없음

[Python] AIFB 강의(텍스트 데이터 전처리)

agingcurve 2022. 7. 19. 14:09
반응형

형태소분석기 설치

In [9]:
# 한글 형태소 분석기인 konlpy 패키지를 설치합니다.
! pip install konlpy
Requirement already satisfied: konlpy in /usr/local/lib/python3.6/dist-packages (0.6.0)
Requirement already satisfied: lxml>=4.1.0 in /usr/local/lib/python3.6/dist-packages (from konlpy) (4.8.0)
Requirement already satisfied: numpy>=1.6 in /usr/local/lib/python3.6/dist-packages (from konlpy) (1.19.5)
Requirement already satisfied: JPype1>=0.7.0 in /usr/local/lib/python3.6/dist-packages (from konlpy) (1.3.0)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.6/dist-packages (from JPype1>=0.7.0->konlpy) (3.7.4.3)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
In [90]:
# mecab 태그 패키지를 가져오겠습니다.
from konlpy.tag import Mecab  
mecab = Mecab()
특수기호와 명사를 추출하는 함수를 정의합니다.
In [61]:
def extended_extraction (text):
    pos = mecab.pos(text)
    extended_list = []
    for i in range(len(pos)):
        #명사 : NP, NNB, NNP, NNG
        #특수기호 : SF, SY
        if pos[i][1] in('NP','NNB','NNP','NNG','SF','SY'):
            extended_list.append(pos[i][0])
    return extended_list
 

실습 학습용 1. 텍스트 분석 및 전처리

STEP 0. 데이터 가져오기

In [62]:
# 현재 디렉토리 확인 (실행금지)
import os
print(os.getcwd())
/aihub/workspace
In [63]:
# pandas 를 import 합니다.
import pandas as pd

# 데이터를 가져옵니다.
#df = pd.read_csv('/aihub/data/spam_data_binary.csv')
df = pd.read_csv('/aihub/workspace/spam_data_binary.csv')
In [64]:
# head 함수를 이용해 데이터를 확인해봅니다. (띄어쓰기가 되어 있지 않음을 알 수 있어요.)
df.head(10)
Out[64]:
textlabel0123456789
[Web발신]통화중이시네요신★청하신▶상♣품승♡인나셨습니다.톡문의바랍니다.ka톡[sun] spam
[Web발신]통화중이시네요신★청하신▶상♣품승♡인나셨습니다.톡문의바랍니다.ka톡[kd] spam
[국외발신][투]▼복권방프젝밴드band.us/n/aazKUk거짓도없는조-합▲월수익책... spam
[Web발신](광고)ⓝhe-.com신규OO@@올인~%O에수O에수무료거부 spam
[Web발신][투](광고)ⓝhe-.com신규OO@@올인~%O에수O에수무료거부 spam
[Web발신](광고)jⓓq-.com신규OO@@올인~%O에수O에수무료거부 spam
[국제발신]▼복권방프젝밴드band.us/n/aazKUk거짓도없는조-합▲월수익책임지겠... spam
[국외발신]▼복권방프젝밴드band.us/n/aazKUk거짓도없는조-합▲월수익책임지겠... spam
언니안녕하세요.요즘잘지내세요.어디서일해요 ham
가게서소주한잔먹고갈게.빨리들어갈게 ham
In [65]:
# info() 함수를 이용해서 데이터의 정보를 확인합니다.
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 30000 entries, 0 to 29999
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   text    29985 non-null  object
 1   label   30000 non-null  object
dtypes: object(2)
memory usage: 468.9+ KB
In [66]:
# label 데이터 분포를 확인합니다.
df['label'].value_counts()
Out[66]:
spam    19132
ham     10868
Name: label, dtype: int64

STEP 1. 데이터 클렌징

실습 1-1. 불필요한 문자열 삭제

(실습) str.replace() 함수를 활용해서 학습에 불필요한 문자열을 삭제 하고, head() 활용해 결과를 확인 합니다.
MMS스팸신고, KISA신고메시지 : 스팸신고할때 자동으로 붙여지는 문자열[Web발신][WEB발신] : 핸드폰이 아닌 시스템에서 발송되는 문자에 자동으로 붙여지는 문자열head 함수를 활용하여 처리 결과를 확인 합니다
In [67]:
# df['text'] = pd.DataFrame(df['text'].str.replace('KISA신고',''))
#실습코드
df['text'] = pd.DataFrame(df['text'].str.replace('MMS스팸신고',''))
df['text'] = pd.DataFrame(df['text'].str.replace('\[Web발신\]',''))
df['text'] = pd.DataFrame(df['text'].str.replace('\[WEB발신\]',''))
df['text'] = pd.DataFrame(df['text'].str.replace('KISA신고메시지',''))
df['text'] = pd.DataFrame(df['text'].str.replace('KISA신고',''))
df['text'].head()
Out[67]:
0            통화중이시네요신★청하신▶상♣품승♡인나셨습니다.톡문의바랍니다.ka톡[sun]
1             통화중이시네요신★청하신▶상♣품승♡인나셨습니다.톡문의바랍니다.ka톡[kd]
2    [국외발신][투]▼복권방프젝밴드band.us/n/aazKUk거짓도없는조-합▲월수익책...
3                     (광고)ⓝhe-.com신규OO@@올인~%O에수O에수무료거부
4                  [투](광고)ⓝhe-.com신규OO@@올인~%O에수O에수무료거부
Name: text, dtype: object

실습 1-2. 결측치 제거

(실습) dropna() 함수를 활용해서 결측치 데이터를 제거 하고, info() 활용해 결과를 확인 합니다.
In [84]:
# (옵션) axis=0 : 행을 제거한다는 의미로 default가 axis =0 임.
#실습코드
df = df.dropna(axis=0)
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 25096 entries, 0 to 25095
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   text    25096 non-null  object
 1   label   25096 non-null  object
dtypes: object(2)
memory usage: 588.2+ KB

실습 1-3. 중복값 제거

(실습) drop_duplicates() 함수를 활용해서 중복 데이터를 삭제 하고, info() 활용해 결과를 확인 합니다.
In [85]:
#(옵션) keep='first' 중복제거시 남기는 행을 뜻하고, ignore_index=True 는 index 재설정 한다는 의미입니다.
#실습코드
df = df.drop_duplicates(keep="first", ignore_index=True)
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 25096 entries, 0 to 25095
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   text    25096 non-null  object
 1   label   25096 non-null  object
dtypes: object(2)
memory usage: 392.2+ KB

STEP 2. 토큰화 및 Dictionary 생성

토큰화 하는 방법은 명사만 이용할 수도 있고, 명사 외 다른 형태소를 이용 할 수도 있습니다.실습에서는 명사와 특수기호를 모두 이용하는 방법 실습 하도록 하겠습니다.
전체 문장에서 명사와 특수기호를 추출하여 dic을 만들어 봅니다. {key = 명사토큰, value = 정수 형태}

실습 2-1. 단어의 토큰화

(실습) 문장을 사전에 정의한 extended_extraction() 함수를 활용해서 토큰화 합니다.
In [86]:
token_list = []
for text in df['text']:
    token_list.extend(extended_extraction(text))

print(token_list[:20])
['통화', '중', '요신', '★', '청', '▶', '상', '♣', '품', '승', '♡', '.', '문', '.', '톡', '통화', '중', '요신', '★', '청']

실습 2-2. 내림 차순 정렬

In [87]:
# collections모듈의 Counter클래스를 import 합니다.
from collections import Counter
(실습) 토큰의 출현 빈도로 내림차순 정렬합니다
In [88]:
vocab_collection = Counter(token_list)
vocab = vocab_collection.most_common(len(vocab_collection))
print(vocab[:20])
[('.', 26575), ('광고', 9798), ('무료', 8176), ('거부', 7564), ('!', 6917), ('-', 3791), ('~', 3160), ('"', 2866), ('?', 2337), ('%', 2328), ('_', 2237), ('정보', 2180), ('월', 1807), ('수신', 1795), ('확인', 1783), ('수', 1782), ('수익', 1653), ('★', 1600), ('*', 1424), ('월일', 1358)]

실습 2-3. Dictionary를 생성

(실습) Dictionary를 생성 후 nouns_dic 변수에 저장합니다. key = 토큰, valeu = 숫자
In [89]:
extended_dic = {}

i=0
for (word, frequency) in vocab:
    i += 1
    extended_dic[word] = i

    
# dict 생성 결과 확인
print(extended_dic['통화'])
print(extended_dic['안녕'])
print(extended_dic['광고'])
print(extended_dic['무료'])
322
25
2
3

실습 2-4 Dictionary 사이즈를 확인 후 데이터 저장

Dictionary 사이즈를 확인해봅니다.word_size 는 임베딩 레이어 설계시 중요한 요소이니, 꼭 확인 및 저장이 필요합니다.
In [74]:
word_size = len(extended_dic)
print("word_size : ", word_size)
word_size :  24635
(실습) pickle 모듈을 import하여 dic을 nouns_dic이라는 이름으로 저장합니다.해당 dictionary를 이용하여, 학습데이터 인코딩을 시행 합니다.
In [75]:
import pickle
file=open("extend_dic","wb") 
pickle.dump(extended_dic, file) 
file.close()

STEP 3. 스팸 데이터 [x 값] 인코딩

STEP2에서 만든 dictionary를 이용해 스팸 데이터를 숫자열로 변환하는 인코딩 작업을 진행합니다.예제에서는 학습 데이터들 중에서 명사와 특수기호를 모두 추출하여 숫자로 인코딩 합니다.
(실습) 학습 데이터를 모두 토큰화 하고, 숫자로 변환을 해 보도록 합니다.
In [76]:
x = list(map(lambda text: list(map(lambda x : extended_dic[x], extended_extraction(text))) , df['text']))

STEP 4. 패딩

딥러닝 학습을 위해서는 학습데이터 길이를 동일하게 맞춰야 합니다. 이때 빈칸에 0을 추가하여 길이를 맞춥니다.keras 전처리 함수 중 pad_sequences 함수를 이용해서 패딩 작업을 하려고 합니다.길이는 학습 데이터의 최대 값으로 하도록 하겠습니다. (이는 선택사항이며, 개발자가 학습효율이 높은 길이로 변경 가능합니다.)

실습 4-1 학습데이터의 최대 길이를 구합니다.

(실습) 학습 데이터의 최대 길이를 구해주세요.
In [77]:
max_length = 0
max_length = max(map(len, x))
print("max_length : ", max_length)
max_length :  53

실습 4-2 패딩

In [91]:
# pad_sequences를 import합니다.
from tensorflow.keras.preprocessing.sequence import pad_sequences
(실습) pad_sequences를 활용하여, 4-1에서 구한 최대 길이로 padding 처리 후, padded_x에 저장 합니다.
In [92]:
padded_x = pad_sequences(x, max_length)
In [93]:
# 10개의 결과를 출력해 잘 변환이 되었는지 확인합니다.
print(padded_x[0:10])
[[   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0  322   46 5142   18
   775   26  633  349 1273 1503  153    1  100    1  184]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0  322   46 5142   18
   775   26  633  349 1273 1503  153    1  100    1  184]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0  173   91  445   27   99
  3867  223    1 2016  446    6 1034  648   13   17    1]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     2 1352  303  217 1353 2118  301   16   16    3    4]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0  445
     2 1352  303  217 1353 2118  301   16   16    3    4]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     2 4403  303  217 1353 2118  301   16   16    3    4]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0  171   91   27   99
  3867  223    1 2016  446    6 1034  648   13   17    1]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0  173   91   27   99
  3867  223    1 2016  446    6 1034  648   13   17    1]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0  829   25    1    1  666   30]
 [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0    0    0    0    0    0    0    0
     0    0    0    0    0    0    0 2119 3472  743    1]]

STEP 5. 라벨 데이터 인코딩

라벨링 데이터 (y)도 spam, ham 문자입니다. 모델이 처리 할 수 있도록 숫자 형태로 변환이 필요합니다.dataframe의 apply() 함수와 lambda를 이용해 해결 하겠습니다. https://wikidocs.net/22804apply() ? DataFrame의 칼럼에 복잡한 연산을 vectorizing할 수 있게 해주는 함수

lambda <매개변수1>, <매개변수2>... : 매개변수를 이용한 식(if 문이 나올 수 있음)

실습 5-1 라벨 데이터 인코딩

(실습) apply()와 lambda를 활용하여, df의 label 데이터를 인코딩 후 y에 저장 합니다. spam은 1로 ham은 0 으로 인코딩 합니다.
In [94]:
# (옵션) axis = 1 (열 방향으로 연산을 적용)
y = df.apply(lambda r: 0 if r.label == 'ham' else 1 if r.label =='spam' else r.label, axis = 1)
5-2) value_counts() 이용해서, y값의 결과를 확인합니다.

실습 5-2 인코딩 결과 확인

(실습) value_counts() 이용하여 변환 결과를 count합니다.
In [95]:
y.value_counts()
Out[95]:
1    15417
0     9679
dtype: int64

STEP 6. 데이터셋 나누기 및 저장하기

sklearn 의 함수를 이용하여, 데이터 셋을 나누고 저장합니다.
In [96]:
# 사이킷런의 train_test_split 을 import 합니다.
from sklearn.model_selection import train_test_split

실습 6-1. 데이터 셋 나누기

(실습) train_test_split 을 이용해서 학습과 검증에 사용할 데이터 셋을 나누어 보겠습니다.
In [97]:
# 학습셋 : X_train, y_train
# 검증셋 : X_test, y_test
## test_size를 0.2로 해서 데이터 셋을 나누어 보세요

X_train, X_test, y_train, y_test = train_test_split(padded_x, y, test_size = 0.2, random_state = 1)

실습 6-2. 데이터의 shape을 확인

(실습) shape 함수를 이용해서 만들어진 X_train, y_train, X_test, y_test shape을 확인해 봅니다.
In [98]:
print("X_train shape:", X_train.shape  )
print("y_train shape:", y_train.shape   )
print("X_test  shape:", X_test.shape  )
print("y_test  shape:", y_test.shape  )
X_train shape: (20076, 53)
y_train shape: (20076,)
X_test  shape: (5020, 53)
y_test  shape: (5020,)
numpy의 save 함수를 이용하여, 전처리된 데이터를 저장합니다.
In [99]:
import numpy as np

np.save("extended_X_train", arr = X_train)
np.save("extended_y_train", arr = y_train)
np.save("extended_X_test", arr = X_test)
np.save("extended_y_test", arr = y_test)
In [ ]: