見出し画像

自然言語処理で思想家の文書特徴を把握する

今回のプログラムのねらい

主だった近代日本思想家から「経験」にまつわる論文を選び、それらの文書特徴を把握する。
自然言語処理でよく使われる手法である、re.subを使った正規表現によるクレンジング、janome.tokenizerによる形態素解析、part_of_speechによる特定品詞の抽出、ストップワード削除、word2vecによる単語のベクトル化、などによって特徴把握を目指します。

環境

  • Python 3.8.10

  • Google Colaboratory

プログラムの作成手順

①データの抽出

青空文庫トップページから、1 哲学12 東洋思想121 日本思想の中から抽出しました。

②データの前処理

正規表現によって、今回の解析結果に不要と思われる、英数字、記号類、改行などを削除します。

import re

text = open("/content/drive/MyDrive/ColabNotebooks/test-text/text_nishida_zen.txt","r") 
cont = text.read()
text.close()

cont = re.sub("[a-xA-Z0-9_]","",cont)
cont = re.sub("[!-/:-@[-`{-~]","",cont)
cont = re.sub(u'\n\n', '\n', cont)
cont = re.sub(u'\r', '', cont)

③形態素解析

janomeという形態素解析エンジンを使います。テキストを、意味をもつ表現要素の最小単位である形態素ごとに分割します。品詞の判定、分かち書き(単語に分割)を実行します。

# janomeのTokenizerモジュールをインポートします。
from janome.tokenizer import Tokenizer

# Tokenizerインスタンスを生成し、形態素解析したい文章をtokenizeメソッドに渡します。
t = Tokenizer()
tokens = t.tokenize(cont)
for token in tokens:
    print(token)

例えば西田幾多郎『善の研究』の冒頭部分を上記のコードによって形態素解析すると、以下のように出力されます。

経験 名詞,サ変接続,*,*,*,*,経験,ケイケン,ケイケン
する 動詞,自立,*,*,サ変・スル,基本形,する,スル,スル
という 助詞,格助詞,連語,*,*,*,という,トイウ,トユウ
の 名詞,非自立,一般,*,*,*,の,ノ,ノ
は 助詞,係助詞,*,*,*,*,は,ハ,ワ
事実 名詞,副詞可能,*,*,*,*,事実,ジジツ,ジジツ
其儘 名詞,一般,*,*,*,*,其儘,*,* ( 記号,括弧開,*,*,*,*,(,(,( そのまま 副詞,一般,*,*,*,*,そのまま,ソノママ,ソノママ )
記号,括弧閉,*,*,*,*,),),)
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
知る 動詞,自立,*,*,五段・ラ行,基本形,知る,シル,シル

この中から今回使用する、名詞・動詞・形容詞・形容動詞だけを抽出します。
また、動詞・形容詞・形容動詞については、活用形を含んだままだと解析しづらいので、基本形を使用するようにします。

def tokenize(cont):
  t = Tokenizer()
  tokens = t.tokenize(cont) 
  # 取り出した品詞が入るための空の箱word = []を作っておきます。
  word = []
  stop_word = create_stop_word()

  for token in tokens:
    part_of_speech = token.part_of_speech.split(",")[0]
    print(part_of_speech)
    if part_of_speech == "名詞":
      print('名詞:', token.surface)
      if not token.surface in stop_word:
        word.append(token.surface)        
    if part_of_speech == "動詞":
      if not token.base_form in stop_word:
        word.append(token.base_form)
    if part_of_speech == "形容詞":
      if not token.base_form in stop_word:
        word.append(token.base_form)        
    if part_of_speech == "形容動詞":        
      if not token.base_form in stop_word:
        word.append(token.base_form)
  return word

④ストップワードの作成

今回のねらいに関係なさそうな言葉をストップワードとして省きます。
まず、日本語のストップワードが既に登録されているSlothlibを使って取り除きたいと思います。
さらに、自分で不要そうなワードを、変数my_stop_wordに格納してストップワードリストに追加します。

def create_stop_word():
    target_url = "http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt"
    r =requests.get(target_url)
    stop_word=str(r).split() 
    my_stop_word=['もの', 'なる', 'する', 'れる', 'こと', 'できる', 'いる', 'これ'] 
    stop_word.extend(my_stop_word)
    return stop_word

⑤word2vecで学習

Word2Vecとは、文章に含まれるワードを「数値ベクトル」に変換し、その意味を把握していくという自然言語処理の手法です。
Word2Vecのモデルによって、ワード間の意味的な距離を定量的に表したり、単語同士で意味の足し算や引き算ができたりします。

sentence = [tokenize(cont)]
model = word2vec.Word2Vec(sentence, size=200, min_count=4, window=4, iter=50)

⑥類似度を計算する

most_similarによって、入力したワード(下のコードでは'経験')に対して意味的に近いワード、およびどれほど近いかを数値で出力してくれます。
topn=10で、1位~10位までを出力してくれます。

print(model.wv.most_similar(positive=[u"経験"], topn=10))

手順①〜⑥までをまとめると

作成したプログラム

from janome.tokenizer import Tokenizer
from gensim.models import word2vec
import re
import requests


text = open("書類のパス","r") 
cont = text.read()
text.close()

cont = re.sub("[a-xA-Z0-9_]","",cont)
cont = re.sub("[!-/:-@[-`{-~]","",cont)
cont = re.sub(u'\n\n', '\n', cont)
cont = re.sub(u'\r', '', cont)

def tokenize(cont):
  t = Tokenizer()
  tokens = t.tokenize(cont) 
  word = []
  stop_word = create_stop_word()

  for token in tokens:
    part_of_speech = token.part_of_speech.split(",")[0]
    print(part_of_speech)
    if part_of_speech == "名詞":
      print('名詞:', token.surface)
      if not token.surface in stop_word:
        word.append(token.surface)        
    if part_of_speech == "動詞":
      if not token.base_form in stop_word:
        word.append(token.base_form)
    if part_of_speech == "形容詞":
      if not token.base_form in stop_word:
        word.append(token.base_form)        
    if part_of_speech == "形容動詞":        
      if not token.base_form in stop_word:
        word.append(token.base_form)
  return word

def create_stop_word():
    target_url = "http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt"
    r =requests.get(target_url)
    stop_word=str(r).split() 
    my_stop_word=['もの', 'なる', 'する', 'れる', 'こと', 'できる', 'いる', 'これ'] 
    stop_word.extend(my_stop_word)
    return stop_word

sentence = [tokenize(cont)]
model = word2vec.Word2Vec(sentence, size=200, min_count=4, window=4, iter=50)
print(model.wv.most_similar(positive=[u"経験"], topn=10))

プログラム実行の結果

西田幾多郎の実行結果

西田の『善の研究』第1章(1911年)において、「経験」に近い言葉上位10単語を示します。

1位:'純粋', 0.8694230318069458
2位:'主客', 0.8483998775482178
3位:'判断', 0.8320882320404053
4位:'現前', 0.8295841217041016
5位:'直接', 0.8282835483551025
6位:'事実', 0.8262712955474854
7位:'範囲', 0.8198851346969604
8位:'入れる', 0.801323652267456
9位:'別', 0.7928428649902344
10位:'超越', 0.7881696224212646

第1位の'純粋'は「純粋経験」という単語が分かれて抽出されていますので、モデルの調整が必要ですね。第2位以降を見ると、直接の事実、まさに現前するものという特徴が見られそうです。

戸坂潤の実行結果

戸坂の「哲学の現代的意義」(1966年)において、「経験」に近い言葉上位10単語を示します。

1位:'過去', 0.9673113822937012
2位:'人々', 0.9379932880401611
3位:'形態', 0.9264334440231323
4位:'ロゴス', 0.9061765670776367
5位:'かくれる', 0.8870216012001038
6位:'知能', 0.8865772485733032
7位:'趣味', 0.8761657476425171
8位:'彼', 0.8757074475288391
9位:'従う', 0.8677871227264404
10位:'意識', 0.858801007270813

「ロゴス」「知能」「意識」などからは、経験と知識や論理的思考との結びつきという特徴が見られます。

三木清の実行結果

三木の『人生論ノート』(1954年)において、「経験」に近い言葉上位10単語を示します。

1位:'新しい', 0.8461295366287231
2位:'浪漫', 0.7994835376739502
3位:'新た', 0.7598129510879517
4位:'漂泊', 0.7372455596923828
5位:'既知', 0.7275353670120239
6位:'機械', 0.7264443635940552
7位:'習慣', 0.7163444757461548
8位:'近い', 0.7129574418067932
9位:'あわただしい', 0.7056584358215332
10位:'感', 0.7038125395774841

「新しい」「新た」や「浪漫」「機械」など、経験に無関係そうなワードが抽出されています。そもそも、意味的な距離を示す数値が第1位でも0.846と低いので、特徴を捉えるには他の手法も取り入れる必要がありそうです。




この記事が気に入ったらサポートをしてみませんか?