생애 처음 명품백을 사봤다. 아주 고가는 아니지만 주머니에 비례하면 엄청 고가이다.ㅋ 백화점에서 사는게 좋을지, 이월 상품을 조금 저렴하게 살 수 있는 프리미엄 아울렛이 좋을지, 인터넷 쇼핑에서 최저가로 사는게 좋을지... 제 가격 다 주고 살 베짱은 없어서 백화점은 제외하고, 인터넷은 짝퉁이 난무할거 같아 제외하다보니 결국 프리미엄 아울렛으로 향했다. 한창 명품에 관심이 있었을 시절 좋아했던 브랜드들은 올드하니 제외하고, 요즘 뜨는 브랜드를 선물하고 싶었는데 아는 것도 없고... 근 3시간을 돌다보니 생로랑 면적이 참 넓어 보이더라. 생로랑이 가장 핫함? 하지만 결국 계획하고 간 대로 발렌시아가를 선택. 계속해서 몇백 만원대의 명품들만 보다 보니 판단력이 흐려지더만. 300만원 짜리만 보다보면 100만원 짜리가 아주 싸보임...

 

아무튼 뿌듯한 마음으로 집에 와서 진품 판별 및 최저가 검색을 해보는데, 해당 매장에서 소유한 인터넷 상점에서 같은 상품이 20만원 가량 싼 것을 보고... 아 이런 ㅆ... 시간버리고 최저가에도 못사고 바보짓.ㅜ 인터넷으로 최저가로 사는게 다 짝퉁은 아니라는 것을 학습함. 통관표지 있어도 가품이면 뭐... 그래도 난 할만큼 했다고 생각하고 넘어가야 하나?ㅎㅎ 또 명품백을 살 일이 생길지는 모르겠으나, 다음엔 믿을 만한 매장을 가진 인터넷 상점에서(상품 내용을 보면 대충 감이옴...ㅋ 어쨌든 최소 자체 AS라도 되는...) 최저가로 살 것이라고 다짐함.


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  0개가 달렸습니다.
secret

 

미래가 유망한 피아노 5년 경력의 조카에게 이사 기념 및 생일 선물로 피아노를 한 대 선물했다. 스테이지 피아노 중에 가성비가 뛰어나다고 느끼는 나의 CP4ㅋ 그리고 RD2000 과 FP90. 하지만 아이들에게는 좀 고가긴하지. 게다가 클래식을 배우고 있으니 이웃집을 위해 디지털 피아노가 나을 것 같아서 좀 살펴봤다.

 

우선 2년 정도 사용한 내 CP4.

 

  • [건반] 88키 / 그레이드해머 / NW-GH
  • [음향] 음색: 433개 / 효과(이펙트): 리버브, 코러스, 피치시프트, 마스터 EQ / 폴리포니(동시발음): 128음
  • [부가기능] 건반분리 / 음향효과 / 음색혼합 / 조옮김 / 메트로놈
  • [부가장치] 보면대 / 자동절전 / LCD 디스플레이

 

리버브 하나 키고 그 어떤 다른 기능도 사용하지 않음. 동시발음도 128로 충분한듯. 갠적으로 좀 오래된거, 리듬 없는거랑 블루투스 연결 안되는게 조금 아쉽긴 하지만. 기본 CFX 음색 한가지와 타건감 하나 만으로도 제값하는 스테이지 피아노다.

 

결국 타건감만 좋으면 되는데, 별 잡다한 기능들 다 들어가면서 가격이 함께 높아지는게 문제. 야마하 건반 종류에는 NWX(Natural Wood:천연목) > NW, GH3X > GH3 > GH > GHS 가 있다. CP4가 NW-GH 건반이니 꽤 훌륭한 편이다. 어쿠스틱 피아노 느낌을 원하면 최소 NW 건반 모델을 추천한다. NWX 건반은 조금 더 비싸다. 대충 보니 디지털 피아노 중 CLP 775 가 NWX 들어간 가장 저렴한 제품같은데 370만원정도...

 

아무튼 대충 200만원 선에서 보다보니 P-515 / CLP-735 두 가지로 좁혀졌다. P-515는 아이들이 원하는 잡기능들이 다 들어가 있고 NWX 건반이라 전용 스탠드까지 해서 주문을 했으나 한 달 반이 지나도록 감감 무소식...(NWX 건반인데 저렴한 편...) 결국 CLP-735 로 구매했는데 타건감이...??? 잘 모르겠다... 생각보다는 별루... 인조건반이라 그런듯. 80만원만 더 썼으면 CLP-745 사는건데 미안하다.ㅜ 또 미끄럼 방지(?) 재질 때문에 더 어색... 뭐 아이들은 새거라 그런가 마냥 좋아하는 거 같기도 하고. 735 모델의 Grand Touch-S 건반이란 건 어느급인지는 모르겠다만 635모델의 GH3X 정도는 되지 않을까... 물론 내꺼보다 신형이고 좋은 기술이 들어가 있겠지만.

 

이번에 느낀 것은 결국 타건감이라는 것은 결국 주관적이라는 것. 어쿠스틱 피아노도 그랜드 피아노랑 다 다른데, 그 느낌을 찾고자 디지털 피아노를 고른다는 것 자체가 거의 불가능. 고가 상품에서 타건감을 만족하지 못할 수도 있고, 저가 상품에서 타건감을 만족할 수도 있다. 대부분의 사람들이 직접 매장가서 쳐보고 사는게 가장 후회없이 살 수 있는 방법이라고 생각하겠지만, 모델을 알고 가격을 아는데 과연 정해놓은 금액대로 만족을 할 수 있을지. 아이가 직접 쳐보고 맘에 든다는 피아노가 개비싸다면 어떨지. 그래도 괜찮은 피아노 사주고 싶어서 며칠을 검색하고 알아보고 했는데 어쨌든 결국엔 사람들이 좋다는 것으로 추려진다.

 

그래서 내린 결론은,

 

먼저 가격 정하고 인터넷에 그 가격대에 이미 명품으로 알려진 상품들을 사는게 속편하다. 2~3개 중에 잡기능이랑 외모보고 땡기는거 사면 된다. 그 가격대에 좋다고 알려진 피아노들 타건감은 다 거기서 거기다. 내 손가락을 새 피아노에 적응 시키는게 최고. 이게 결론이다. 새 피아노에 적응하기.


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  0개가 달렸습니다.
secret

토픽 모델링 알고리즘인 LSA 의 단점을 보완한 대표적인 알고리즘이 잠재 디리클레 할당(LDA) 이다. 문서들에서 발견된 단어의 빈도수를 분석하여, 해당 문서가 어떤 주제를 다루고 있을지 예측할 수 있다. LDA 를 사용하여 토픽을 몇개 얻을 것인지 사용자가 지정해야 하는데, 이 하이퍼 파라미터로부터 결과가 달라질 수 있으므로 올바른 토픽을 얻기 위한 테스트가 필요하다.

 

LDA 는 각 문서의 토픽 분포와 각 토픽의 단어 분포를 도출하고 분석하여, 해당 문서가 어떤 주제들을 함께 다루고 있을지를 예측할 수 있다.


LDA 수행과정

 

  1. 문서 빈도수 기반의 표현 방법인, DTM 이나 TF-IDF 행렬을 입력으로 한다. (단어의 순서가 중요치 않음)
  2. 사용자가 LDA 에 하이퍼 파라미터인 토픽 개수(k) 를 전달한다.
  3. 문서에 사용할 토픽의 혼합을 확률 분포에 기반하여 결정한다.
  4. 랜덤으로 할당된 단어에 잘못 할당된 토픽을 각 단어들은 P(t|d) 와 P(w|t) 작업을 반복(역공학) 하며 토픽을 재할당한다.
     - 각 문서의 토픽 분포 P(t|d) : 해당 문서 d 에 나타난 토픽 t 의 비율을 보고 단어에 토픽 할당
     - 각 토픽의 단어 분포 P(w|t) : 는 전체 문서에서 단어 w 에 할당된 토픽 t 의 비율을 보고 단어에 토픽 할당

 

아래는 뉴스 기사의 제목을 모아놓은 약 100만개의 영어 데이터로부터 gensim 과 sklearn 을 사용하여 토픽을 추출하는 예제이다.

 

 

LDA with gensim

import gensim 
from gensim import corpora 

""" 전처리 결과가 아래와 같다고 할 때 
print(tokenized_doc[:5]) 
0    [well, sure, about, story, seem, biased, what,... 
1    [yeah, expect, people, read, actually, accept,... 
2    [although, realize, that, principle, your, str... 
3    [notwithstanding, legitimate, fuss, about, thi... 
4    [well, will, have, change, scoring, playoff, p... 
Name: clean_doc, dtype: object 
"""

# 각 단어에 정수 인코딩으로 (word_id, word_frequency) 의 형태로 변환 
dictionary = corpora.Dictionary(tokenized_doc) 
corpus = [dictionary.doc2bow(text) for text in tokenized_doc]  # [[(52, 1), (55, 1), ... , (88, 1), (89, 1)]] 

# LDA 토픽 모델링 (num_topics: 토픽 수, passes: 반복훈련횟수)
ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics=20, id2word=dictionary, passes=15)
topics = ldamodel.print_topics(num_words=4) 
for topic in topics: 
    print(topic) 

""" 토픽 별 단어 분포 
(0, '0.015*"drive" + 0.014*"thanks" + 0.012*"card" + 0.012*"system"') 
(1, '0.009*"back" + 0.009*"like" + 0.009*"time" + 0.008*"went"') 
(2, '0.012*"colorado" + 0.010*"david" + 0.006*"decenso" + 0.005*"tyre"') 
(3, '0.020*"number" + 0.018*"wire" + 0.013*"bits" + 0.013*"filename"') 
(4, '0.038*"space" + 0.013*"nasa" + 0.011*"research" + 0.010*"medical"') 
(5, '0.014*"price" + 0.010*"sale" + 0.009*"good" + 0.008*"shipping"') 
(6, '0.012*"available" + 0.009*"file" + 0.009*"information" + 0.008*"version"') 
(7, '0.021*"would" + 0.013*"think" + 0.012*"people" + 0.011*"like"') 
(8, '0.035*"window" + 0.021*"display" + 0.017*"widget" + 0.013*"application"') 
(9, '0.012*"people" + 0.010*"jesus" + 0.007*"armenian" + 0.007*"israel"') 
(10, '0.008*"government" + 0.007*"system" + 0.006*"public" + 0.006*"encryption"') 
(11, '0.013*"germany" + 0.008*"sweden" + 0.008*"switzerland" + 0.007*"gaza"') 
(12, '0.020*"game" + 0.018*"team" + 0.015*"games" + 0.013*"play"') 
(13, '0.024*"apple" + 0.014*"water" + 0.013*"ground" + 0.011*"cable"') 
(14, '0.011*"evidence" + 0.010*"believe" + 0.010*"truth" + 0.010*"church"') 
(15, '0.016*"president" + 0.010*"states" + 0.007*"united" + 0.007*"year"') 
(16, '0.047*"file" + 0.035*"output" + 0.033*"entry" + 0.021*"program"') 
(17, '0.008*"dept" + 0.008*"devils" + 0.007*"caps" + 0.007*"john"') 
(18, '0.011*"year" + 0.009*"last" + 0.007*"first" + 0.006*"runs"') 
(19, '0.013*"outlets" + 0.013*"norton" + 0.012*"quantum" + 0.008*"neck"') 
""" 

# 문서 별 토픽 분포 
for i, topic_list in enumerate(ldamodel[corpus]): 
    if i==5:  # 상위 5개 
        break 
    print(i,'번째 문서의 topic 비율은',topic_list) 

""" 
0 번째 문서의 topic 비율은 [(7, 0.3050222), (9, 0.5070568), (11, 0.1319604), (18, 0.042834017)] 
1 번째 문서의 topic 비율은 [(0, 0.031606797), (7, 0.7529218), (13, 0.02924682), (14, 0.12861845), (17, 0.037851967)] 
2 번째 문서의 topic 비율은 [(7, 0.52241164), (9, 0.36602455), (16, 0.09760969)] 
3 번째 문서의 topic 비율은 [(1, 0.16926806), (5, 0.04912094), (6, 0.04034211), (7, 0.11710636), (10, 0.5854137), (15, 0.02776434)] 
4 번째 문서의 topic 비율은 [(7, 0.42152268), (12, 0.21917087), (17, 0.32781804)] 
""" 



LDA with sklearn

 

from sklearn.feature_extraction.text import TfidfVectorizer 
from sklearn.decomposition import LatentDirichletAllocation

""" 전처리 결과가 아래와 같다고 할 때 
print(tokenized_doc[:5]) 
0       decide community broadcast licence 
1       fire witness must aware defamation 
2    call infrastructure protection summit 
3                   staff aust strike rise 
4      strike affect australian travellers 
Name: headline_text, dtype: object 
""" 

# TF-IDF 행렬 만들기 
vectorizer = TfidfVectorizer(stop_words='english', max_features= 1000)  # 상위 1,000개의 단어로 제한 
X = vectorizer.fit_transform(tokenized_doc) 

# LDA 토픽 모델링 
lda_model = LatentDirichletAllocation(n_components=10, learning_method='online', random_state=777, max_iter=1) 
lda_top = lda_model.fit_transform(X) 

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].round(2)) for i in topic.argsort()[:-n - 1:-1]]) 
get_topics(lda_model.components_,terms) 

""" 토픽 별 단어 분포 
Topic 1: [('government', 8725.19), ('sydney', 8393.29), ('queensland', 7720.12), ('change', 5874.27), ('home', 5674.38)] 
Topic 2: [('australia', 13691.08), ('australian', 11088.95), ('melbourne', 7528.43), ('world', 6707.7), ('south', 6677.03)] 
Topic 3: [('death', 5935.06), ('interview', 5924.98), ('kill', 5851.6), ('jail', 4632.85), ('life', 4275.27)] 
Topic 4: [('house', 6113.49), ('2016', 5488.19), ('state', 4923.41), ('brisbane', 4857.21), ('tasmania', 4610.97)] 
Topic 5: [('court', 7542.74), ('attack', 6959.64), ('open', 5663.0), ('face', 5193.63), ('warn', 5115.01)] 
Topic 6: [('market', 5545.86), ('rural', 5502.89), ('plan', 4828.71), ('indigenous', 4223.4), ('power', 3968.26)] 
Topic 7: [('charge', 8428.8), ('election', 7561.63), ('adelaide', 6758.36), ('make', 5658.99), ('test', 5062.69)] 
Topic 8: [('police', 12092.44), ('crash', 5281.14), ('drug', 4290.87), ('beat', 3257.58), ('rise', 2934.92)] 
Topic 9: [('fund', 4693.03), ('labor', 4047.69), ('national', 4038.68), ('council', 4006.62), ('claim', 3604.75)] 
Topic 10: [('trump', 11966.41), ('perth', 6456.53), ('report', 5611.33), ('school', 5465.06), ('woman', 5456.76)] 
""" 

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  0개가 달렸습니다.
secret

2020년 12월 31일 월미도

 

 

스피드하게 2020 결산을 하긴 했지만, 반성할 게 별로 없다고는 썼지만 한 달 전인 그때만 해도 정신머리가 어디 고여 있었던 것 같다. 전 세계가 코로나니까, 모두가 힘드니까, 나도 그냥 이렇게... 한 해를 보냈던 것 같다. 그렇게 살아서 뭐 문제 있어? 라고 묻는다면 문제는 없지만 발전 없는 하루하루가 좋니? 라고 말하고 싶다. 근데 왜 그러구 있니? 라는 물음에는 할 말이 없어 이렇게 또 반성문을 써본다. 12월 31일에 월미도에서 석양을 보며 정신 차리려고 했는데 그날부터 시작된 음주가 오늘에서야 글을 쓰게 만들었다.ㅋ

 

그 힘든 1년간의 코로나 시대에, 집값은 2배가 됐고, 코스피는 3천을 넘었는데, 월급은 그대로고, 현금을 보유하고 있는 자들은 오히려 바보가 됐다. 딱 1년만을 보자면 그렇다. 내 노력으로 생긴 보상 보다, 운으로 생긴 보상이 더 크게 되니, 피땀의 가치가 이렇게 초라할 수 없다. 이렇게 신분 상승의 기회를 주는데도 제대로 못 받아 먹은 게 아쉬울 따름. 뭐 이런 얘기를 하려는 건 아닌데, 아무튼... 

 

코로나로 인한 재택근무가 많아지고 개인 시간도 많았었는데, 열정적으로 아무것도 하지 않은 시간이 너무 많다. 결과적으로 많이 실망스럽다. 흔히 사람들이 시간을 돈에 비유한다. 이 시간이란 돈은 쓰려고 하지 않아도 계속 돌아가고 쓰이고 있다. 그런데 이 소중한 시간을 한순간이라도 아무 생각 없이 보낸다는 게 과연 정상적인 삶일까. 다음 주면 싱글라이프도 끝나고... 지금이 딱 재정비하기 좋은 시기다. 각자 삶의 방식은 모두 다르지만, 올해 나는 이 시간을 의미 있게, 집중적으로, 효과적으로 쓰는 것을 목표로 하고 정리 한번 들어간다.

 

 

1. 잠은 최고의 보약.

 

하루에 사용할 에너지를 충전하는 시간. 규칙적인 시간에 잠들기. 5시간을 자도 일어나기 힘들고 6시간을 자도 일어나기 힘들면 5시간만 자는 게 맞다. 8시간쯤 자면 쉽게 일어나지만, 그럼 아무것도 못 하고 맨날 회사<->집만 반복하다가 하루가 끝날 것이다. 4시간을 자면 가끔 알람 소리가 안 들릴 때도 있으니 난 5시간만 자는 것이 맞는 것 같다. 점심시간 쪽잠은 안 자는 걸로... 점심 먹고 몇 분 자는 게 꿀이긴 하지만 점심 먹고 바로 잠이 들면 속도 편치 않고, 정작 밤에는 제시간에 못 잘 수도 있다.

 

 

2. 출퇴근 시간 활용.

 

자가 이용 시는 아무것도 할 수 없고, 대중교통 이용 시는 이게 참... 사람 많을 때는 낑겨서 아무것도 못 하는데 그렇다고 왕복 세시간을 포기하는 것도 아깝고... 갈아타느라 잠도 제대로 못 자고. 약 20년간을 돌이켜 보면 뭘 하던 결국 몽롱하게 있다가 잠으로 이어졌음. 어쨌든 잠들면 어쩔 수 없는 거고, 핸드폰/태블릿 활용하는 게 최선이겠지.

 

 

3. 업무 및 자기계발

 

사실 이거때매 작년에 망했다고 내가 지금 이 글을 쓰는거다. 하루 중 시간을 가장 많이 할애하는 업무시간과 자기계발시간. 이 시간에 얼마나 집중할 수 있느냐에 따라서 더 많은 시간을 확보하거나 잃을 수 있다. 재택 하면서 생긴 심각한 버릇이 일 하다 말고 자꾸 딴짓하게 된다. 감시자들이 없어서 그런 건지. TV 틀어놓고, 음악 틀어놓고 그러니 1시간이면 끝낼 일을 2시간, 3시간이 넘도록 하는 경우가 많다. 그렇다고 전기 충격 같은 걸 설치할 수도 없고, 이건 그냥 다 끄고 다시 집중하도록 노력하는 수밖에. 뽀모도로 앱도 일단 깔아봤다.ㅋ

 

 

4. 헬스

 

한 달이 넘게 헬스를 못 했고, 안 했다. 못한 이유는 헬스장 셧다운 때문이고, 집에서조차 안 한 이유는 이거 뭐 무게도 칠 것도 없고 시간만 낭비하는 거 같아서 아예 아무것도 안 했다. 그런데 코로나뿐 아니라 언제라도 전염병이 돌면 또 같은 상황이 반복될 것이 뻔하다. 이제는 자의로 헬스장을 꾸준히 다닐수 없는 세상이 왔고 나는 홈 짐을 선택했다. 이것도 방 하나를 다 차지 하니 쉽게 결정할 수는 없다. 이제 나이도 계속 들어가고 하니 중량도 필요 없고 내가 평생 무리 없이 할 수 만큼만 해서 최소한으로 준비해 보려 한다.

 

 

5. 음주

 

고질병... 시간 빨아먹는 주요인.ㅋ 사실 한 2년간 혼자 있으면서 술을 진짜 적당히 잘 마셨다. 혼술할 때는 마실만큼 마시지만, 오래 마시지도 않고, 많이 마시지도 않고, 흔히 말하는 반주로 기분 좋게 마셨지. 이렇게만 먹으면 문제없는데, 날 잡고 지인들과 만날 때가 문제. 과할 때는 다음 날 저녁쯤이 돼서야 움직여지니 만 하루를 버리는 셈인데. 이거 안 만날 수도 없고, 분위기 깨지게 덜 먹을 수도 없고. 여우 같은 마누라가 있나 토끼 같은 자식이 있나 핑계거리도 없고. 안타깝지만 간을 새 걸루 바꾸지 않는 한 이것도 방법이 없다. 술 먹자고 선창만 날리지 말아야지.

 

 

6. 효도

 

올해로 부모님이 70세를 넘기셨다. 또한 손자들로부터도 해방이 되셨다. 그리고 내가 합가를 선언했다. 아버지께서 아직 일하시고 두 분 다 아프지 않으시니, 내가 모시고 산다고는 볼 수 없다. 사실 혼자 살면서 내가 이렇게 싱글라이프에 최적화 되어 있는지 몰랐다. 내가 평생 자신 있는게 외롭지 않고 심심하지 않는거다.ㅋㅋ 부모님 잔소리나 심부름이 없어진 것은 덤. 뭐 암튼 그럼에도 불구하고 합가를 결심한 것은 모든 가족의 바램이기도 하고, '가정도 못 꾸렸는데 부모님이라도 책임져야지'라는 생각이 들었다. 아직은 먼 얘기지만, 한 분만 남게 되었을 때 모시려면 그 또한 서로 쉽지 않을 것 같았다. 그냥 일찍부터 함께 살고 있는 것이 자연스러울터. 부모님 돌아가시면 어차피 죽을 때까지 혼자 살 거. 운세에 나온 45살까지 밖에서 버텨보려 했는데... 부질없다.ㅋ 우리 세 식구 살면 큰 소리 날 일도 없고, 나만 잘하면 평생 행복하게 산다. 매일 저녁 함께 하면서 얘기 나누고, 주말도 되도록 함께 보내는 착한 아들 돼야지. 45살 전에 며느리 얻으면 더 착한 아들인데...

 

 

작년 한 해는 이 부모님을 모시는 문제 때문에 정말 고민이 깊었다. 마지막 순간에 내가 원하는 집을 찾고도 맘 편히 계약하지 못하는 나를 보면서 합가를 결심하게 됐다. 물론 지금은 맘이 엄청 편하다. 후련하고. 앞으로 남양주에서의 출퇴근이 걱정이지. 출퇴근하고 운동할 시간만 잘 짜낸다면, 남은 인생 어찌되든 상관읍따! 내년 이맘때 이 글을 보고 부끄럽지 않도록 실천 잘하자. 신축년 새해에도 아프지 않고 소처럼 열심히 일하기! (1월 1일에 눈다래끼 시전으로 액땜 끝!)

 

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  2개가 달렸습니다.
  1. 구구절절 옳은 말들을.. 여전히 효자입니다. 다만 아쉬운 건 새해 시작은 입춘 기준이므로 눈다래끼는 庚子年 뒤끝입니다. (욕 같아 한자로 바꿨음) 어차피 가톨릭 신자는 열외일 겁니다.^^
secret

토픽 모델링(Topic Modeling) 이란 문서집합에서 추상적인 주제를 발견하기 위한 통계적 모델로, 잠재 의미 분석(Latent Semantic Analysis, LSA) / 잠재 디리클레 할당(Latent Dirichlet Allocation, LDA) 등의 알고리즘이 있다. LSA 는 기본적으로 DTM 이나 TF-IDF 행렬에 절단된 특이값 분해(truncated SVD) 를 사용하여 차원을 축소시키고, 단어들의 잠재적인 의미를 끌어내지만, SVD 의 특성상 새로운 데이터를 업데이트 하려면 처음부터 다시 계산해야 하는 단점이 있다.


특이값 분해(SVD) 는 A 가 m × n 행렬일 때,

3개의 행렬(U:m×m 직교행렬, VT:n×n 직교행렬, S:m×n 직사각 대각행렬) 의 곱으로 분해(decomposition) 하는 것이다.


(9 x 4) 행렬의 DTM 으로 절단된 특이값 분해(truncated SVD) 를 구하기.


import numpy as np
 
# 아래와 같은 DTM 이 있다고 할 때,
= [
    [000101100],
    [000110100],
    [011020000],
    [100000011]
]
 
# (4 x 9) 행렬에서
# 일단 특이값 분해 full SVD 구하기 : U x s x VT
# U : m×m 직교행렬,
# s : m×n 직사각 대각행렬,
# VT : n×n 직교행렬 이라 할 때,
U, s, VT = np.linalg.svd(A, full_matrices=True)
 
# 4 x 4 직교행렬 확인
print(U.round(2))
# [[ 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.  ]]
 
# 특이값 s 를 대각행렬로 바꾸고 직교행렬 구하기
print(s.round(2))
# [2.69 2.05 1.73 0.77]
= np.zeros((49))
S[:4, :4= np.diag(s)  # 특이값 s 를 대각행렬에 삽입
print(S.round(2))
# [[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.  ]]
 
# 9 x 9 직교행렬 확인
print(VT.round(2))
# [[ 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]]
cs


여기까지 구해본 full SVD 를 역으로 계산해 보면 U x S x VT = A 와 같음을 알 수 있다.

이제 3개 행렬을 축소시킨 truncated SVD 를 구하여 다른 문서나 단어의 유사도를 구할 수 있다.


# Truncated SVD 구하기
# 특이값 상위 2개만 남기기 (t = 2)
= U[:, :2]
= S[:2, :2]
VT = VT[:2, :]
print(np.dot(np.dot(U,S), VT).round(2))
# [[ 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.  ]]
cs


위와 같이 전체 코퍼스에서 절단된 특이값 분해를 구해야 하므로, 데이터를 추가하게 되면 전과정을 처음부터 다시 실행해야 하는 단점이 있다.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  0개가 달렸습니다.
secret