[빅데이터 직무연구회] 7회차 모임 정리
Chapter 7. 텍스트 데이터 다루기
텍스트 데이터는 주로 글자가 연결된 문자열로 표현된다. 텍스트 데이터의 길이는 서로 같은 경우는 거의 없다. 이런 특성은 이제까지 본 수치형 특성과 매우 다르므로 머신러닝 알고리즘에 적용하기 전에 전처리를 해야 한다.
7.1 문자열 데이터 타입
문자열 데이터는 네 종류가 있다
- 범주형 데이터
- 빨강, 녹색, 파랑, 노랑, 검정, 흰색, 자주, 분홍 중 하나를 선택
- 범주에 의미를 연결시킬 수 있는 임의의 문자열
- 철차를 틀리거나, 회색이나 쥐색처럼 다르게 쓸 수 있다. 이런 데이터를 범주형 변수로 인코딩하려면 가장 보편적인 값을 선택하든지, 애플리케이션에 맞게 이런 응답을 포용할 수 있는 범주를 저으이하는게 최선이다. "녹색과 빨강 줄무늬" 같은 응답은 "여러가지 색" 범주에 할당하거나, 다른 것으로 인코딩할 수 없는 값은 "그 외" 라고 하면 된다.
- 범주형 변수로 받을 수 있는 것은 직접 입력받지 않는 것을 권장한다.
- 구조화된 문자열 데이터
- 주소, 장소, 사람 이름, 날짜, 전화번호, 식별번호처럼 일정한 구조를 가지는 것
- 텍스트 데이터
- 자유로운 형태의 절과 문장으로 구성된 것.
- 트윗, 채팅, 호텔 리뷰, 셰익스피어 작품, 위키백과 문서 등
7.2 예제 애플리케이션: 영화 리뷰 감성 분석
이 데이터셋은 양성 클래스와 음성 클래스를 같은 비율로 수집했다. 따라서 양성과 음성 레이블의 수가 같다.
우리가 풀려는 문제는, 리뷰가 하나 주어졌을 때 이 리뷰의 텍스트 내용을 보고 '양성'인지 '음성'인지 구분하는 것이다. 전형적인 이진 분류 문제이다. 텍스트 데이터는 머신러닝 모델이 다룰 수 있는 형태가 아니다. 텍스트의 문자열 표현을 머신러닝 알고리즘에 적용할 수 있도록 수치 표현으로 바꿔야 한다.
7.3 텍스트 데이터를 BOW로 표현하기
BOW(bag of words)는 가장 간단하지만 효과적이면서 널리 쓰이는 방법이다. 장, 문단, 문장, 서식 같은 입력 텍스트의 구조 대부분을 잃는다. 각 단어가 이 말뭉치에 있는 텍스트에 얼마나 많이 나타나는지만 헤아린다. 구조와 상관없이 단어의 출현 횟수만 센다. 이를 텍스트를 담는 가방(bag)으로 생각할 수 있다.
BOW 표현은 다음 세 단계를 거친다.
- 토큰화(tokenization) : 각 문서를 문서에 포함된 단어(토큰)로 나눈다. 예를 들어 공백이나 구두점 등을 기준으로 분리한다.
- 어휘 사전 구축 : 모든 문서에 나타난 모든 단어의 어휘를 모으고 번호를 매긴다. (알파벳 순서)
- 인코딩 : 어휘 사전의 단어가 문서마다 몇 번이나 나타나는지를 헤아린다.
"This is how you get ants." 문자열을 처리하는 과정은 다음과 같다.
(토큰화) => ['this', 'is', 'how', 'you', 'get', 'ants']
(어휘 사전 구축) => ['aardvark', 'amsterdam', 'ants', ..., 'you', 'your', 'zyxst']
(희소 행렬 인코딩) => [0(aardvark), ..., 0, 1(ants), 0, ..., 0, 1(get), 0, ..., 0, 1(you), 0, ..., 0(zyxst)]
이 수치 표현은 전체 데이터셋에서 고유한 각 단어를 특성으로 가진다. 원본 문자열에 있는 단어의 순서는 BOW 특성 표현에서 완전히 무시된다.
7.3.1 샘플 데이터에 BOW 적용하기
"The fool doth think he is wise," 은 첫 번째 행으로 나타난다. 어휘 사전의 첫 번째 단어 "be"가 0번 나온다. 두 번째 단어 "but"도 0번, 세 번째 단어 "doth"는 1번 나오는 식이다.
7.3.2 영화 리뷰에 대한 BOW
7.4 불용어
의미 없는 단어를 제거하는 또 다른 방법이다. 너무 빈번하여 유용하지 않은 단어를 제외하는 것이다. 두 가지 방식이 있다. 언어별 불용어(stopword) 목록을 사용하는 것과 너무 자주 나타나는 단어를 제외하는 것이다. scikit-learn은 feature_extraction.text 모듈에 영어의 불용어를 가지고 있다.
stop_wrods="english" 라고 지정하면 내장된 불용어를 사용한다. 데이터셋에서 특성이 27,271 - 26,966 = 305개가 줄었다. 그리드 서치를 다시 적용해보자. 특성 305개를 제외했다고 성능이나 모델 해석이 나아진 것 같지는 않다. 고로 이 목록을 사용하는 게 도움이 되지 않는다.
고정된 불용어 목록은 모델이 데이터셋만 보고 불용어를 골라내기 어려운 작은 데이터셋에서 도움이 된다. 다른 방식으로는 CountVectorizer의 max_df 옵션을 지정하여 자주 나타나는 단어를 제거하고, 특성의 개수와 성능에 어떻게 영향을 주는지 확인하다.
7.5 tf-idf로 데이터 스케일 변경하기
N은 훈련 세트에 있는 문서의 개수
Nw는 단어 w가 나타난 훈련 세트 문서의 개수
tf(단어 빈도수)는 단어 w가 대상 문서 d(변환 또는 인코딩하려는 문서)에 나타난 횟수
두 파이썬 클래스 모두 tf-idf 계산 뒤 L2 정규화(L2 normalization)를 적용한다. 유클리디안 노름(euclidean norm)이 1이 되도록 각 문서 벡터의 스케일을 바꾼다. 스케일이 바뀐 벡터는 문서의 길이(단어의 수)에 영햐을 받지 않는다.
tf-idf는 어떤 단어가 가장 중요한지도 알려준다. 문서를 구별하는 단어를 찾는 방법임에도 완전히 비지도 학습이다. 따라서 '긍정적인 리뷰'와 '부정적인 리뷰' 레이블과 꼭 관계있지 않다는 게 중요하다.
tf-idf 가 낮은 특성은 전체 문서에 걸쳐 매우 많이 나타나거나, 조금씩만 사용되거나, 매우 긴 문서에서만 사용된다. tf-idf 가 높은 특성은 어떤 쇼나 영화를 나타내는 경우가 많다.
idf 값이 낮은 단어, 즉 자주 나타나서 덜 중요하다고 생각되는 단어들은 idf_ 속성에 저장되어 있다. 대부분 영어의 불용어다. "good", "great", "bad"도 매우 자주 나타나는 단어라 감정 분석에는 매우 중요하지만, tf-idf로 봤을 때는 덜 중요한 단어라고 분류된다.
7.6 모델 계수 조사
로지스틱 회귀 모델이 실제로 이 데이터에서 무엇을 학습했는지 자세히 살펴보자. 가장 큰 값의 계수와 해당 단어를 확인해보자.
왼쪽의 음수 계수는 모델에서 부정적인 리뷰를 의미하는 단어에 속한다. 오른쪽 양수 계수는 긍정적인 리뷰의 단어에 해당한다. "worst", "disappointment", "laughable"는 부정적인 리뷰이다. 반면, "excellent", "wonderful", "enjoyable", "refreshing"는 긍정적인 리뷰임을 말해준다.
"bit", "job", "today" 같은 단어들은 조금 덜 명확하지만 아마도 "good job", "best today" 같은 구절의 일부로 보인다.
7.7 여러 단어로 만든 BOW(n-그램)
BOW 표현 방식은 단어의 순서가 완전히 무시된다는 큰 단점이 있다. 의미가 완전히 반대인 두 문자열 "it's bad, not good at all" 과 "it's good, not bad at all"이 완전히 동일하게 변환된다. BOW 표현 방식을 사용할 때 문맥을 고려하는 방법이 있다.
토큰 하나의 횟수만 고려하지 않고 옆에 있는 두세 개의 토큰을 함께 고려하는 방법이다.
토큰 하나를 유니그램(unigram), 토큰 두 개를 바이그램(bigram), 세 개를 트라이그램(trigram)이라고 한다. 일반적으로 연속된 토큰을 n-그램(n-gram)이라고 한다. CounterVectorizer와 TfidfVectorizer는 ngram_range 매개변수에 특성으로 고려할 토큰의 범위를 지정할 수 있다. 매개변수의 입력값은 튜플이다. 연속된 토큰의 최소 길이와 최대 길이다,
n-그램이 클수록, 특성의 개수가 많아지며 구체적인 특성이 많아져 과대적합될 가능성이 있다. 그리드 서치로 최적의 n-그램 범위를 찾을 수 있다.
유니그램 모델에서는 없던 단어인 "worth"가 들어간 흥미로운 특성이 있다. "not worth"는 부정적인 리뷰를 의미한다. 그러나 "ㅇefinitely worth"와 "well worth"는 긍정적인 리뷰를 암시한다. 문맥을 파악할 수 있게 됐다.
7.8 고급 토큰화, 어간 추출, 표제어 추출
7.8.1 (한국어판 부록) KoNLPy를 사용한 영화 리뷰 분석
데이터셋은 한글로 된 영화 리뷰 20만개를 모은 <Naver sentiment movie corpus v1.0> (https://github.com/e9t/nsmc/) 을 사용한다. KoNLPy와 CountVectorizer 을 함께 사용해 감성 분서글 할 수 있다.
macOS 에서는 KoNLPy의 자바 기반의 태그 클래스가 호환되지 않는다. C++ 기반의 Mecab 태그 클래스를 사용한다. Mecab을 사용하려면 konlpy를 설치한 후 추가적인 설치가 필요하다. Mecab은 윈도우를 지원하지 않는다. KoNLPy의 설치 페이지(http://konlpy.org/ko/latest/install) 를 참고한다.
7.9 토픽 모델링과 문서 군집화
토픽 모델링(topic modeling)은 텍스트 데이터에 자주 적용하는 특별한 기법이다. 비지도 학습으로 문서를 하나 또는 그 이상의 토픽으로 할당하는 작업을 통칭한다. '정치', '스포츠', '금융' 등의 토픽으로 묶을 수 있는 뉴스 데이터가 좋은 예다. 문서가 둘 이상의 토픽을 가질 수 있다면 이는 3장에서 본 분해 방법과 관련이 있다.
학습된 각 성분은 하나의 토픽에 해당하며 문서를 표현한 성분의 계수는 문서가 어떤 토픽에 얼마만큼 연관되어 있는지를 말해준다. 잠재 디리클레 할당(Latent Dirichlet Allocation, LDA)이라고 하는 특정한 성분 분해 방법을 말한다.
7.9.1 LDA
LDA 모델은 함께 자주 나타나는 단어의 그룹(토픽)을 찾는 것이다. LDA는 각 문서에 토픽의 일부가 혼합되어 있다고 간주한다. 머신러닝에서 토픽은 일상에서의 "주제"가 아니라, 의미가 있든 없든 PCA나 NMF로 추출한 성분에 가까운 것이다. LDA의 토픽에 의미가 있다하더라도,일상 주제라고 부르는 것은 아니다.
영화 리뷰 데이터셋에 적용해보자. 텍스트 문서에 대하 비지도 학습 모델에서 분석의 결과가 왜곡되지 않으려면 자주 나타나는 단어를 제거하는 것이 좋다. NMF의 성분과 비슷하게 토픽은 어떤 순서를 가지고 있지 않다. 토픽의 수를 바꾸면 모든 토픽이 바뀌게 된다. 기본 학습 방법(online) 대신 조금 느리지만 성능이 더 나은 batch 방법을 사용하고 모델 성능을 위해 max_iter 값을 증가시킨다.
더 구체적일 수록, 해석하기가 더 어렵다. 중요도가 높은 토픽 중 거의 불용어에 가깝고 약간 부정적 경향의 단어인 "didn thought" 이다. 토픽 16 ("worst awful") 은 확실히 부정적이다.
LDA가 장르와 점수라는 두 종류의 큰 토픽과 어디에도 속하지 않는 토픽 몇 개를 더 찾았다. 대부분의 리뷰가 특정 영화에 대한 의견이거나 평가 점수를 합리화하거나 강조하기 위한 댓글이라는 사실은 재미있는 발견이다.
LDA와 같은 토픽 모델은 레이블이 없거나, 여기서처럼 레이블이 있더라도 큰 규모의 텍스트 말뭉치를 해석하는 데 좋은 방법이다. LDA는 확률적 알고리즘이기 때문에 random_state 매개변수를 바꾸면 결과가 많이 달라진다.
비지도 학습에서 내린 결론은 각 토픽에 해당하는 문서를 직접 보고 직관을 검증하는게 좋다. LDA.transform 메서드에서 만든 토픽이 지도 학습을 위한 압축된 표현으로 사용될 수도 있다. 특히 훈련 샘플이 적을 때 유용하다.
7.10 요약 및 정리
'인공지능' 카테고리의 다른 글
[빅데이터 직무연구회] 8회차 모임 정리 (0) | 2018.06.26 |
---|---|
[빅데이터 직무연구회] 7회차 모임 정리 - 소스 (0) | 2018.06.26 |
[빅데이터 직무연구회] 6회차 모임 정리 (2) (0) | 2018.06.06 |
[빅데이터 직무연구회] 6회차 모임 정리 (1) (0) | 2018.06.06 |
[빅데이터 직무연구회] 5회차 모임 예제 소스 (3) (0) | 2018.05.19 |
댓글