SOOJLE
수즐 커뮤니티
수즐 커뮤니티
  • SOOJLE Document
  • 프로젝트 요약
  • Untitled
  • 프로젝트 개요
    • 프로젝트 소개
    • 추진 배경 및 필요성
    • 프로젝트 내용
      • 기능적 요구사항
      • 비기능적 요구사항
    • 개발환경 및 팀 구성
    • 워크플로우
      • 계획 수립 & 설계
      • 데이터 수집 및 정규화
      • 인공지능 개발
      • 서비스 모듈 개발
      • 성능 평가 및 보고
    • 프로젝트 예산 내역
  • 사전조사 & 의사결정
    • 사전조사
      • 재학생 대상 사전조사
      • 수집 URL 대상 목록
        • 세종대학교 직할
        • 세종대학교 학과
        • 공식 공지사항
        • 세종대 평생교육원
        • 외부 웹사이트
      • 학습 모델 사전조사
        • LSA - 잠재 의미 분석
        • LDA - 잠재 디리클레 할당
        • Word2Vec - 워드투벡터
        • FastText - 패스트텍스트
    • 의사결정
      • 사용자 인증 방식 의사결정
      • 데이터베이스 의사결정
        • MySQL vs MongoDB 성능 분석
      • 토픽별 의사결정
      • 부가 기능 의사 결정
  • 프로젝트 설계
    • 시스템 구조 설계
    • 핵심 기능 설계
      • 데이터 크롤러 설계
      • 게시물 토픽 정의 및 분류
      • 사용자 관심분야 측정
      • 뉴스피드 설계
        • 사용자-문서 유사도(Recommendation Score)
        • FaS (관심 분야 및 유사도 측정 - 추가)
        • 토픽 뉴스피드 목록
      • 검색 알고리즘 설계
        • 검색 알고리즘 1차 설계
        • 검색 알고리즘 1차 개선안
        • 검색 알고리즘 2차 설계
    • 요구사항 목록
      • DB 요구사항
      • 기능 요구사항
      • 품질 요구사항
      • 관리 요구사항
  • DB
    • 구조 설계
    • 테이블 명세
  • 데이터 크롤러
    • 데이터 크롤러 개요
    • 크롤링 URL 선정
    • 크롤러 구현을 위한 사전조사
    • 크롤러 개발 과정
      • 크롤러 프로그램 설계
      • 크롤러 규격화
      • 크롤러 정규화
      • 데이터 정제 과정
      • 에러 핸들러 구현
      • 배포 환경 이식을 위한 Porting
    • Issue & Exception
    • 결과 보고
  • 인공지능 개발
    • 인공지능 개발 개요
    • NLP 스터디
      • Bag of Words(BoW)
      • Document Term Matrix(DTM)
      • TF-IDF(Term Frequency-Inverse Document Frequency)
      • 문서 유사도(Document Similarity)
    • 데이터 전처리 과정
    • 개발 과정
      • 토크나이저 구현
      • LDA 모델 학습 및 구현
    • LDA 학습 모델링
      • 1차 파라미터 튜닝 결과 (NUM_TOPICS)
      • 2차 파라미터 튜닝 결과 (NUM_TOPICS)
      • 3차 파라미터 튜닝 결과 (NUM_TOPICS)
      • NUM_TOPICS 파라미터 의사결정
      • 4차 파라미터 튜닝 결과 (PASESS, ITERATION)
      • 최종 학습 모델 명세
    • Word2Vec(FastText) 학습 모델링
    • Issue & Exception
    • 성능 분석 결과
  • BackEnd
    • 서버 구축 및 배포
      • SOOJLE 서버 구조
      • 상용 서버 (UWSGI + NGINX) 구축
      • HTTPS 서버 구현
    • API 문서 개요
    • API 목록
      • Analysis
      • Auth API
      • Newsfeed API
      • Post API
      • Search API
      • Admin API
    • 세종 Auth API
    • 통계 기능 설계
    • Issue & Exception
    • 성능 분석 결과
  • FRONTEND
    • 프론트엔드 설계 개요
    • 디자인 설계 의사결정
      • 디자인 컨셉 및 기능 정의
      • 컴포넌트 디자인
      • Logo Variation
    • 화면 흐름도
    • 페이지 UI 명세
      • Main Page
      • Header
      • Footer
      • Mobile Control Bar
      • Login Page
      • Timeline Page
      • Menu Page
      • Hyperlink Icons Page
      • Search Component & Mobile Search Modal
      • Search Page
      • Post Block
      • Snackbar
  • 프로그램 배포
    • 프로그램 개요
    • 시스템 아키텍쳐
    • 주요 기능 및 명세
    • 프로그램 테스트
    • 구현 결과물 배포
  • 마무리
    • References
  • SOOJLE AI
  • SEJONG AUTH
  • IML Tokenizer
  • SOOJLE Crawler
  • SOOJLE Frontend
  • SOOJLE Backend
Powered by GitBook
On this page
  • 개요
  • 1. 특이 값 분해(Singular Value Decomposition, SVD)
  • 2. TSVD(Truncated SVD)
  • 예제 실행 코드
  • 3. 잠재 의미 분석(Latent Semantic Analysis, LSA)
  • LSA 모델 분석

Was this helpful?

  1. 사전조사 & 의사결정
  2. 사전조사
  3. 학습 모델 사전조사

LSA - 잠재 의미 분석

Previous학습 모델 사전조사NextLDA - 잠재 디리클레 할당

Last updated 5 years ago

Was this helpful?

개요

BoW에 기반한 DTM이나 TF-IDF는 기본적으로 단어의 빈도 수를 이용한 수치화 방법이기 때문에 단어의 의미를 고려하지 못한다는 단점이 있다. 이를 위한 대안으로 DTM의 잠재된(Latent) 의미를 이끌어내는 방법으로 잠재 의미 분석(Latent Semantic Analysis, LSA)이라는 방법이 존재한다.

1. 특이 값 분해(Singular Value Decomposition, SVD)

SVD란 A가 m × n 행렬일 때, 다음과 같이 3개의 행렬의 곱으로 분해(decomposition)하는 것을 말한다.

여기서 각 3개의 행렬은 다음과 같은 조건을 만족한다.

U = m×m의 직교행렬

V = n×n 직교행렬 Σ = m×n 직사각 대각행렬

직교행렬(orthogonal matrix)이란 자신과 자신의 전치 행렬(transposed matrix)의 곱 또는 이를 반대로 곱한 결과가 단위행렬(identity matrix)이 되는 행렬을 말한다.

2. TSVD(Truncated SVD)

LSA의 경우 위에서 생성된 Full SVD에서 나온 3개의 행렬에서 일부 벡터들을 삭제시켜 절단된 SVD(truncated SVD)를 사용한다.

절단된 SVD는 대각 행렬 Σ의 대각 원소의 값 중에서 상위 값 t개가 남게 된다. 절단된 SVD를 수행하면 값의 손실이 일어나므로 기존의 행렬 A를 복구할 수 없으며 U행렬과 V행렬의 t열까지만 남는다. 여기서 t는 토픽의 수를 반영한 하이퍼 파라미터 값으로 사용자가 직접 값을 선택하며 성능에 영향을 주는 매개변수를 뜻한다.

예제 실행 코드

아래와 같은 DTM 시나리오를 통해 코드 상에서 TSVD를 구현해보면 다음과 같다.

import numpy as np
A=np.array([
[0,0,0,1,0,1,1,0,0],
[0,0,0,1,1,0,1,0,0],
[0,1,1,0,2,0,0,0,0],
[1,0,0,0,0,0,0,1,1]])

해당 행렬의 Shape은 다음과 같다.

>>> np.shape(A)
(4, 9)

생성된 행렬에 대하여 DTM 및 SVD를 생성한다.

>>> U, s, VT = np.linalg.svd(A, full_matrices = True)

>>> np.shape(U)
[[-0.24  0.75  0.   -0.62]
 [-0.51  0.44 -0.    0.74]
 [-0.83 -0.49 -0.   -0.27]
 [-0.   -0.    1.    0.  ]]
(4, 4)

>>> np.shape(s)
[2.69 2.05 1.73 0.77]
(4,)

>>> S = np.zeros((4, 9)) # 대각 행렬의 크기인 4 x 9의 임의의 행렬 생성
>>> S[:4, :4] = np.diag(s) # 특이값을 대각행렬에 삽입
>>> np.shape(S)
[[2.69 0.   0.   0.   0.   0.   0.   0.   0.  ]
 [0.   2.05 0.   0.   0.   0.   0.   0.   0.  ]
 [0.   0.   1.73 0.   0.   0.   0.   0.   0.  ]
 [0.   0.   0.   0.77 0.   0.   0.   0.   0.  ]]
(4, 9)

>>> np.shape(VT)
[[-0.   -0.31 -0.31 -0.28 -0.8  -0.09 -0.28 -0.   -0.  ]
 [ 0.   -0.24 -0.24  0.58 -0.26  0.37  0.58 -0.   -0.  ]
 [ 0.58 -0.    0.    0.   -0.    0.   -0.    0.58  0.58]
 [ 0.   -0.35 -0.35  0.16  0.25 -0.8   0.16 -0.   -0.  ]
 [-0.   -0.78 -0.01 -0.2   0.4   0.4  -0.2   0.    0.  ]
 [-0.29  0.31 -0.78 -0.24  0.23  0.23  0.01  0.14  0.14]
 [-0.29 -0.1   0.26 -0.59 -0.08 -0.08  0.66  0.14  0.14]
 [-0.5  -0.06  0.15  0.24 -0.05 -0.05 -0.19  0.75 -0.25]
 [-0.5  -0.06  0.15  0.24 -0.05 -0.05 -0.19 -0.25  0.75]]
(9, 9)

이제 t를 정하고, TSVD(Truncated SVD)를 수행해야 한다. 하이퍼 파라미터의 값은 t=2로 가정하고 각 성분에 대하여 절단 작업을 수행한다.

S=S[:2,:2]
U=U[:,:2]
VT=VT[:2,:]
A_prime=np.dot(np.dot(U,S), VT)

Full SVD(A)와 완성된 TSVD(A_prime)의 결과를 비교해보자.

# A
[[0 0 0 1 0 1 1 0 0]
 [0 0 0 1 1 0 1 0 0]
 [0 1 1 0 2 0 0 0 0]
 [1 0 0 0 0 0 0 1 1]]
 
 # A_prime
[[ 0.   -0.17 -0.17  1.08  0.12  0.62  1.08 -0.   -0.  ]
 [ 0.    0.2   0.2   0.91  0.86  0.45  0.91  0.    0.  ]
 [ 0.    0.93  0.93  0.03  2.05 -0.17  0.03  0.    0.  ]
 [ 0.    0.    0.    0.    0.    0.    0.    0.    0.  ]]

대체적으로 기존에 0인 값들은 0에, 1인 값들은 1에 가까운 값이 나오는 것을 확인할 수 있다. 축소된 U는 4 × 2의 크기를 가지며, 이는 문서의 개수 × 토픽의 수 t의 크기이다. 즉, U의 각 행은 잠재 의미를 표현하기 위한 수치화 된 각각의 문서 벡터이며, 2 × 9의 크기를 가지는 축소된 VT는 토픽의 수 t × 단어의 개수의 크기를 뜻한다.

3. 잠재 의미 분석(Latent Semantic Analysis, LSA)

기존의 DTM이나 DTM에 단어의 중요도에 따른 가중치를 주었던 TF-IDF 행렬은 단어의 의미를 전혀 고려하지 못한다는 단점을 갖고 있다. 그리하여 LSA는 기본적으로 DTM이나 TF-IDF 행렬에 TSVD(truncated SVD)를 적용 시 차원을 축소시키고, 단어들의 잠재적인 의미를 끌어내는 방식이다.

아래의 코드는 LSA를 기반으로 Sklearn에서 제공하는 테스트 데이터를 사용하여 주제 분류 모델을 학습하는 코드이다.

# LSA : DTM을 차원 축소 하여 축소 차원에서 근접 단어들을 토픽으로 묶는다.
import pandas as pd
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.corpus import stopwords
from sklearn.decomposition import TruncatedSVD
import numpy as np
dataset = fetch_20newsgroups(shuffle=True, random_state=1, remove=('headers', 'footers', 'quotes'))
#####list, 테스트용 뉴스데이터
documents = dataset.data
# 실제 토픽(답안)
#print(len(dataset.target_names), dataset.target_names)
#### 전처리
news_df = pd.DataFrame({'document':documents})
# 알파벳을 제외하고 모두 제거`
news_df['clean_doc'] = news_df['document'].str.replace("[^a-zA-Z#]", " ")
# 길이가 3이하인 단어는 제거 (길이가 짧은 단어 제거)
news_df['clean_doc'] = news_df['clean_doc'].apply(lambda x: ' '.join([w for w in x.split() if len(w)>3]))
# 전체 단어에 대한 소문자 변환
news_df['clean_doc'] = news_df['clean_doc'].apply(lambda x: x.lower())
# NLTK로부터 불용어 사전 로드
stop_words = stopwords.words('english')
# 토큰화 및 불용어 제거
tokenized_doc = news_df['clean_doc'].apply(lambda x: x.split())
tokenized_doc = tokenized_doc.apply(lambda x: [item for item in x if item not in stop_words])
#### 역토큰화
detokenized_doc = []
for i in range(len(news_df)):
	t = " ".join(tokenized_doc[i])
	detokenized_doc.append(t)
news_df['clean_doc'] = detokenized_doc
#### TF-IDF 행렬 만들기
vectorizer = TfidfVectorizer(stop_words = "english",
							#max_features = 10000, # 최대 단어 제한
							max_df = 0.5,
							smooth_idf = True)
X = vectorizer.fit_transform(news_df['clean_doc'])
#### 토픽모델링
svd_model = TruncatedSVD(n_components = 20, 
						algorithm = 'randomized',
						n_iter = 100,
						random_state = 122)
svd_model.fit(X)
#(토픽의 수, 해당 토픽과 관련된 단어)
print(np.shape(svd_model.components_))
#결과출력
terms = vectorizer.get_feature_names()
def get_topics(components, feature_names, n = 5):
	for idx, topic in enumerate(components):
		print("Topic %d:" % (idx+1), 
			[(feature_names[i], topic[i]) for i in topic.argsort()[:-n - 1:-1]])
get_topics(svd_model.components_, terms)

아래는 생성된 모델에 기반형 분류된 토픽 및 해당 토픽에 기여한 중요 빈도 단어를 출력시켜 보았다.

Topic 1: [('like', 0.2138), ('know', 0.20031), ('people', 0.19334), ('think', 0.17802), ('good', 0.15105)]
Topic 2: [('thanks', 0.32918), ('windows', 0.29093), ('card', 0.18016), ('drive', 0.1739), ('mail', 0.15131)]
Topic 3: [('game', 0.37159), ('team', 0.32533), ('year', 0.28205), ('games', 0.25416), ('season', 0.18464)]
Topic 4: [('drive', 0.52823), ('scsi', 0.20043), ('disk', 0.15518), ('hard', 0.15511), ('card', 0.14049)]
Topic 5: [('windows', 0.40544), ('file', 0.25619), ('window', 0.1806), ('files', 0.16196), ('program', 0.14009)]
Topic 6: [('government', 0.16085), ('chip', 0.16071), ('mail', 0.15626), ('space', 0.15047), ('information', 0.13582)]
Topic 7: [('like', 0.67121), ('bike', 0.14274), ('know', 0.11189), ('chip', 0.11043), ('sounds', 0.10389)]
.....
생략

LSA 모델 분석

LSA는 단어의 잠재적인 의미를 이끌어낼 수 있어 문서의 유사도 계산 등에서 좋은 성능을 보여준다는 장점을 갖고 있다. 그러나 SVD의 특성상 이미 계산된 LSA에 새로운 데이터가 추가될 경우, 보편적으로 처음부터 다시 계산해야 한다. 즉, 새로운 정보에 대해 업데이트가 거의 불가능하다. 접근 방법 자체는 본 프로젝트와 유사하지만 해당 결점으로 인해 모델로 선정하기에는 부족한다고 판단된다.

SVD를 통해 나온 대각 행렬 Σ는 기존의 대각 행렬과 별개로 추가적인 성질을 가지게 된다. 대각 행렬 Σ의 주대각원소를 행렬 A의 특이값(singular value)라고 하며, 이를라고 표현한다고 하였을 때 특이값 은 내림차순으로 정렬되어 있다는 특징을 가진다.