#!/usr/bin/env python # coding: utf-8 # # **NLP (Natural Language Processing) 분석** # **뉴스그룹 데이터 Set 분석** # 1. 단어의 지식과 개념을 정리하는 작업으로 **Ontology** 같은 예들이 존재 # 1. 낮은 단계로는 **Tagging, POS(Part of Speech)** 이 있다 # 1. Python 라이브러리로 **NLTK, Gensim, TextBlob** 등이 있다 #
# # ## **1. NLP 개념 익히기** # # **NLTK 에서 자연어 분석 작업** # 1. **Tokenization**(토큰화) : 텍스트를 공백문자로 구분하여 조각을 나누는 작업 (Document --> Ngram) # 1. **POS Tagging**(품사태깅) : **Konlpy, NLTK** 에 규격화 된 Tagger를 적용하거나, **POS_TAG**와 같은 함수를 활용 # 1. **NER** (개체명 인식) : **Named entity Recognition** 은 텍스트 문장에서 명사를 식별하는 작업이다 # 1. **Stemming** (어간추출) : 어간, 어근의 **원형으로** 되돌리는 작업 # 1. **Lemmatization**(표제어 원형 복원) : 어간 추출보다 좁은 의미로써 **단어를 유효한 결과로** 출력하는 작업 # In[1]: # 어간의 추출 from nltk.stem.porter import PorterStemmer porter_stemmer = PorterStemmer() porter_stemmer.stem('machines') # In[2]: # Token 의 원형을 복구한다 from nltk.stem import WordNetLemmatizer lemmatization = WordNetLemmatizer() lemmatization.lemmatize('machines') # ### **Gensim 에서의 자연어 분석 작업** # 문장간 유사도 측정을 위해 2008년 시작된 모듈로써, 다양한 모델링이 가능하다 # 1. **Similarity Querying** (유사도 쿼리) : 주어긴 쿼리 객체와 유사한 객체를 검색 # 1. **Word vectorization** (단어 벡터화) : 단어의 동시출현 Feacture를 유지하면서 단어를 표현 # 1. **Distribution Computing** (분산 컴퓨팅) : 다수의 문서를 효과적으로 학습 # # ### **Text Blob** # NLTK 기반의 라이브러리로 **맞춤법 확인 및 교정, 언어감지, 번역기능이** 추가 #
# ## **2. newsgroups 데이터 보기** # 20개의 **News Group을** 대상으로 **11,313 개의** 뉴스 데이터가 담겨있다 # ### **01 News Group 데이터 살펴보기** # > **fetch_20newsgroups()** # # 1. subset : 적제할 데이터를 정의한다 # 1. data_home : 파일을 저장할 폴더 ex) **~/scikit_learn_data**(초기값) # 1. categories : 추출할 목록을 지정 # In[3]: # 뉴스 데이터를 가져온다 (약 14MB) # 뉴스 그룹 0 ~ 19 (20개 목록) from sklearn.datasets import fetch_20newsgroups groups = fetch_20newsgroups(data_home='data/news/') groups['target_names'] # In[4]: # groups Json 데이터 살펴보기 for key in groups.keys(): print(key, ':', type(groups[key])) groups.keys() # In[5]: # 뉴스그룹 Primary Key 값인 정수값 인코딩 # 정수들이 중복되지 않게 정리된 결과를 출력한다 import numpy as np print(groups.target) np.unique(groups.target) # ### **02 개별 News 데이터 살펴보기** # 0 번 뉴스의 정보를 확인하기 # In[6]: # 해당 뉴스의 내용 살펴보기 print("News Group 포함된 자료갯수: {:,} 개\n\n0번 샘플보기: \n{}".format( len(groups.data), groups.data[0])) # In[7]: # 0번 뉴스의 해당 그룹 Category 확인 groups.target_names[groups.target[0]] # ### **03 데이터 시각화** # 1. Document를 분석하는 경우 **Bag of Words로써** (단어의 집합) 활용한다 # 1. **단어 모델링과** 어떠한 차이가 있는지를 확인해 본다 # 1. **총 20개 카테고리** 뉴스들을 Histogram으로 시각화 (비슷한 갯수로 모델이 분표) # In[8]: get_ipython().run_line_magic('matplotlib', 'inline') # Seaborn 내부함수에 대한 FutureWarning이 출력 import warnings warnings.simplefilter(action='ignore', category=FutureWarning) # 전체 뉴스그룹 데이터의 길이를 시각화 한다 # 전체적으로 11,316개가 비슷한 길이를 갖음을 확인할 수 있다 import matplotlib.pyplot as plt import seaborn as sns sns.distplot(groups.target) plt.grid() # ### **04 Feacture Set을 활용하여 전체 Text 갯수를 확인한다** # 1. **Sklearnd의 CountVectorizer를** 활용하여 **빈도상위 500**개 Token으로 Embadding # 1. **위는 알파벳 갯수로써** 비교를 했기 때문에 비슷하게 나오는데 # 1. **단어 기준으로** Feacture Set을 생성하면 결과가 어떻게 되는지 확인해보자 # # > **CountVectorizer()** 의 파라미터 확인 # # 1. **stop_words** : 불용어 목록을 활성화 한다 ex) **None(초기값), english, [a, the, of]** # 1. **ngram_range** : 추출할 ngram 하한/ 상한선을 지정 ex) **(1,1)(초기값) (1,2) (2,2)** # 1. **lowercase** : 소문자 변환 활성화 여부 ex) **True(초기값), False** # 1. **max_feacture** : None 아니면 최대 token 갯수를 지정 ex) **None(초기값), 500** # 1. **binary** : 바이너리 여부를 정의한다 # In[9]: from sklearn.feature_extraction.text import CountVectorizer import numpy as np # 빈도상위 500개의 단어로만 추출한 결과를 분석 cv = CountVectorizer(stop_words="english", max_features=500) transformed = cv.fit_transform(groups.data) print(cv.get_feature_names()[:100]) # 빈도상위 100개의 Token을 출력한다 : 문장간 식별력이 낮은 숫자와 기호들이 포함 # In[10]: # 위에서 추출한 임베딩 데이터로 히스토그램을 보여준다 sns.distplot(np.log(transformed.toarray().sum(axis=0))) plt.xlabel('Log Count') plt.ylabel('Frequency') plt.title('Distribution Plot of 500 Word Counts') plt.grid(); plt.show() #
# # ## **3. newsgroups 데이터 분석** # 데이터를 전처리, 분석 과정을 단계별 진행한다 (분석에 용이한 텍스트로 재선별) # ### **01 데이터 전처리 (식별력이 높은 자료들만 추출한다)** # 1. 식별에 용이한 숫자 기호들은 제외한, 순수한 문자 데이터만 선별한다 # 1. 단어별 일치도를 높이기 위해서 **표제어 복원을** 진행 # 1. 문자중에도 Stopword, name 같이 식별력이 낮은 내용들은 제거한다 # # ```python # # 실행 중 nltk 오류시 # import nltk # nltk.download('names') # ``` # In[11]: # 아래에서 사용하는 알파벳 판단함수 'names'.isalpha() # In[12]: get_ipython().run_cell_magic('time', '', 'from nltk.corpus import names\nfrom nltk.stem import WordNetLemmatizer\n\n# 영문 제시어만 추출한다\ndef letters_only(astr):\n for c in astr:\n if not c.isalpha(): return False\n return True\n\n# 추출한 데이터 Token을 하나씩 표제어복원을 진행한다\nall_names = set(names.words())\nlemmatizer = WordNetLemmatizer()\ncleaned = [\' \'.join([lemmatizer.lemmatize(word.lower())\n for word in post.split()\n if letters_only(word) and word not in all_names]) \n for post in groups.data]\n \n# cv = CountVectorizer(stop_words="english", max_features=500)\ntransformed = cv.fit_transform(cleaned)\nprint(cv.get_feature_names()[:10])\nlen(names.words())\n') # ### **02 K-means 를 활용한 클러스터링** # 1. **(transformed)** : 위 전처리 및 빈도순서 500으로 선별된 데이터 활용 # 1. 데이터세트를 몇 개의 클러스터로 묶는다 # 1. **하드 클러스터링** : 개별 token 이 **1개 클러스터에만** 할당 (엄격) # 1. **소프트 클러스터링** : 개별 token 이 **다양한 확률값으로 여러 클러스터에** 할당 (유연) # 1. **이상치** (Outlier) : 어떠한 클러스터에도 할당되지 않는 값을 **이상치, 노이즈라** 한다 # # > **KMeans(클러스터수, 샘플갯수, 반복횟수)** # # 1. **n_cluster** : 클러스터 묶음 갯수 ex) 8 (기본값) # 1. **max_iter** : 반복자 할당 갯수 ex) 300 (기본값) # 1. **n_iter** : 다른 초기값으로 알고리즘 재실행 횟수 ex) 10 (기본값) # 1. **tol** : 실행 중지조건 ex) 1e-4 # In[13]: get_ipython().run_cell_magic('time', '', "# K Mean를 활용한 묶음처리\nfrom sklearn.cluster import KMeans\nkm = KMeans(n_clusters=20, n_jobs=-1)\nkm.fit(transformed)\n\nlabels = groups.target\nplt.scatter(labels, km.labels_)\nplt.xlabel('Newsgroup'); plt.ylabel('Cluster')\nplt.show()\n") # ### **03 Topic 모델링** # 1. 문장 내 단어 Token중 **핵심(주제)가 되는 Token을** 선별한다 # 1. Topic 마다 **다른 가중치를 할당하여 additive model을** 정의한다 # 1. **비음수 행렬 인수분해** : Non-Negative Matrix Factorization # In[14]: get_ipython().run_cell_magic('time', '', 'from sklearn.decomposition import NMF\nnmf = NMF(n_components=100, random_state=43).fit(transformed)\n\nfor topic_idx, topic in enumerate(nmf.components_):\n label = \'{}: \'.format(topic_idx)\n print(label, " ".join([cv.get_feature_names()[i]\n for i in topic.argsort()[:-9:-1]]))\n')