본문 바로가기

머신러닝,딥러닝/자연어처리(NLP)

캐글 자연어처리(NLP) 튜토리얼 입문 2. 머신러닝 모델링 - 백터화

https://www.kaggle.com/c/word2vec-nlp-tutorial

지난 번에 했던 캐글 NLP 튜토리얼 이어서 하겠습니다! 

데이터를 정제한 뒤부터 이어지니깐 커널 돌려서 실행한 뒤에 따라서 해주시면 됩니다. 

이 포스팅은 박조은님의 인프런 '[NLP] IMDB 영화리뷰 감정 분석을 통한 파이썬 텍스트 분석과 자연어 처리' 강좌를 듣고 실습하며 따로 내용을 정리한 글입니다! 따라서, 강의 내용 + @ (추가적으로 공부한 내용 및 방법) 으로 구성됩니다! :)

 

출처: https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html

scikit-learn 의 기본 알고리즘을 보여주는 그림입니다. 

이번 모델링에서는 랜덤포레스트를 사용할 것입니다. 

 

랜덤 포레스트는 

https://ko.wikipedia.org/wiki/%EB%9E%9C%EB%8D%A4_%ED%8F%AC%EB%A0%88%EC%8A%A4%ED%8A%B8

 

랜덤 포레스트 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 기계 학습에서의 랜덤 포레스트(영어: random forest)는 분류, 회귀 분석 등에 사용되는 앙상블 학습 방법의 일종으로, 훈련 과정에서 구성한 다수의 결정 트리로부터 부류(분류) 또는 평균 예측치(회귀 분석)를 출력함으로써 동작한다. 랜덤 포레스트는 다수의 결정 트리들을 학습하는 앙상블 방법이다. 랜덤 포레스트는 검출, 분류, 그리고 회귀 등 다양한 문제에 활용되고 있다. 초기 랜덤 포레스트는 단일 트리를 확장할

ko.wikipedia.org

에 설명이 잘 나와 있습니다! 

 

랜덤 포레스트를 알기 위해선 우선, 결정 트리에 대한 이해가 필요합니다. 

결정 트리는 쉽게 말해 스무 고개 방식으로 피처를 찾고, 이를 결합하여 규칙 조건으로 만들어서 규칙 노드가 만들어 집니다. 하지만 많은 규칙이 있으며 분류를 결정하는 방식이 복잡해지고, 이는 과적합으로 이어지기 쉽습니다. 즉, 트리의 깊이가 길어질수록 결정 트리의 예측 성능은 저하될 가능성이 높습니다. 

 

따라서, 가능한 적은 결정 노드로 높은 예측 정확도를 가지려면 데이터를 분류할 때 최대한 많은 데이터 세트가 해당 분류에 속할 수 있도록 결정 노드의 규칙을 정해야 합니다. 이를 위해 최대한 균일하게 데이터 세트를 분할할 필요가 있습니다. 결정 노드는 정보 균일도가 높은 데이터 세트를 먼저 선택하도록 규칙 조건을 만듭니다. 이를 위한 대표적인 방법은 엔트로피를 이용한 정보 이득(Information Gain)지수와 지니 계수가 있습니다. 

 

엔트로피는 주어진 데이터 집합의 혼잡도, 다른 말로는 불확실성에 따른 정보 가치(=불확실성이 높을수록 정보 가치가 높다)라고도 볼 수 있을 겁니다. 데이터 집합에서 서로 다른 값들이 섞여 있으면 엔트로피가 높고(=불확실성이 높음, 예를 들어 한 주머니에 검은 공 10개, 흰 공 10개 들어있으면 검은 공 꺼낼 확률 0.5), 같은 값이 섞여 있으면 엔트로피가 낮습니다.(=불확실성이 낮다, 즉 한 주머니에 20개의 검은 공만 들어있고, 이 때 검은 공 꺼낼 확률 1.0)

 

정보이득 지수1에서 엔트로피 지수를 뺀 값입니다. 결정 트리는 이 정보 이득 지수로 분할 기준을 정합니다. 즉, 정보 이득이 높은 (=1-엔트로피 지수 가 큰 값 ; 엔트로피 지수가 낮아야 되는데 그러기 위해선 균일도가 높은 집합이어야 한다.) 속성을 기준으로 분할합니다.

 

(여기서) 지니계수는  다양한 값을 가질수록 평등하며 특정 값으로 쏠릴 경우에는 불평등한 값이 됩니다. 즉, 다양성이 낮을 수록 균일도가 높습니다. 1로 갈수록 균일도가 높으므로 지니 계수가 높은 속성을 기준으로 분할합니다. 

 

정리하자면,정 트리는 정보 이득 지수와 지니 계수가 둘 다 높은 속성을 찾아서 이를 기준으로 분할합니다. 사이킷런에서 구현한 DecisionTreeClassifier는 기본으로 지니 계수를 이용해 데이터 세트를 분할합니다. 

 

// 결정 트리는 여기까지만 이야기 하겠습니다. 

 

https://ko.wikipedia.org/wiki/%EA%B2%B0%EC%A0%95_%ED%8A%B8%EB%A6%AC_%ED%95%99%EC%8A%B5%EB%B2%95   

 

이후에는 위키피디아나 권철민 센세의 <파이썬 머신러닝 완벽가이드> 4장을 참고하시길! 참고로 이 책은 완전레알 강추!!! :)

 

출처: https://amueller.github.io/ml-training-intro/slides/01-supervised-learning.html#2

위 그림은 사이킷런 창시자님의 깃허브에서 가져온 글입니다! 

이 튜토리얼에서는 클렌징(=정제)한 리뷰 데이터를 벡터화 한것이 위 그림 좌측 상단의 Training Data가 되며 거기에 맞는 sentiment 칼럼(=0,1 긍부정이 적힌)이 Training Labels이 됩니다. 

 

이후 학습한 모델로 예측을 해주는데 이 때에도 Test Data 인 리뷰를 벡터화해준 뒤에 sentiment를 .predict 해줘야 합니다! 

이 모델 성능을 roc 커브로 확인할 겁니다!

 

출처: https://amueller.github.io/ml-training-intro/slides/01-supervised-learning.html#2

구체적인 코드로 보면 위와 같이 모델을 import 하여 객체화 시켜주고 거기에 달린 .fit() 안에다가 x,y 값을 넣어주면 끝! 

참...쉽죠..? :) 

 

 

코드 시작!

 

위에서 pipeline의 경우, 여러 가지 작업을 묶어서 할 수 있도록 해주는 라이브러리입니다.  cross-validation 과 GridSearch 과정을 하나로 만들어 주는게 pipeline의 가장 큰 장점입니다. 아쉽게도 이번 튜토리얼에서는 조은 센세가 다뤄주시지 않았어요 ㅠㅠ 

이는 제가 다른 스터디 자료에서 예제로 따로 만들어서 올리겠습니다! 

 

파이프라인 안에 카운터벡터가 들어있으니 그걸로 fit_transform 시키면 빈도수를 기반으로 벡터화가 진행됩니다.

 

리뷰를 벡터화한 피처를 살펴보았습니다!

 

n_estimators 는 결정 트리의 갯수를 지정합니다. 디폴트는 10개 입니다. 숫자가 클수록 더 좋은 성능을 기대할 수 있지만, 
계속 증가한다고 성능이 향상되는 것은 아닙니다. 또한, 늘릴수록 학습 수행 시간이 오래 걸립니다. 
n_jobs는 활용하는 cpu 코어의 수를 의미. -1이면 cpu 코어를 모두 다 사용한다는 뜻입니다.
보통 random_state는 어떠한 정수가 들어가는 걸 볼 수 있습니다. 이 숫자를 시드로 난수 생성기가 사용되는데 보통 0과 42를 많이 쓴다. 크게 중요한 건 아니고 그냥 이런 거구나 하고 읽고 넘어가시면 됩니다! 

random_state 는 https://scikit-learn.org/stable/glossary.html#term-random-state  참고

 

학습한 모델로 테스트 데이터의 감성 분석을 위해 테스트 데이터의 리뷰를 벡터화하고, 이를 predict하면 감성 분석이 마무리됩니다. 

 

이 다음으로는 제가 따로 tf-idf vector화를 이용해서 성능을 한 번 비교해보았습니다! (강의에는 없어요!)

 

코드는 몇 줄 바꾼 게 없습니다 :) 

 

피처를 봐도 앞에 10개는 달라지지 않았습니다. 

데이터프렝미에서 숫자가 좀 낮아진 것도 확인할 수 있습니다. 

 

아까 쓴 주석인데 제가 앞에서 언급한 책에서 발췌하고 random_state는 공식문서랑 구글링 해서 정리한 것입니다 :) 

 

잘 진행되다가 문제가 발생하게 됐는데요.

 

predict를 하는데 메모리 에러가 떠요... 

제 노트북 cpu i5-4200, 램은 8G 초저사양이라...그런거 같아요...

이를 해결하는 방법은...!!

 

이렇게 numpy의 array_split 시켜서 부분부분 predict 시키고 이를 리스트에 추가한 뒤 다시 numpy 형태로 concat 시켜주는 겁니다! (개인적으로 이 문제 해결할 때가 제일 기뻤네요 ㅎㅎ)

 

근데 tf-idf 벡터화를 해서 한 건데 별반 차이가 없네요...ㅠㅠ 

뭐가 문제였을까요...ㅠㅠ tf-idf sklearn API를 너무 강하게 믿었던 걸까요...ㅠㅠ 

 

다음 시간에는 딥러닝 word2vec 코드 실습으로 돌아오겠습니다.