#はじめに
以下の記事を眺めていたら、自然言語処理を使って、大量データの中から、自分が求めているデータを抽出できるのって素敵だなーって感じていました。
なので、超シンプルな検索エンジンを作りました。
作った検索エンジンの仕組み
①蓄積した文章群から言語モデル(今回はtfidf)、ベクトルを作成。
②入力文章を言語モデルからベクトル化
③入力文章ベクトルと、蓄積した文章群の一つ一つとcos類似度を計算
④cos類似度が高い順にソートして、出力
#ソースコードはこんな感じ
twitterから取得したデータを用いて、言語モデル、ベクトル作成。
※データ取得については、この記事の本質ではないので、今回は割愛します。
#データサイエンティスト、自然言語処理、機械学習を含むtwitterデータを使います。
#search_tweet_listが、取得したデータを保持しているリスト変数です。
#tfidfのために、twitterデータを分かち書きする関数
def wakati_word_list_create(sentences, get_word_class):
#複数文から、指定の品詞(GET_WORD_CLASS)を抽出した単語リスト
sentences_word_list = []
for sentence in sentences:
#一文から、指定の品詞(GET_WORD_CLASS)を抽出した単語リスト
one_sentence_word_str = ''
#形態素解析
node = mecab.parseToNode(sentence)
while node:
#語幹
word = node.feature.split(",")[-3]
#品詞
word_class = node.feature.split(",")[0]
#(指定の品詞(GET_WORD_CLASS)である) and (語幹が*のもの(つまり未知語))場合は、単語リストに追加
if word_class in get_word_class and word != '*':
one_sentence_word_str = one_sentence_word_str + " " + word
node = node.next
sentences_word_list.append(one_sentence_word_str)
return sentences_word_list
#twitterデータから、指定品詞の分かち分割形式の単語リストを生成
GET_WORD_CLASS = ['名詞', '形容詞']
wakati_word_list = wakati_word_list_create(search_tweet_list, GET_WORD_CLASS)
#tfidfベクトル化
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(use_idf=True, token_pattern=u'(?u)\\b\\w+\\b')
#言語モデル作成
tfidf_model = tfidf.fit(wakati_word_list)
#ベクトル空間作成
vectors = tfidf_model.transform(wakati_word_list).toarray()
tfidfとcos類似度で類似度を計算し、降順ソートして、出力する
import numpy as np
#cos類似度を計算する関数
def cos_sim(v1, v2):
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
#検索時に何件を表示させるか
OUTPUT_NUMBER = 5
#検索したい文章、キーワード(入力データ)
search_sentence = ["ここに、なに調べたいかを書いてね"]
#wakati_word_list_createは、上のソースコードに書いている関数です。
wakati_input_texts = wakati_word_list_create(search_sentence, GET_WORD_CLASS)
#作った言語モデルはここで使うよ
tfidf_vectors = tfidf_model.transform(wakati_input_texts).toarray()
similars_map = {}
for sentence_id, sentence_vector in enumerate(vectors):
similars_map[sentence_id] = cos_sim(tfidf_vectors[0], sentence_vector)
sorted_similars_map = sorted(similars_map.items(), key=lambda x: -x[1])
#任意件数(OUTPUT_NUMBER)を表示
print("入力文章:{}".format(search_sentence[0]))
for break_flag, similar_map in enumerate(sorted_similars_map):
if break_flag == OUTPUT_NUMBER:
break
sentence_id = similar_map[0]
sentence_similar = similar_map[1]
if np.isnan(sentence_similar):
if break_flag == 0:
print("類似データは1件もなかったよ")
break
print("==========================================")
print("類似度 : {}".format(sentence_similar))
print("{}".format(search_tweet_list[sentence_id]))
print("")
実行結果
ええ感じやでー( *´艸`)
特に結果②は、ちゃんとイベント情報をとれてるわ!素敵!!
#もっと良くするには、を考えてみた
これを作ってみて、感じたのは、ベクトル化の手法がかなり大事だなって
ことです。
今回は、tfidfでベクトル化をしましたが、BM25、SCDV、word2vecなどで、全然違うでしょう。さらに、感情評価やネガポジ(極性)を取り込んでベクトル化してみたら、ネガポジの観点を含むような、ちょっと変わった検索エンジンができますね!
なによりも、こういうのには、Bertとか使ってみたいですね!!!どんな精度の検索がされるか、すごく気になります!!!!スペック足りないので、僕の家では作れないですけどね。。。(涙)
#最後に
最後まで読んで頂き、ありがとうございました。
今回のソースコード書いていて、もっと、色々なNLPの手法について勉強してみたいと思いました。
次は、LDAとかやってみて、なにか作ってみようかな~!!('◇')ゞ