🐷

【自然言語処理】Doc2Vecで文章ベクトルを算出し、類似文書検索をやってみた

2022/09/03に公開

はじめに

以前、BERTを使って歌詞の文章ベクトルを算出し可視化する試みを行いました。BERTは優秀なんですが、入力できるトークン数が512に限られるため、長い文章のベクトル算出には向いていないんですよね。
 
今回は、上場企業約2,500社が有価証券報告書で書いている割と長文の文章について、Doc2Vecを使って文章ベクトルを算出し、あわせて、文章ベクトルから類似文書を検索してみました。
個人的には、BERTよりもDoc2Vecの方が納得感のいく結果を出している気がしています。
ここでは、文章ベクトルの算出方法・類似文書検索方法について、お伝えしていきたいと思います。

 
https://zenn.dev/robes/articles/fd3315881f8874

文章ベクトルのイメージ

①野球を観戦した
②サッカーの試合を見た
③犬の散歩にでかけた
の3つの文章を2次元のベクトルに変換することを考えてみましょう。
文章の内容を考えると①と②が近く、③が少し離れているイメージですね。
ここでは2次元で表していますが、実際は300次元ぐらいで算出することが一般的のようです。

 

文章ベクトルを算出するデータの準備

文章ベクトルを算出し類似文書を検索するための有価証券報告書のテキストデータを準備します。
取得の方法は以下のサイトをご覧ください。
https://zenn.dev/robes/articles/4ab5a7f992000d

import pandas as pd
df = pd.read_csv("/content/2203有報セット.csv",index_col=0)
df

企業別に「経営方針」「事業等のリスク」が格納されています。

 

MeCabと辞書(NEologd)のインストール

形態素解析ライブラリーであるMeCabと辞書をインストールします

# 形態素分析ライブラリーMeCab と 辞書(mecab-ipadic-NEologd)のインストール 
!apt-get -q -y install sudo file mecab libmecab-dev mecab-ipadic-utf8 git curl python-mecab > /dev/null
!git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git > /dev/null 
!echo yes | mecab-ipadic-neologd/bin/install-mecab-ipadic-neologd -n > /dev/null 2>&1
!pip install mecab-python3 > /dev/null

# シンボリックリンクによるエラー回避
!ln -s /etc/mecabrc /usr/local/etc/mecabrc
# 辞書のディレクトリを確認
!echo `mecab-config --dicdir`"/mecab-ipadic-neologd"

 

文章ベクトル作成のためのトークナイザー(関数)の作成

  1. 単純に文章をクリーニングし、わかち書きだけをする関数
  2. わかち書きした単語単位で要素に区切って、文書(企業)単位でリストにする関数

import MeCab
import re

#Neologdによるトークナイザー(文書ベクトル作成用・わかちだけ)
def mecab_tokenizer(text):

    replaced_text = text.lower()
    replaced_text = re.sub(r'[【】]', ' ', replaced_text)       # 【】の除去
    replaced_text = re.sub(r'[()()]', ' ', replaced_text)     # ()の除去
    replaced_text = re.sub(r'[<><>]', ' ', replaced_text)       # 【】の除去
    replaced_text = re.sub(r'[[]\[\]]', ' ', replaced_text)   # []の除去
    replaced_text = re.sub(r'[@@]\w+', '', replaced_text)  # メンションの除去
    replaced_text = re.sub(r'\d+\.*\d*', '', replaced_text) #数字を0にする

    path = "-d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd"
    mecab = MeCab.Tagger(path)
    parsed_lines = mecab.parse(replaced_text).split("\n")[:-2]
    
    # 表層形を取得
    surfaces = [l.split('\t')[0] for l in parsed_lines]

    return ' '.join(surfaces)

#分かち書きした単語単位で要素に区切って、ひとつひとつの文章単位でリストにする関数
#column_numberで経営方針か事業等のリスクを指定
def make_sentences(df,column_number):
    sentences=[]
    for i in range(len(df)):
        text = df.iloc[i,column_number]
        text = mecab_tokenizer(text)
        sentences.append(text.split(" "))
    return sentences

 

関数を実行

dfのテキストデータに関数をあてていきます。
今回は事業等のリスクを対象にします(2列目)

sentences = make_sentences(df,2)

 

sentencesの出力結果

sentences[0]を見てみると以下のようになっています。

['事業', '等', 'の', 'リスク', '有価証券報告書', 'に', '記載', 'し', 'た', '事業', 'の', '状況', '、', '経理', 'の', '状況', '等', 'に関する', '事項', 'の', 'うち', '、', '投資', '者', 'の', '判断', 'に', '重要', 'な', '影響', 'を', '及ぼす', '可能性', 'の', 'ある', '事項', 'に', 'は', '以下', 'の', 'よう', 'な', 'もの', 'が', 'あり', 'ます', '。', 'なお', '、', '文中', 'における', '将来', 'に関する', '事項', 'は', '、', '有価証券報告書', '提出', '日', '現在', 'において', '当社', 'グループ', 'が', '判断', 'し', 'た', 'もの', 'で', 'あり', 'ます', '。', '特定', 'の', '取引先', '・', '製品', '・', '技術', '等', 'へ', 'の', '依存', 'の', 'リスク', 'フィルム', '事業', 'の', '新製品開発', '力', '当社', 'グループ', 'の', '収益', 'の', '大部分', 'は', '、', '多種', '多様', 'な', '機能', 'を', '有する', '各種', '工業', '材料', 'を', '製造', '販売', 'し', 'て', 'いる', 'フィルム', '事業', 'によって', 'おり', 'ます', '。', '当社', 'グループ', 'は', '継続', 'し', 'て', '市場', 'の', 'ニーズ', 'に', 'こたえる', '新製品', 'の', '開発', 'が', 'できる', 'と', '考え', 'て', 'おり', 'ます', 'が', '、', '当社', 'グループ', 'が', '業界', 'と', '市場', 'の', '変化', '、', '技術', 'の', '変化', 'を', '十分', 'に', '予測', 'でき', 'ず', 'に', '新製品', 'の', '投入', 'が', '遅延', 'し', 'た', '場合', 'もしくは', '競合', '他社', '、', '異', '業種', 'から', 'の', '競合製品', 'が', 'より', '低価格', 'で', '導入', 'さ', 'れ', '価格競争', 'が', '激化', 'し', 'た', '場合', '、', 'あるいは', '業界', 'の', '技術', 'の', '革新', 'により', '従来', 'の', '需要', 'が', '激減', 'し', 'た', '場合', 'に', 'は', '、', '収益性', 'を', '保つ', 'こと', 'が', '出来', 'ない', '可能性', 'が', 'あり', 'ます', '。', 'これら', 'の', 'リスク', 'を', '軽減', 'する', 'ため', '、', '競合', '情報', '及び', '市場', '情報', 'の', '収集', 'を', '強化', 'し', '、', '付加価値', 'の', '高い', '製品', 'の', '開発', 'を', '行い', '競合', '他社', 'と', 'の', '差別化', 'を', '行っ', 'て', 'おり', 'ます', '。', '特有', 'の', '法的', '規制', '・', '取引', '慣行', 'の', '影響', '①', '環境規制', 'の', '強化', '当社', 'グループ', 'は', '、', '機能性', 'フィルム', 'の', '製造工程', 'において', '有機溶剤', 'を', '使用', 'し', 'て', 'おり', 'ます', '。', 'この', '有機溶剤', 'は', '取り扱い', 'において', '、', '労働安全衛生法', '、', '毒物及び劇物取締法', '、', '消防法', '、', 'prtr', '法', '等', 'の', '法規制', 'を', '受け', 'て', 'おり', 'ます', '。', '当社', 'グループ', 'は', '、', '法規制', 'を', '遵守', 'する', 'とともに', '、', '工場', '、', '研究所', 'におきまして', 'は', '、', '環境', '目標', 'を', '設定', 'し', '、', '環境汚染', 'の', '防止', '、', '安全', '衛生', 'の', '推進', 'に', '努め', 'て', 'おり', 'ます', '。', '特に', '有機溶剤', '及び', '有機溶剤', 'ガス', 'に関しまして', 'は', '、', '現在', '最高', '水準', 'の', '技術', 'を', '導入', 'し', '、', '有機溶剤', '回収', 'や', '熱', '回収', 'を', '行っ', 'て', 'おり', 'ます', '。', '今後', '、', 'これら', 'の', '規制', 'の', '改廃', 'や', '新た', 'な', '法的', '規制', 'が', '設け', 'られる', '場合', 'に', 'は', '、', '新た', 'な', '設備投資', 'が', '必要', 'と', 'なり', '、', '経営成績', 'に', '影響', 'を', '及ぼす', 'こと', 'が', '考え', 'られ', 'ます', '。', 'これら', 'の', 'リスク', 'を', '軽減', 'する', 'ため', '、', '環境', 'に', '配慮', 'し', 'た', '溶剤', '等', 'の', '使用量', 'の', '少ない', '製造', 'プロセス', 'を', '重点的', 'に', '進め', 'て', 'おり', 'ます', '。', '②', '知的財産', '保護', 'の', '限界', '当社', 'グループ', 'は', '、', '他社', '製品', 'と', '差別', '化', 'する', 'べく', '、', '製品', '又は', '技術', 'に関して', 'は', '、', '特許', '等', 'の', '知的財産権', 'により', '積極的', 'に', '権利', 'の', '保護', 'を', '図っ', 'て', 'おり', 'ます', '。', 'しかしながら', '、', '特定', 'の', '地域', 'において', 'は', '、', 'その', 'よう', 'な', '法的', '保護', 'が', '不完全', 'で', 'ある', 'こと', 'により', '、', '当社', 'グループ', '製品', '・', '技術', 'が', '模倣', '又は', '解析', '調査', '等', 'さ', 'れる', 'こと', 'を', '防止', 'でき', 'ない', '可能性', 'が', 'あり', 'ます', '。', '重要', 'な', '訴訟事件', '等', 'の', '発生', 'の', '影響', '①', '知的財産権', '侵害', 'の', '可能性', '当社', 'は', '積極', '的', 'な', '特許', '出願', 'を', '行う', 'とともに', '、', '第三者', 'から', 'の', '特許侵害', '訴訟', 'を', '未然', 'に', '防止', 'する', 'ため', '、', '当社', '及び', '特許事務所', 'を', '通じ', 'た', '特許', '調査', 'を', '随時', '行っ', 'て', 'おり', 'ます', '。', 'しかしながら', '、', '第三者', 'の', '特許権', 'を', '侵害', 'し', 'て', 'い', 'ない', 'こと', 'を', '完全', 'に', '調査', 'し', '確認', 'する', 'こと', 'は', '極めて', '困難', 'で', 'あり', '、', '現時点', 'において', '当社', 'グループ', 'が', '認識', 'し', 'て', 'い', 'ない', '第三者', 'の', '特許', '等', 'の', '知的財産権', 'が', '存在', 'する', '可能性', 'は', '完全', 'に', 'は', '否定', 'でき', 'ず', '、', 'また', '今後', '、', '当社', 'グループ', 'が', '第三者', 'より', '特許権', 'その他', '知的財産権', 'の', '侵害', 'を', '理由', 'として', '訴訟', '提起', 'を', '受け', 'ない', 'という', '保証', 'は', 'あり', 'ませ', 'ん', '。', '当社', 'グループ', 'が', '第三者', 'から', '訴訟', '提起', '等', 'を', '受け', 'た', '場合', 'に', 'は', '、', '当社', 'は', '、', '弁理士', '・', '弁護士', 'と', '相談', 'の', 'うえ', '、', '個別具体', '的', 'な', '対応', 'を', '行っ', 'て', 'いく', '方針', 'で', 'あり', 'ます', 'が', '、', 'その', '対応', 'において', '多大', 'な', '費用', 'と', '時間', 'を', '要する', '可能性', 'が', 'あり', 'ます', '。', 'その', '結果', 'によって', 'は', '、', '当社', 'グループ', 'の', '事業戦略', 'や', '経営成績', 'に', '悪影響', 'が', '及ぶ', '可能性', 'が', 'あり', 'ます', '。', '②', 'その他', 'の', '訴訟', '提起', 'を', '受ける', '可能性', '当社', 'グループ', 'は', '、', '顧客満足度', 'に', '重点', 'を', '置い', 'て', '製品', 'の', '製造', '販売', 'を', '行っ', 'て', 'おり', 'ます', 'が', '欠陥', '等', 'の', '不具合', 'が', '発生', 'し', 'た', '場合', '、', '損害賠償', 'による', '利益', 'の', '喪失', '、', '当社', 'グループ', 'の', 'ブランド', 'に対する', '信頼', 'の', '喪失', '、', '補償', '費用', 'あるいは', '保険料', '等', 'の', '発生', 'が', '予測', 'さ', 'れ', 'ます', '。', 'その', '結果', '、', '経営成績', 'に', '大きく', '影響', 'を', '及ぼす', '可能性', 'が', 'あり', 'ます', '。', '固定資産', '減損', 'の', 'リスク', '当社', 'グループ', 'は', '、', '複数', 'の', '生産拠点', 'を', '所有', 'し', '、', 'また', '設備投資', 'を', '積極', '的', 'に', '実施', 'し', 'て', 'おり', 'ます', '。', '収益性', 'の', '低下', 'による', '大幅', 'な', '業績', 'の', '悪化', 'や', '固定資産', 'の', '市場価格', 'の', '下落', 'が', 'あっ', 'た', '場合', '、', '固定資産', '等', 'について', 'の', '減損損失', 'が', '発生', 'し', '、', '経営成績', '及び', '財政状態', 'に', '影響', 'を', '与える', '可能性', 'が', 'あり', 'ます', '。', 'これら', 'の', 'リスク', 'を', '軽減', 'する', 'ため', '、', '以下', 'の', '施策', 'を', '進め', 'て', 'まいり', 'ます', '。', 'a', '.', '新しい', '技術', '及び', '設備', 'を', '活用', 'し', 'た', '製造', 'の', '歩留', '向上', '並びに', '廃棄物', 'の', '削減', 'による', '製造原価', 'の', '低減', '。', 'b', '.', 'マーケット', 'の', '変化', 'へ', '柔軟', 'に', '対応', 'する', 'ため', '、', '開発', 'スピード', 'の', '向上', '及び', 'ニーズ', 'に', '合わせ', 'た', '製造', '対応', '。', 'c', '.', '製造', '在庫', 'リスク', 'を', '低減', 'さ', 'せる', 'ため', '受注', '生産', '方式', 'の', '採用', '。', 'その他', 'の', '事業', '等', 'の', 'リスク', 'について', '①', '天災', '、', '火災', '、', '事故', '等', 'の', '発生', 'が', '将来', 'の', '業績', 'に', '悪影響', 'を', '及ぼす', '可能性', '当社', 'グループ', 'は', '国内外', 'に', '所在', 'する', 'メーカー', 'より', '原材料', 'を', '調達', 'し', '、', '三重県', '、', '茨城県', '、', 'ジョージア州', '米国', 'に', '分散', '所在', 'する', '工場', 'にて', 'それぞれ', '製品', '製造', 'を', '行っ', 'て', 'おり', 'ます', '。', '原材料', 'の', '調達', '先', '工場', 'の', '所在', 'する', '地域', 'において', '地震', '等', 'の', '天災', 'あるいは', '、', '火災', 'や', '爆発事故', '等', 'が', '発生', 'し', 'た', '場合', 'は', '原材料', '調達', 'に', '支障', 'が', '発生', 'し', '生産', 'に', '影響', 'を', '及ぼす', '可能性', 'が', 'あり', 'ます', '。', 'また', '、', '同じく', '当社', 'グループ', 'の', '工場', '所在地', 'において', '地震', '等', 'の', '天災', 'が', '発生', 'し', 'た', '場合', 'あるいは', '、', '万一', '火災', '等', 'が', '発生', 'し', 'た', '場合', '、', '生産活動', 'が', '停止', 'する', 'こと', 'から', '経営成績', 'に', '重大', 'な', '影響', 'が', '生じる', 'こと', 'に', 'なり', 'ます', '。', 'また', '電力', '不足', 'による', '電力供給', 'の', '調整', 'が', '行わ', 'れ', 'た', '場合', '、', '生産活動', 'に', '影響', 'を', '受ける', '可能性', 'が', 'あり', 'ます', '。', 'これら', 'の', 'リスク', 'を', '軽減', 'さ', 'せる', 'ため', '、', '主要', '製品', 'の', '生産', '場所', 'の', '複数', '化', 'や', '、', '材料', 'サプライヤー', 'と', '連携', '強化', 'を', '進め', 'て', 'まいり', 'ます', '。', '②', '情報セキュリティ', 'について', '当社', 'グループ', 'は', '、', 'データ', 'キッチン', '事業', '及び', 'コンサルティング', '事業', 'において', '個人情報', 'を', '含む', '顧客情報', 'を', '取り扱っ', 'て', 'おり', 'ます', 'が', '、', 'これら', 'の', '情報', 'が', '漏洩', 'する', 'こと', 'が', 'あれ', 'ば', '、', '当社', 'グループ', 'の', '信用', 'が', '失墜', 'し', '、', '経営成績', 'に', '影響', 'を', '及ぼす', '可能性', 'が', 'あり', 'ます', '。', 'これら', 'の', 'リスク', 'を', '回避', 'する', 'ため', 'の', 'マニュアル', 'を', '作成', 'し', '対応', 'し', 'て', 'おり', 'ます', '。', '③', '在庫', '評価', 'の', '影響', '当社', 'グループ', 'は', '、', '国内', '、', '北米', '、', '東アジア', '及び', '欧州', 'に', 'フィルム', '事業', '製品', 'を', '安定', 'かつ', '迅速', 'に', '供給', 'する', 'ため', '、', '原材料', 'について', '一定量', '在庫', 'に', 'し', 'て', 'おり', 'ます', '。', 'そのため', '急激', 'な', '市場', '動向', 'の', '変化', 'により', '原材料', 'の', '評価損', 'が', '発生', 'する', 'リスク', 'が', 'あり', 'ます', '。', 'これら', 'を', '回避', 'する', 'ため', '、', '営業', '、', 'サプライヤー', 'と', 'の', '情報共有', 'の', '強化', '、', 'また', '材料', '品種', '、', 'サイズ', 'の', '標準化', 'を', '進め', '長期', '在庫', 'リスク', 'の', '低減', 'を', '進め', 'て', 'おり', 'ます', '。']

 

Doc2Vecによる文章ベクトルの算出

gensimuのDoc2Vecを使って、文章ベクトルを算出していきます。
ベクトルサイズは300、エポック数は20で学習し、算出していきます。少し時間がかかります。

from gensim.models.doc2vec import Doc2Vec, TaggedDocument
documents = [TaggedDocument(doc, [i]) for i, doc in enumerate(sentences)]
model = Doc2Vec(documents, size=300,  window=7, min_count=1, workers=4, epochs=20)

 

ベクトルのサイズを見てみましょう。

model.docvecs.vectors_docs.shape

2,573先で各300次元のベクトルができました。

(2573, 300)

 

類似文書の検索

商船三井、三井住友銀行、トヨタ自動車で類似文書を検索してみました。

index = df.reset_index().query('会社名 == "株式会社商船三井"').index
result = pd.DataFrame(model.docvecs.most_similar(index),columns=["index","類似度"])
result["corp"] = result["index"].apply(lambda x : df.iloc[x,3])
result

 

検索結果〜類似文書

海運会社の商船三井が作成した文章と類似した文章を検索した結果がこちらです。
ご覧いただくとわかように、海運会社が並んでいるんですよね。
私はこの結果を見た時、驚きました。
文章ベクトルが特徴量をちゃんと捉えているんですよね。

三井住友銀行と類似した文書

ちゃんと銀行が並んでいますね。

トヨタ自動車と類似した文書

2位にホンダ、5位にスズキとこちらもちゃんと計算されているようです。

 

モデルの保存

作成したモデルは、今後も使えるので保存しておきましょう。

import pickle
with open("/content/doc2vec_2203有報_事業等のリスク.pkl","wb") as f:
    pickle.dump(model,f)

 

さいごに

いかがでしたでしょうか。
私自身は、単語や文章をベクトルで数値化し、構造化データと同じように分析ができることに大変感銘を受けました。しかも、こうして類似文書検索をしてみると、文章ベクトル化の技術精度の良さを肌感覚で実感できる。
これからも、研究を続けていきたいと思います。

Discussion