[머신러닝] 파이썬 머신러닝 #5 - 유사한 게시물 찾기

in kr •  6 years ago  (edited)

안녕하세요. @anpigon 입니다.

이번에는 유사한 게시물을 찾아내는 방법을 공부하였습니다. 게시물을 벡터로 계산하고, 벡터 간의 거리를 구하는 방법으로 유사도를 분석합니다. 이 기술을 이용하면 인터레스팀 서비스처럼 관련 글을 찾아낼 수도 있습니다. 저는 이 기술을 사용해서 불펌러(어뷰징 계정)들을 찾아내고 싶네요.

이번 예제는 "Building Machine Learning Systems with Python - Second Edition" 서적을 참고하였습니다.
이 책의 54 페이지에 있는 내용입니다.





scikit-learn

scikit-learn는 데이터 마이닝 및 데이터 분석을 위한 파이썬 라이브러리이다. NumPy, SciPy 및 matplotlib를 기반으로 제작되었다. 그리고 상업적으로 사용 가능한 오픈 소스(BSD) 라이센스를 가지고 있다.

scikit-learn 사용 환경은 다음과 같다. 아쉽게도 최신 버전인 파이썬3.7에서는 동작하지 않는다.

Python (>= 2.7 or >= 3.3),
NumPy (>= 1.8.2),
SciPy (>= 0.13.3).
설치하기
pip install -U scikit-learn




카운트 벡터 생성하기

게시물에 등장하는 단어를 세어 하나의 카운트 벡터로 생성한다. 그리고 해당 컨텐츠와 다른 컨텐츠 사이의 벡터 거리를 계산하여 컨텐츠 사이의 유사도를 파악한다. 하지만 우리는 단어를 세고 그 카운트를 벡터로 나타내는 코드를 작성할 필요가 없다. 그냥 SciKit의 "countVectorizer" 함수를 사용하면 된다.

scikit-learn에서 텍스트를 벡터화할 수 있는 CountVectorizer 함수를 import한다.

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(min_df=1)


CountVectorizer의 매개변수를 간단하게 설명하면, min_df의 값은 해당 값보다 낮은 빈도수의 단어는 모두 삭제된다. max_df도 비슷한 방식으로 작동한다. 아래와 같이 vectorizer를 출력하면 SciKit이 제공하는 다른 매개 변수와 기본값을 볼 수 있다.

Imgur


다음 데이터 세트를 사용하여 벡터간 거리를 계산해보자.

posts = [
  "이 글은 머신러닝에 관한 글이다. 사실은 재미없는 내용을 포함하고 있다.",
  "이미징 데이터베이스는 저장 기능을 제공한다.",
  "대부분의 이미징 데이터베이스는  이미지를 영구적으로 저장한다.",
  "이미징 데이터베이스는 데이터를 저장한다.",
  "이미징 데이터베이스는 데이터를 저장한다. 이미징 데이터베이스는 데이터를 저장한다. 이미징 데이터베이스는 데이터를 저장한다.",
]


fit_transform() 함수를 사용하여 벡터화 작업을 수행한다. 결과를 확인해보면, 19개 단어로 구성된 5개의 게시물이 벡터화되었다.

X_train = vectorizer.fit_transform(posts) 
num_sample, num_features = X_train.shape
print("#sample: %d, #fearutes: %d" % (num_sample, num_features))


feature_names을 출력해보자. vectorizer가 19개의 단어를 감지했다는 것을 확인할 수 있다. 그러나 "글은""글이다" 처럼 동일한 단어가 따로 구분되어 잡힌게 찜찜하지만 일단은 그대로 진행해본다.

print(vectorizer.get_feature_names())


이제 새로운 게시물이 주어졌을때 해당 게시물이 어느 게시물과 거리가 가까운지 살펴보자. 거리가 가까운 게시물이 가장 유사한 게시물이라고 보면 된다.

새 게시물을 벡터화하고 카운터 벡터를 생성하자.

new_post = "이미징 데이터베이스는"
new_post_vec = vectorizer.transform([new_post])


책 내용에 따르면 'transform' 함수에 의해 반환되는 카운트 벡터는 희소(sparse)하다는 것에 주의해야 한다. 이것은 각 벡터가 각 단어에 대한 카운트 값을 가지고 있지 않기 때문에 대부분은 0에 가까운 값을 가진다는 것을 의미한다. 대신, 더 효율적인 메모리 구현체인 'coo_matrix'를 사용한다. 예를 들어 새 게시물에는 실제로 두가지 요소만 포함하고 있다.

사실 저는 이 내용을 이해하지 못했습니다. 영어를 제대로 번역한게 맞는지도 모르겠어요. 이 부분에 대해서는 쉽게 설명하지 못해서 죄송합니다.ㅠ


벡터화된 새 게시물의 new_post_vec를 출력해보자.

print(new_post_vec)


출력 결과를 설명하면 새로운 게시물의 벡터가 7번째와 12번째에 위치하고 있다는 의미이다.


toarry() 멤버를 통해 전체 ndarray를 출력해보자.

print(new_post_vec.toarray())

하지만 책이 설명하는 것과 동일한 결과가 나오지 않았다. 아마도 한글은 형태소 분석을 해야 원하는 결과가 나올 것 같다.


형태소 분석기를 사용하여 형태소를 분석하자. 그리고 형태소 분석된 게시물을 다시 벡터화를 해보자.

from konlpy.tag import Mecab
pos_tagger = Mecab()

posts_tokens = [' '.join(pos_tagger.morphs(sentence)) for sentence in posts]
posts_tokens


형태소 분석된 게시물을 벡터화한다.

X_train = vectorizer.fit_transform(posts_tokens) 



그리고 새로운 게시물도 형태소 분석을 한다.

new_post = "이미징 데이터베이스는 저장한다."
new_post_tokens = ' '.join(pos_tagger.morphs(new_post))
new_post_tokens


새로운 게시물을 벡터화하고 new_post_vec를 출력해본다.

new_post_vec = vectorizer.transform([new_post_tokens])
print(new_post_vec)


ndarray도 출력해본다. 새로운 게시물의 벡터가 5번째, 11번째, 14번째, 17번째에 위치한다는 예상했던 결과가 나왔다.

print(new_post_vec.toarray())




벡터 사이의 거리 구하기

이제 새로운 게시물(new_post_vec)과 기존 게시물(posts)들 각각에 대해 거리를 계산해보자. 두 벡터 사이의 유클리드 거리를 계산하여 유사성을 측정한다.

우선 거리를 구하는 dist_raw() 함수 정의한다. np.linalg.norm() 함수를 사용하면 최단 거리를 계산할 수 있다.

import numpy as np
def dist_raw(v1, v2):
  delta = v1 - v2
  return np.linalg.norm(delta.toarray())


dist_raw() 함수를 사용하여 이전 게시물과 기존 게시물의 거리를 계산하여 출력한다. 그리고 유사도가 가장 높은 게시물을 찾아보자.

import sys
best_dist = sys.maxsize
best_doc = None
best_i = None
 
for i, post in enumerate(posts):
    post_vec = X_train.getrow(i)
    d = dist_raw(post_vec, new_post_vec)
    print("=== Post %i with dist = %.2f: %s" % (i, d, post))
    if d < best_dist:
        best_dist = d
        best_i = i
 
print("Best post is %i with dist=%.2f" % (best_i, best_dist))

3번 게시물이 새로운 게시물과 거리가 가장 가깝다는 결과가 나왔다. 그러나 3번, 4번 게시물을 보면 이상한 점이 있다. 4번 게시물은 3번 게시물을 복사&붙여넣기 한 것이다. 따라서 3번 게시물처럼 4번 게시물도 새로운 게시물과도 유사하다는 결과가 나와야 한다.


해당 벡터의 feature를 출력해보면 그 이유를 알 수 있다.

이를 교정하기 위해서는 카운트 벡터를 정규화해야한다. 위에서 정의한 거리 구하는 함수 dist_raw()를 수정함으로써 문제를 간단히 해결할 수 있다.


카운터 벡터 정규화하기

원시 벡터(raw vectors)가 아닌 정규화된 벡터 거리를 계산하기 위한 함수 dist_norm()를 정의한다. 이 함수는 각 벡터의 norm을 나눈 후에 거리를 계산한다.

def dist_norm(v1, v2):
    v1_normalized = v1/np.linalg.norm(v1)
    v2_normalized = v2/np.linalg.norm(v2)
    delta = v1_normalized - v2_normalized
    return np.linalg.norm(delta)


이 함수를 사용하여 유사도를 측정한 결과를 출력해보자.

=== Post 0 with dist = 3.32: 이 글은 머신러닝에 관한 글이다. 사실은 재미없는 내용을 포함하고 있다.
=== Post 1 with dist = 1.41: 이미징 데이터베이스는 저장 기능을 제공한다.
=== Post 2 with dist = 2.00: 대부분의 이미징 데이터베이스는  이미지를 영구적으로 저장한다.
=== Post 3 with dist = 1.00: 이미징 데이터베이스는 데이터를 저장한다.
=== Post 4 with dist = 1.00: 이미징 데이터베이스는 데이터를 저장한다. 이미징 데이터베이스는 데이터를 저장한다. 이미징 데이터베이스는 데이터를 저장한다.
Best post is 3 with dist=1.00


이제 원하는 결과가 나왔다. 3번 게시물과 4번 게시물도 동일한 결과가 나왔다.


여기까지 읽어주셔서 감사합니다.


이전글
Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

개념은 알 것 같은데, 자세한 내용은 좀 어렵네요^^ 머신러닝도 관심사인데 진도가 쉽게 나가질 않습니다. 앞으로도 좋은 포스팅 기대할께요~ 언젠가 다 이해할 수 있는 날이 오겠죠^^

저도 관심을 가지고 시작했는데 하면 할 수록 점점 어렵네요. 능력이 되는데 까지는 해 볼려고 합니다.

열심히 찾아보겠습니다~많이 읽다보면 조금씩 더 이해가 되겠죠^^

아직 Payout 되지 않은 관련 글
  1. 파이썬으로 스팀잇 형태소 분석하기 #2 - 구름단어 만들기 ( 89.31 % )
  2. 3-6 XOR 논리 처리를 위한 Neural Network(NN) 구성 ( 89.12 % )
  3. Tensorflow 사용해보기 ( 88.32 % )
  4. tensorflow로 딥러닝 교육 ( 88.11 % )
  5. [D3.js] 버전에 따른 사라진 함수 복원 ( 87.99 % )
모든 기간 관련 글
  1. D3.js Data 실시간 처리 ( 92.76 % )
  2. 2-10 Rosenblatt N = 2 Perceptron Weight Update 알고리듬 Processing 코딩 ( 91.55 % )
  3. [EOSIO dapp]튜토리얼 따라하기 v.1.2.0 - Multi Index Table ( 90.81 % )
  4. [js] #001 global objet ( 90.70 % )
  5. Python Basic Syntax ( 90.64 % )

인터레스팀(@interesteem)은 AI기반 관심있는 연관글을 자동으로 추천해 주는 서비스입니다.
#interesteem 태그를 달고 글을 써주세요!

어뷰징 찾아내는건가염? 옹~^^

아마도 어려울 것 같아요.
사실은 어떻게 해야할지 모르겠어요.ㅎㅎ
어뷰징 계정이 없어졌으면 좋겠어요😀

이오스 계정이 없다면 마나마인에서 만든 계정생성툴을 사용해보는건 어떨까요?
https://steemit.com/kr/@virus707/2uepul

Congratulations @anpigon! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

Award for the number of comments

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Support SteemitBoard's project! Vote for its witness and get one more award!

잘보고 가용 ㅎㅎ

  ·  6 years ago (edited)

감사합니다.😀

저도 요즘 cnn 공부하면서 효과적인 짤빵 관리와 태깅을 나름 연구중이긴 한데 결과는 별로네요 ㅜㅜ

저는 뉴럴 네트워크는 너무 어려워서 공부할 엄두도 못내고 있습니다. 그래서 쉬운거부터 따라하면서 공부하고 있어요.
원사마님은 CNN 으로 멋진걸 구현 중이신가봐요? 연구 결과가 무척 궁금합니다. ㅎㅎ

Posted using Partiko Android

[kr-event] 세계 최초 EOS 기축 암호화폐 거래소 CMO 인터뷰 / 최대 $0.4 보팅

리스팀 감사합니다^^

최신 글에 $0.2씩 보팅합니다.


프로그래머가 되고 싶습니다 ㅜ

직장 생활이랑 병행하는게 쉽지 않네요

프로그래머는 추천하지 않습니다. 밤새는 일이 많거든요.ㅋㅋ 그리고 회사 업무랑 개발을 병행하려면 잠을 줄이시게 될지도..ㅎㅎ

Hi @anpigon!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your UA account score is currently 0.967 which ranks you at #52639 across all Steem accounts.
Your rank has dropped 710 places in the last three days (old rank 51929).

In our last Algorithmic Curation Round, consisting of 426 contributions, your post is ranked at #268.

Evaluation of your UA score:
  • Only a few people are following you, try to convince more people with good work.
  • You have already convinced some users to vote for your post, keep trying!
  • You have already shown user engagement, try to improve it further.

Feel free to join our @steem-ua Discord server

표절프로그램으로도 불펌러들을 쉽게 찾을수 있습니다

표절프로그램이라는 것이 있군요. 한번 찾아봐야겠어요. 감사합니다.😀

Posted using Partiko Android