book.naver.com/bookdb/book_detail.nhn?bid=16238302
*해당 글은 학습을 목적으로 위의 도서 내용 중 일부 내용만을 요약하여 작성한 포스팅입니다.
상세한 내용 및 전체 내용 확인을 원하신다면 도서 구매를 추천드립니다.
텍스트 분석 (텍스트 마이닝)
NLP와 텍스트 분석의 차이
- NLP는 머신이 인간의 언어를 이해하고 해석하는 데 중점을 둔다.
- 텍스트 분석은 비정형 텍스트에서 의미있는 정보를 추출하는 것에 중점을 둔다.
*엄밀히 따지면 다른 개념이지만, 머신러닝이 보편화되며 NLP와 텍스트 마이닝을 구분하는 것이 의미가 없어졌다.
텍스트 분석의 종류
- 텍스트 분류 : 문서가 특정 분류 또는 카테고리에 속하는 것을 예측하는 기법
- 감성 분석 : 텍스트에서 나타나는 주관적인 요소를 분석하는 기법
- 텍스트 요약 : 텍스트 내의 중요한 주제나 중심 사상을 추출하는 기법
- 텍스트 군집화와 유사도 측정 : 비슷한 유형의 문서에 대해 군집화를 수행하는 기법
텍스트 분석
- 비정형 데이터인 텍스트를 분석하는 것
- 순서는 다음과 같이 진행된다.
- 텍스트 전처리 (클렌징, 대소문자 변경, 특수문자 삭제, 토큰화, 스톱웨드 제거 등)
- 피처 벡터화 및 추출 : 텍스트 데이터를 숫자형 피처 데이터로 변환하는 것. (BOW, Word2Vec 등)
- ML 모델 수립 및 학습, 예측, 평가
NLTK
- 파이썬 기반의 텍스트 분석 패키지
- 방대한 데이터 셋과 서브 모듈, 다양한 데이터 셋을 지원해 오래전부터 파이썬의 대표 NLP 패키지였다.
- 하지만 수행 성능과 정확도, 신기술, 엔터프라이즈한 기능 지원 등의 측면에서 많이 부족한 부분이 있다.
- 이런 점을 보완하기 위해 Gensim, SpaCy가 출시되어 실제 업무에서 활용되고 있다.
*사이킷런은 NLP를 위한 라이브러리를 가지고 있지 않아 더 다양한 텍스트 분석을 위해
NLTK, Gensim, SpaCy와 같은 NLP 전용 패키지와 함께 결합해야 한다.
*단, 일정 수준으로는 가공하고 피처로 처리할 수 있지만 충분하지는 않다.
*Gensim : 토픽 모델링 분야(텍스트 요약)에서 두각을 나타낸다. Word2Vec 지원
*SpaCy : 뛰어난 수행 성능을 가지고 있다.
텍스트 정규화
- 텍스트를 입력 데이터로 사용하기 위해 클렌징, 정제, 토큰화, 어근화 등 다양한 텍스트 데이터의 사전 작업을 수행하는 것
클렌징
- 텍스트 분석에 방해가 되는 불필요한 문자, 기호 등을 제거하는 작업
- HTML, XML의 태그나 특정 기호도 포함된다.
텍스트 토큰화
- 문서에서 문장을 분리하거나, 문장에서 단어를 토큰으로 분리하는 작업
- 문장 토큰화 : 문서를 마침표, 개행문자 등을 기준으로 분리하는 작업.
- nltk.sent_tokenize(text=데이터)로 쉽게 처리할 수 있다.
- 단어 토큰화 : 문장을 공백, 콤마, 마침표 등을 기준으로 분리하는 작업
- nltk.word_tokenize(데이터)로 쉽게 할 수 있다.
스톱 워드 제거
- 스톱 워드란 분석에 큰 의미가 없는 단어를 지칭한다.
- 영어에서는 is, the, a, will 등의 필수 문법 요소가 해당된다.
- 제거해야 하는 이유는, 이러한 것들은 빈번하게 나타나 중요하지 않음에도 중요한 단어로 인식될 수 있기 때문이다.
- nltk.corups.stopwords.words('english')로 스톱 워드 목록을 불러올 수 있다.
- 이후 제거는 단어 토큰화된 리스트에서 직접 삭제 알고리즘을 만들어서 사용해야 한다.
Stemming과 Lemmatization
- 많은 언어가 문법적인 요소에 따라 단어가 다양하게 변화한다.
- 영어의 경우 과거/현재, 3인칭 단수 여부, 진행형 등이 이에 해당된다.
- Stemming과 Lemmatization은 문법적 또는 의미적으로 변화하는 단어의 원형을 찾아내는 작업이다.
- Stemming은 원형 단어로 변환 시 일반적인 방법을 적용하거나 더 단순화된 방법을 적용해서 원래 단어에서 일부 철자가 훼손된 어근 단어를 추출하는 경향이 있다.
- 이에 반해 Lemmatization은 품사와 같은 문법적인 요소와 더 의미적인 부분을 감안해 정확한 철자로 된 어근 단어를 찾아준다.
- 즉, Lemmatization이 Stemming보다 정교하며 의미론적 기반에서 단어의 원형을 찾지만, 변환에 더 오랜 시간이 소요된다.
NLTK에서의 Stemming
- nltk.stem.LancasterStemmer
- 형용사의 비교형, 최상급형의 변환에 대해 정확하지 못하다.
NLTK에서의 Lemmatization (어근 추출)
- nltk.stem.WordNetLemmatizer
- 파라미터로 단어와 품사를 입력해야 한다. (동사는 'v', 형용사는 'a')
BOW (Bag Of Words)
- 문서가 가지는 모든 단어를 문맥이나 순서를 무시한다.
- 모든 단어를 일괄적으로 단어에 대해 빈도 값을 부여해 특징 값을 추출하는 모델.
- 쉽고 빠르게 구축할 수 있다.
- 또한 단순히 단어의 발생 횟수에 기반함에도 불구하고 문서의 특징을 잘 나타낸다.
- 그래서 여러 분야에서 활용도가 높다.
- 하지만 문맥 의미를 반영하지 못해 문맥적인 해석을 처리하지 못한다.
- 또한 머신러닝 알고리즘의 수행 시간과 예측 성능을 떨어뜨리는 희소 행렬을 만들어내기 쉽다.
*희소 행렬 : 대부분의 값들이 0으로 채워진 행렬
BOW에 피처 벡터화
- 피처 벡터화 : 텍스트를 특정 의미를 가지는 숫자형 벡터 값으로 변환하는 것.
- BOW 모델에서의 피처 벡터화는 모든 문서에서 모든 단어를 칼럽 형태로 나열하고 각 문서에서 해당 단어의 횟수나 정규화된 빈도를 값으로 부여하는 데이터 세트를 모델로 변경하는 것.
- m개의 문서에 들은 모든 단어 수의 총합이 n개이면 m*n개의 행렬이 출력된다.
Bow의 피처 벡터화 방식
1) 카운트 기반의 벡터화
- 단어 피처에 값을 부여할 때 각 문서에서 해당 단어가 나타내는 횟수를 센 것.
- 카운트 값이 높을수록 중요한 단어로 인식된다.
- 하지만 언어의 특성상 문장에서 자주 사용되는 단어에 높은 값을 부여하게 된다.
2) TF-IDF
- 카운트 기반의 벡터화가 중요하지 않은 단어에 높은 값을 부여해 중요한 단어로 인식하는 문제를 해결한 모델
- 개별 문서에서 자주 나타나는 단어에 높은 가중치를 주되, 모든 문서에서 전반적으로 자주 나타나는 단어에 대해서는 패널티를 부여한다.
- 개별 문서에서 자주 나타나는 단어는 해당 문서를 특정짓는 중요한 단어일 수 있지만, 해당 단어가 다른 문서에서도 빈번하게 나타나면 언어 특성상 범용적으로 자주 사용되는 단어일 확률이 높기 때문.
- 문서마다 텍스트가 길고 문서의 개수가 많은 경우 카운트 방식보다 TF-IDF 방식이 낫다.
사이킷런의 Count
- sklearn.feature_extraction.text.CountVectorizer(*, input='content', encoding='utf-8', decode_error='strict', strip_accents=None, lowercase=True, preprocessor=None, tokenizer=None, stop_words=None, token_pattern='(?u)\b\w\w+\b', ngram_range=(1, 1), analyzer='word', max_df=1.0, min_df=1, max_features=None, vocabulary=None, binary=False, dtype=<class 'numpy.int64'>)
*max_df : 전체 문서에 걸쳐 max_df 이상의 빈도수를 가지는 단어 피처 제외.
*min_df : 전체 문서에 걸쳐 min_df 이하의 빈도수를 가지는 단어 피처 제외
*max_features : 추출하는 피처의 개수 제한. 가장 높은 빈도의 단어를 max_features개만 추출
*stop_words : 해당 언어의 스톱 워드를 불러와 추출에서 제외
*n_gram_range : 단어 순서를 보장하기 위한 n_gram 범위 설정
*analyzer : 피처 추출을 수행한 단위 지정
*token_pattern : 정규 표현식 패턴 지정
*tokenizer : 토큰화를 별도의 커스텀 함수로 이용시 적용
사이킷런의 TF-IDF
- sklearn.feature_extraction.text.TfidfVectorizer(*, input='content', encoding='utf-8', decode_error='strict', strip_accents=None, lowercase=True, preprocessor=None, tokenizer=None, analyzer='word', stop_words=None, token_pattern='(?u)\b\w\w+\b', ngram_range=(1, 1), max_df=1.0, min_df=1, max_features=None, vocabulary=None, binary=False, dtype=<class 'numpy.float64'>, norm='l2', use_idf=True, smooth_idf=True, sublinear_tf=False)
- 주요 파라미터는 CountVectorizer와 같다.
- 리턴 값은 CSR 형태로 추출된다.
BOW 벡터화를 위한 희소 행렬
- 희소 행렬은 연산 시 데이터 액세스에 시간을 많이 사용하게 하고, 메모리 공간을 너무 많이 차지한다.
- 그래서 변환해야 하는데, 대표적인 변환 형식은 COO와 CSR이 있다.
COO 형식
- 0이 아닌 데이터만 별도의 데이터 배열에 저장하고, 그 데이터가 가리키는 행과 열의 위치를 별도의 배열로 저장한다.
- [[3, 0, 1], [0, 2, 0]] => [3, 1, 2], [0, 0, 1], [0, 2, 1] #값, 행 위치, 열 위치
- scipy.sparse의 coo_matrix((data, (row_pos, col_pos)) 를 사용해 행렬로 전환이 가능하다.
CSR 형식
- COO 행렬은 행과 열의 위치를 나타내기 위해 반복적인 위치 데이터를 사용했다.
- 이로 인해 큰 희소 행렬을 저장하고 계산하는 능력이 떨어졌는데, 이 점을 극복했다.
- 순차적인 같은 값이 반복적으로 나타날 때, 고유한 값의 시작 위치만 표기한다.
- 마지막에는 총 항목 개수를 기입한다.
- [[3, 0, 1], [0, 2, 0]] => [3, 1, 2], [0, 2, 3], [0, 1, 2, 3]
- 행위치 [0,0,1,1,1,1,1,2,2,3,4,4,5] => [0, 2, 7, 9, 10, 12, 13]
- scipy.sparse의 csr_matrix((data, (row_pos, col_pes)) 를 사용해 행렬로 전환이 가능하다.
감성 분석
- 문서의 주관적인 감성/의견/감정/기분 등을 파악하기 위한 방법
- 소셜 미디어, 여론조사, 온라인 리뷰, 피드백 등 다양한 분야에서 활용된다.
- 문서 내 텍스트가 나타내는 여러 가지 주관적인 단어와 문맥을 기반으로 감성 수치를 계산하는 방법
- 감성 지수는 긍정 감성 지수와 부정 감성 지수로 구성되며, 이 지수를 합산태 긍정 혹은 부정 감성을 결정
- 감성 분석은 지도 학습과 비지도 학습으로 나뉜다.
*지도 학습은 일반적인 텍스트 기반의 분류와 거의 동일
*비지도 학습은 Lexico이라는 일종의 감성 어휘 사전을 이용.
비지도 학습 기반 감성 분석
- Lexicon을 기반으로 한다.
- Lexicon은 일반적으로 어휘집을 의미하지만, 주로 감성만을 분석하기 위해 지원하는 감성 어휘 사전이다.
- 렉시콘은 긍정 감성 또는 부정 감성의 정도를 의미하는 수치를 가지고 있으며, 이를 감성 지수라고 한다.
- 감성 지수는 단어의 위치, 주변 단어, 문맥, POS (Part of speech) 등을 참고해 결정된다.
- NLTK에서도 감성 사전인 WordNet이 존재하지만, 예측 성능이 뛰어나지 못하다. 그래서 실제 업무는 NLTK가 아닌, NLTK를 포함한 감성 사전을 이용한다.
NLTK을 포함한 감성 사전
1) SentiWordNet
- NLTK 패키지의 WordNet과 유사한 감성 단어 전용의 워드넷.
- 긍정 감성 지수, 부정 감성 지수, 객관성 지수를 할당한다.
- 객관성 지수는 개념적으로 단어의 감성과 관계없이 얼마나 객관적인지를 수치로 나타낸다.
- 전혀 감성적이지 않은 단어의 객관성 지수는 1이다.
- SentiWordNet을 이용하기 위해샤는 WordNet을 이용해 문서를 단어로 토큰화한 뒤 어근 추출과 품사 태깅을 적용해야 한다.
- nltk.corpus.sentiwordnet
2) VADER
- 주로 소셜 미디어의 텍스트에 대한 감성 분석을 제공하기 위한 패키지
- 뛰어난 감성 분석 결과를 제공하며, 비교적 빠른 수행 시간을 보장한다.
- nltk.sentiment.vader.SetimentIntensityAnalyzer
3) Pattern
- 예측 성능 측면에서 가장 주목받는 패키지.
- 하지만 파이썬 2.X에서만 동작한다.
토픽 모델링 (문서 요약)
- 문서 집합에 숨어있는 주제를 찾아내는 것
- 머신러닝 기반의 토픽 모델링은 숨어있는 중요 주제를 효과적으로 찾아낼 수 있다.
- 토픽 모델은 숨겨진 주제를 효과적으로 표현 가능한 중심 단어를 함축적으로 추출한다.
- 토픽 모델링에는 LSA와 LSD 기법이 자주 활용된다.
사이킷 런에서의 LDA(Latent Dirchlet Allocation)
- sklearn.decomposition.LatentDirichletAllocation
- Count 기반의 벡터화를 사용한다.
*n_components : 결과값 클래스
*LDA는 반환값으로 객체를 생성하는데, components_ 속성값을 가지고 있다.
*components_ 속성은 개별 토픽별로 각 word 피처가 얼마나 많이 그 토픽에 할당됐는지에 대한 수치를 가지고 있다.
문서 군집화
- 비슷한 텍스트 구성의 문서를 군집화한다.
- 텍스트 분류와 유사한데, 텍스트 분류 기반의 문서 분류는 사전에 결정 카테고리 값을 가진 학습 데이터를 활용한다.
- 그에 비해 문서 군집화는 비지도 학습 기반이다.
- 별도의 클래스와 함수가 존재하는 것은 아니고, 전처리하여 토큰화된 문서들을 기존의 KMeans 와 같은 군집화 알고리즘으로 군집한다.
문서 유사도 (코사인 유사도)
- 문서와 문서간 유사도는 일반적으로 코사인 유사도를 사용한다.
- 코사인 유사도는 벡터의 유사도를 비교할 때 벡터의 크기보다 벡터의 상호 방향성의 유사성을 중시한다.
- 즉 코사인 유사도는 두 벡터 사이의 사잇각을 구해 얼마나 유사한지 수치로 적용한 것이다.
왜 코사인 유사도인가?
- 문서를 피처 벡터로 변환하면 희소 행렬이 되기 쉽다.
- 희소 행렬 기반에서 문서와 문서 벡터간의 크기에 기반한 유사도 (유클리드 거리 기반)는 정확도가 떨어지기 쉽다.
- 그래서 크기보다 상호 방향성의 유사성에 기반한 코사인 유사도로 확인한다.
사이킷 런의 코사인 유사도
- sklearn.metrics.pairwise.cosine_similarity
- 희소 행렬, 밀집 행렬 모두 가능하며, 행렬이나 배열 또한 가능하다.
- 별도의 변환 작업 없이 그냥 바로 넣어도 된다.
*입력 파라미터는 문서 두 개인데, 문서의 배열을 두 개 넣어도 된다.
*배열로 넣을 경우 서로 비교해서 비교도를 행렬로 반환.
한글 텍스트 처리
한글 텍스트 처리가 어려운 이유
1) 띄어쓰기의 문제
- 띄어쓰기가 잘못 사용되면 의미가 왜곡되기 쉽다.
- 참고로 한글의 띄어쓰기는 고등교육을 받은 사람들도 종종 틀릴 정도로 어렵다.
2) 조사의 문제
- 조사의 경우의 수가 너무 많아 어근 추출 시 제거하기가 까다롭다.
파이썬에서의 한글 NLP
- KoNLPy를 사용한다.
- KoNLPy는 대표적인 한글 형태소 패키지이다.
- 말뭉치를 어근 단위로 쪼개 각 형태소에 품사 태깅을 부착하는 형태소 분석 작업을 지원한다.
- C/C++/JAVA로 만들어진 한글 형태소에 파이썬 래퍼를 기반으로 재작성한 패키지이다.
- 꼬꼬마, 한나눔, Komoran, Mecab, Twitter 같은 형태소 분석 모듈을 사용할 수 있다.
*형태소 : 단어로서 의미를 가지는 최소 단위
*Mecab의 경우에는 윈도우에서 사용이 불가능함을 주의.