MeCab使います。
def analysis(sentence):
"""
# 与えられたテキストに対し、形態素解析を行います
#
# @param string sentence 形態素解析を行いたいテキストを渡します
# @return list 形態素解析の結果が、リスト型で返ります
"""
# 辞書をneologdを指定して、MeCabを起動
# tagger = MeCab.Tagger(' -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')
tagger = MeCab.Tagger()
# 形態素解析を実行
node = tagger.parseToNode(sentence)
# 形態素解析結果を保持しておく変数
result = []
# 形態素分繰り返す
while node:
# タグ情報を取得を取得
tag_line = node.feature
# カンマ区切りのタグ情報を、カンマでスピリット
tags = tag_line.split(',')
# 最初のノイズ除去として、名詞・動詞・形容詞のみを残す
if (tags[0] == '名詞') or (tags[0] == '動詞') or (tags[0] == '形容詞'):
# データを変数に追加(その語句の原型を追加)
result.append(tags[6])
# 次のワードへポインタを動かす
node = node.next
# 結果を返す
return result
def loadFile(file_path):
"""
# 引数で指定されたファイルを1行ずつ読み込み、配列にして返します。
#
# @param string file_path 形態素解析を行いたいテキストをまとめたファイル
"""
# 結果として返す値を入れる変数
result = []
# 読み込むファイルをオープンする
fp = open(file_path, 'r')
# 全行一気に読み込む
result = fp.readlines()
# ファイルのクローズ
fp.close()
# データを返す
return result
def excludeStopWords(file_path, word_list):
"""
# 指定したストップワードリストを除外します
#
# @param string file_path 除外したいワードが書かれているファイル
# @param list word_list ワード(語句)が格納されているリストオブジェクト
# @param list ストップワードを除外した配列が返ります
"""
# ストップワードリストを読み込むための変数
stopwords = []
# ファイルのオープン(文字コードはUtf8)
fp = open(file_path, 'r', -1, 'utf-8')
# 全行読み込み
stopwords = fp.read()
# お返し
fp.close()
# 改行コードで分割
stopwords = stopwords.split("
")
# ストップワードを除外する
result = list(filter(lambda x: x not in stopwords, word_list))
# 除外したデータを返す
return result
def calcTf(sentence):
"""
# 与えられたテキストのtf値を求めます
#
# @param string sentence tf値を計算したい文章を入力
# @return dict 単語とtf値が返ります
"""
# 文章を形態素解析
morphological = analysis(sentence)
# ストップワードを除去
morphological = excludeStopWords('stop_word_list.csv', morphological)
# 全形態素数
morphological_number = len(morphological)
# 形態素の数をカウントしていく
result = {} # 結果は辞書配列にしておく(dict型)
for value in morphological:
# まとめている変数に、すでにその形態素がキーとして存在しているかのチェック
if value in result:
# 値を保持している場合
result[value] = result[value] + 1
else:
# 存在していない場合
result[value] = 1
# tf値の計算
for value in result:
# tf = その単語の登場回数 / 全単語の登場回数
result[value] = float(result[value]) / morphological_number
# 返却
return result
def calcIdf(sentence_list):
"""
# 与えられた文章集合のIDFを計算します
# キーにワード、値にtf-idfの値というペアのdict型の配列が返ります
#
# @param list sentence_list IDF値を計算したい文章集合
# @return dict 単語とIdfの配列が返ります
"""
# 文書集合の数
sentence_number = len(sentence_list)
# 与えられた全ての文章を形態素解析する
word_list = {} # 出てきた単語とその登場回数を保存しておく変数
for value in sentence_list:
# 形態素解析
morphological = analysis(value)
# ストップワードを除去
morphological = excludeStopWords('stop_word_list.csv', morphological)
# データを全て登録
temp_word_list = [] # 一時的に形態素を保存しておく変数
for v in morphological:
# 出てきた形態素の原型を溜め込んでいく
temp_word_list.append(v)
# 形態素の重複を削除
temp_word_list = list(set(temp_word_list))
# 抽出した単語リストを、全体を保存している変数に入れる
for v in temp_word_list:
# 単語がすでに変数に存在するか
if v in word_list:
# 存在している場合は、センテンス数を加算
word_list[v] = word_list[v] + 1
else:
# 存在していなければセンテンス数を1にセット
word_list[v] = 1
# IDFをを計算していく
for value in word_list:
# idf = log( センテンス毎の単語の登場回数 / センテンス数 )
idf = float(word_list[value]) / sentence_number + 1
word_list[value] = math.log(10, idf)
# 結果を返す
return word_list
def calcTfIdf(sentence_list):
"""
# tf-idfを計算し、その結果を単語とtf-idf値でまとめたdict型の配列で返します。
#
# @param list tf-idf値を求めたい文章集合
# @return list 単語とtf-idf値をまとめたlist型の配列
"""
# そのセンテンス内のtf-idfのdictを一時的に入れておく変数
sentence_tfidf_list = {}
# 各ワードのidf値を求める
idf_list = calcIdf(sentence_list)
# センテンス毎にtf-idfを出す
for sentence in sentence_list:
# tf値の計算
tf_list = calcTf(sentence)
# tfリストの中にある単語のtf-idfを計算していく
for value in tf_list:
# その語句のtf-idfの計算
tf_idf = float(tf_list[value]) * float(idf_list[value])
# 変数に保存しておく
sentence_tfidf_list[value] = tf_idf
# 結果を返す
return sentence_tfidf_list
def createVector(dimensions, sentence_list):
"""
# 与えられた語句を次元とした特徴ベクトル表を作成します
#
# @param list dimensions 次元とする語句を配列で渡す
# @param list sentence_list ベクトル化したい文章リストを、リスト形式で渡す
# @return list ベクトル表を多次元リスト形式で返す
"""
# ベクトルデータを入れるリスト
vector = []
# センテンスを形態素解析
for value in sentence_list:
# 形態素解析を行う
morphological = analysis(value)
# ストップワードの除去
morphological = excludeStopWords('stop_word_list.csv', morphological)
# このセンテンスのベクトルデータを一時的に入れていおく箱
temp_vector = []
# 次元と比較して、ベクトルデータを作成していく
for dimension in dimensions:
# ベクトルの次元に、データが有れば1、なければ0の二値ベクトルの作成
if dimension in morphological:
# 含まれていれば1
temp_vector.append(1)
else:
# 含まれていなければ0
temp_vector.append(0)
# 出来上がったベクトルのデータを保存
vector.append(temp_vector)
# ベクトルデータを返却
return vector
def calcAllCosineSimilarity(vector, row_num):
"""
# 与えられたベクトルデータのうち、row_numで渡された行番号との類似度を計算します
#
# @param list vector 上記のcreateVectorメソッドで作ったベクトル表
# @param int row_num 計算したいデータの行番号
# @return dict keyに行番号、valueに類似度の組み合わせを持つ辞書配列が返る
"""
# ========================
# この辺にバリデーションを書け
# ========================
# 引数で指定された行のベクトル情報を取得
own_vec = vector[row_num]
# 類似度を保存しておく変数
similarity = {}
# 類似度を計算していく
count_row = 0 # ベクトルテーブルの行数をカウントする変数
for vec in vector:
# ループの中で使う変数定義場
count_col = 0 # ベクトルの何列目かをカウントする変数
numer = float(0) # 分子
denom = float(0) # 分母
own_denom = float(0) # 左側ルート
other_denom = float(0) # 右側ルート
cos = float(0) # コサイン類似度
# ベクトル計算開始
for v in vec:
# コサイン類似度を計算するための分子計算
numer = numer + (own_vec[count_col] * v)
# コサイン類似度を計算するための分母計算
own_denom = own_denom + own_vec[count_col] * own_vec[count_col]
other_denom = other_denom + v * v
# 次の列へ
count_col = count_col + 1
# コサイン類似度の計算
denom = math.sqrt(own_denom) * math.sqrt(other_denom)
if denom != 0:
cos = numer / denom
else:
cos = 0
# 類似度情報を保存
similarity[count_row] = cos
# 次の行へ
count_row = count_row + 1
# 類似度リストの返却
return similarity
def calcCosineSimilarity(vector, row_num1, row_num2):
"""
# 与えられたベクトルリストから、row_num1とrow_num2で与えられた行番号のコサイン類似度を計算して返す
#
# @param list vector ベクトルの次元が格納されたリスト
# @param int row_num1 行番号
# @rapam int row_num2 行番号
# @return float コサイン類似度の計算結果
"""
# 類似度を計算したいベクトルを抜き出す
vec1 = vector[row_num1] # row_num1のベクトル
vec2 = vector[row_num2] # row_num2のベクトル
# 2つのコサイン類似度を計算するのに必要な変数たち
cos = float(0) # コサイン類似度
numer = float(0) # 分子
denom_left = float(0) # 分母(左)
denom_right = float(0) # 分母(右)
# ベクトルの次元数分繰り返す
for v_num in range(0, len(vec1) - 1):
# 分子の計算
numer = numer + (vec1[v_num] * vec2[v_num])
# 分母の計算
denom_left = denom_left + (vec1[v_num] * vec1[v_num])
denom_right = denom_right + (vec2[v_num] * vec2[v_num])
# コサイン類似度を計算
if denom_left * denom_right == 0:
# 0割対策
cos = 0
else:
# 分母が0以外なら普通にこいさん類似度を求める
cos = numer / (math.sqrt(denom_left) * math.sqrt(denom_right))
# コサイン類似度を返却
return cos
この記事を書いた人
Nな人(えぬなひと)。
Nは本名から取っています。
Laravelが大好きなPHPerで、WEBを作るときはLaravelを技術スタックに絶対推すマン。
PHP、Pythonと、昔はperlを書いていたP言語エンジニア。
最近はNimを書いたりしています。
Nは本名から取っています。
Laravelが大好きなPHPerで、WEBを作るときはLaravelを技術スタックに絶対推すマン。
PHP、Pythonと、昔はperlを書いていたP言語エンジニア。
最近はNimを書いたりしています。