CountVectorizer로 텍스트 데이터 벡터화

워드 클라우드

  • 단어의 빈도수 데이터를 가지고 있을 때 이용할 수 있는 시각화 방법
  • 단순히 빈도수를 표현하기보다는 상관관계나 유사도 등으로 배치하는 게 더 의미 있기 때문에 큰 정보를 얻기는 어렵다.
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
# %matplotlib inline 설정을 해주어야지만 노트북 안에 그래프가 디스플레이 된다.
%matplotlib inline

def displayWordCloud(data = None, backgroundcolor = 'white', width=800, height=600 ):
    wordcloud = WordCloud(stopwords = STOPWORDS, 
                          background_color = backgroundcolor, 
                         width = width, height = height).generate(data)
    plt.figure(figsize = (15 , 10))
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.show() 
# 학습 데이터의 모든 단어에 대한 워드 클라우드를 그려본다.
%time displayWordCloud(' '.join(clean_train_reviews))

png

CPU times: user 24.9 s, sys: 1.07 s, total: 26 s
Wall time: 27.7 s

# 테스트 데이터의 모든 단어에 대한 워드 클라우드를 그려본다.
%time displayWordCloud(' '.join(clean_test_reviews))

png

CPU times: user 23.4 s, sys: 906 ms, total: 24.3 s
Wall time: 25.1 s

# 단어 수
train['num_words'] = clean_train_reviews.apply(lambda x: len(str(x).split()))
# 중복을 제거한 단어 수
train['num_uniq_words'] = clean_train_reviews.apply(lambda x: len(set(str(x).split())))
# 첫 번째 리뷰에 
x = clean_train_reviews[0]
x = str(x).split()
print(len(x))
x[:10]

219

['stuff',
'go',
'moment',
'mj',
'start',
'listen',
'music',
'watch',
'odd',
'documentari']

import seaborn as sns

fig, axes = plt.subplots(ncols=2)
fig.set_size_inches(18, 6)
print('리뷰 별 단어 평균값 :', train['num_words'].mean())
print('리뷰 별 단어 중간값', train['num_words'].median())
sns.distplot(train['num_words'], bins=100, ax=axes[0])
axes[0].axvline(train['num_words'].median(), linestyle='dashed')
axes[0].set_title('리뷰 별 단어 수 분포')

print('리뷰 별 고유 단어 평균값 :', train['num_uniq_words'].mean())
print('리뷰 별 고유 단어 중간값', train['num_uniq_words'].median())
sns.distplot(train['num_uniq_words'], bins=100, color='g', ax=axes[1])
axes[1].axvline(train['num_uniq_words'].median(), linestyle='dashed')
axes[1].set_title('리뷰 별 고유한 단어 수 분포')

리뷰 별 단어 평균값 : 119.52356
리뷰 별 단어 중간값 89.0
리뷰 별 고유 단어 평균값 : 94.05756
리뷰 별 고유 단어 중간값 74.0

Text(0.5,1,'리뷰 별 고유한 단어 수 분포')

png

Bag-of-words model - Wikipedia

다음의 두 문장이 있다고 하자,

(1) John likes to watch movies. Mary likes movies too.
(2) John also likes to watch football games.

위 두 문장을 토큰화하여 가방에 담아주면 다음과 같다.

[
    "John",
    "likes",
    "to",
    "watch",
    "movies",
    "Mary",
    "too",
    "also",
    "football",
    "games"
]

그리고 배열의 순서대로 가방에서 각 토큰이 몇 번 등장하는지 횟수를 세어준다.

(1) [1, 2, 1, 1, 2, 1, 1, 0, 0, 0]
(2) [1, 1, 1, 1, 0, 0, 0, 1, 1, 1]

=> 머신러닝 알고리즘이 이해할 수 있는 형태로 바꿔주는 작업이다.

단어 가방을 n-gram을 사용해 bigram으로 담아주면 다음과 같다.

[
    "John likes",
    "likes to",
    "to watch",
    "watch movies",
    "Mary likes",
    "likes movies",
    "movies too",
]

=> 여기에서는 CountVectorizer를 통해 위 작업을 한다.

사이킷런의 CountVectorizer를 통해 피처 생성

  • 정규표현식을 사용해 토큰을 추출한다.
  • 모두 소문자로 변환시키기 때문에 good, Good, gOod이 모두 같은 특성이 된다.
  • 의미 없는 특성을 많이 생성하기 때문에 적어도 두 개의 문서에 나타난 토큰만을 사용한다.
  • min_df로 토큰이 나타날 최소 문서 개수를 지정할 수 있다.
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.pipeline import Pipeline

# 튜토리얼과 다르게 파라메터 값을 수정
# 파라메터 값만 수정해도 캐글 스코어 차이가 크게 남
vectorizer = CountVectorizer(analyzer = 'word', 
                             tokenizer = None,
                             preprocessor = None, 
                             stop_words = None, 
                             min_df = 2, # 토큰이 나타날 최소 문서 개수
                             ngram_range=(1, 3),
                             max_features = 20000
                            )
vectorizer

CountVectorizer(analyzer='word', binary=False, decodeerror='strict',
dtype=, encoding='utf-8', input='content',
lowercase=True, max
df=1.0, maxfeatures=20000, mindf=2,
ngramrange=(1, 3), preprocessor=None, stopwords=None,
stripaccents=None, tokenpattern='(?u)\b\w\w+\b',
tokenizer=None, vocabulary=None)

# 속도 개선을 위해 파이프라인을 사용하도록 개선
# 참고 : https://stackoverflow.com/questions/28160335/plot-a-document-tfidf-2d-graph
pipeline = Pipeline([
    ('vect', vectorizer),
])  
%time train_data_features = pipeline.fit_transform(clean_train_reviews)
train_data_features

CPU times: user 31.9 s, sys: 829 ms, total: 32.8 s
Wall time: 32.8 s

<25000x20000 sparse matrix of type ''
with 2762268 stored elements in Compressed Sparse Row format>

train_data_features.shape

(25000, 20000)

vocab = vectorizer.get_feature_names()
vocab[:10]

['aag',
'aaron',
'ab',
'abandon',
'abbey',
'abbi',
'abbot',
'abbott',
'abc',
'abduct']

# 벡터화된 피처를 확인해 봄
import numpy as np
dist = np.sum(train_data_features, axis=0)

for tag, count in zip(vocab, dist):
    print(count, tag)

pd.DataFrame(dist, columns=vocab)

[[26 48 22 ..., 59 40 23]] aag

aag aaron ab abandon abbey abbi abbot abbott abc abduct ... zombi bloodbath zombi film zombi flick zombi movi zone zoo zoom zorro zu zucker
0 26 48 22 288 24 30 29 30 125 55 ... 23 52 37 89 161 31 71 59 40 23

1 rows × 20000 columns

pd.DataFrame(train_data_features[:100].toarray(), columns=vocab).head()
aag aaron ab abandon abbey abbi abbot abbott abc abduct ... zombi bloodbath zombi film zombi flick zombi movi zone zoo zoom zorro zu zucker
0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0

5 rows × 20000 columns

강의에 등록된 질문이 없습니다. 궁금한 부분이 있으면 주저하지 말고 무엇이든 물어보세요.