単語感情極性対応表を利用して文章のポジティブ・ネガティブ判定を行う

言語処理

ごちゃごちゃいうよりまずはソース

ポジネガ計算プログラム

利用モジュール

  • GiNZA

ポジネガ判定にはタイトルでも示した単語感情極性対応表と、文章を形態素解析できるものが必要。

今回はGiNZAを利用して形態素解析を行う。

 

計算する文章

Yahooニュースより以下を引用。

第92回アカデミー賞授賞式が2月10日(日本時間)、米ロサンゼルスのドルビー・シアターで開催され、松たか子がイディナ・メンゼルら世界各国の“エルサ”と共に「イントゥ・ジ・アンノウン」の歌唱パフォーマンスに参加した。アカデミー賞授賞式での歌唱は日本人として初となる。

https://news.yahoo.co.jp/pickup/6350767

【北京共同】中国政府は10日、肺炎を引き起こす新型コロナウイルスによる中国本土の死者が908人になったと発表した。2002~03年に大流行した重症急性呼吸器症候群(SARS)の世界全体の死者数774人を超えた。感染者は4万171人に増えた。中国や各国は隔離や検疫による対策を急いだが、大規模な流行を防げず、封じ込めは難航している。

https://news.yahoo.co.jp/pickup/6350751

上はポジティブ、下はネガティブなパターンとして引用。

 

ソース

# coding:utf-8

#------------------------------------
#           インポートモジュール
#------------------------------------
import json
import spacy


#------------------------------------
#            グローバル変数
#------------------------------------
pnJson = 'pn_ja.json.org' # 単語感情極性対応表
coValue = 0.315 # 単語感情極性対応表がダークサイドなので値を補正する

#------------------------------------
#                関数
#------------------------------------

###単語感情極性対応表jsonを読み込んで辞書型配列を返す
def loadPnJson():
  f = open(pnJson, 'r')
  result = json.load(f)
  return result

### GiNZAで形態素解析するための関数
def analyzeSentence(_str):
  result = []
  nlp = spacy.load('ja_ginza') # ginzaのリストをロード
  doc = nlp(_str)
  for sent in doc.sents:
    for token in sent:
      addArr = []
      addArr.append(token.orth_)  # 単語
      addArr.append(token.lemma_) # 原型
      addArr.append(token.pos_)   # 品詞
      addArr.append(token.tag_)   # 日本語品詞詳細
      result.append(addArr)
  
  return result

### 単語のポジティブスコアを取得する関数
def getWordPositiveScore(_strArr):
  result = []
  pn = loadPnJson() # ポジネガスコア表を読み込む
  try:
    if pn[_strArr[0]]['noun'] in _strArr[3]:
      result.extend([_strArr[0], _strArr[1], pn[_strArr[0]]['score'] + coValue])
    else:
      result.extend([_strArr[0], _strArr[1], 0])
  except KeyError as e:
    result.extend([_strArr[0], _strArr[1], 0])
  return result

### 文章のポジティブスコアを取得する関数
def getSentencePositiveScore(_sentArr, _detailFlag = False):
  result = []
  dresult = []
  count = 0    # スコアが入っている単語の数
  all = 0      # 全ての単語の数
  sumScore = 0 # スコア合計
  
  for w in _sentArr:
    ret = getWordPositiveScore(w)
    
    # スコアが0以外のときだけcountを増やす。
    if ret[2] != 0:
      sumScore += ret[2]
      count += 1
      all += 1
    else:
      sumScore += ret[2]
      all += 1
    
    if _detailFlag:
      result.append(ret)
  
  # 計算したスコアを返す。詳細フラグがONならappend、OFFならextendで無駄な多重配列しない
  if len(result) == 0:
    result.extend([sumScore, (sumScore / all), (sumScore / count)])
  else:
    result.append([sumScore, (sumScore / all), (sumScore / count)])
  
  return result

#------------------------------------
#              MAIN関数
#------------------------------------
def main():
  word = '【北京共同】中国政府は10日、肺炎を引き起こす新型コロナウイルスによる中国本土の死者が908人になったと発表した。2002~03年に大流行した重症急性呼吸器症候群(SARS)の世界全体の死者数774人を超えた。感染者は4万171人に増えた。中国や各国は隔離や検疫による対策を急いだが、大規模な流行を防げず、封じ込めは難航している。'
  gin = analyzeSentence(word)
  res = getSentencePositiveScore(gin)
  print(word) # 原文
  print('WORD', 'ORG', 'SCORE')
  for w in res:
    print(w[0], w[1], round(w[2], 4)) # 
  
if __name__ == "__main__":
  main()

さらっとした試作の予定だったので変数名とかめっちゃてきとう。

アウトプットとして、

  • ポジネガスコアの合計
  • 単語1語あたりのポジネガスコア
  • ポジネガスコアがついている単語1語あたりのポジネガスコア

どの指標がどういった相関関係になるのか不明だが、出せるものは出しておくスタイル。

ちなみに、ロードする単語感情極性対応表はあらかじめjson形式に変換しておく。

 

 

上から解説していく。

 

import json
import spacy

必要なライブラリのインポート。

今回はjsonをロードして、形態素解析を行うのでこの2つ。

 

pnJson = 'pn_ja.json.org' # 単語感情極性対応表
coValue = 0.315 # 単語感情極性対応表がダークサイドなので値を補正する

読み込むjsonファイルのパスと補正値。

後々説明するが、こちらでダウンロードできる単語感情極性対応表、結構ネガティブな単語が多いので、補正なしだと悪い結果がめっちゃ出る。

そのための補正値。

今回は中央値を取った。平均値でもよいかもしれない。

 

###単語感情極性対応表jsonを読み込んで辞書型配列を返す
def loadPnJson():
  f = open(pnJson, 'r')
  result = json.load(f)
  return result

コメントそのままの処理する。

 

### GiNZAで形態素解析するための関数
def analyzeSentence(_str):
  result = []
  nlp = spacy.load('ja_ginza') # ginzaのリストをロード
  doc = nlp(_str)
  for sent in doc.sents:
    for token in sent:
      addArr = []
      addArr.append(token.orth_)  # 単語
      addArr.append(token.lemma_) # 原型
      addArr.append(token.pos_)   # 品詞
      addArr.append(token.tag_)   # 日本語品詞詳細
      result.append(addArr)
  
  return result

形態素解析を実施する関数。

解析結果を配列に格納してそのまま返す。

何を格納しているかはspacyのマニュアルを見れば理解できるかと。

というかコメントしてるけど・・・

 

### 単語のポジティブスコアを取得する関数
def getWordPositiveScore(_strArr):
  result = []
  pn = loadPnJson() # ポジネガスコア表を読み込む
  try:
    if pn[_strArr[0]]['noun'] in _strArr[3]:
      result.extend([_strArr[0], _strArr[1], pn[_strArr[0]]['score'] + coValue])
    else:
      result.extend([_strArr[0], _strArr[1], 0])
  except KeyError as e:
    result.extend([_strArr[0], _strArr[1], 0])
  return result

analyzeSentence関数の戻り値の中の配列(ややこしい)を引数に渡すと、その単語のポジネガスコアを計算して、色々配列に格納して返す。

例えば、[‘世界’, ‘世界’, ‘noun’, ‘名詞’]

みたいな配列を渡すと、

[‘世界’,’世界’,’-0.471…’]

みたいな値が返る。

ちなみに、「世界」という単語は補正値を抜くと-0.78ぐらいのネガティブ寄りなワードらしい。

基準が分からんね・・・。

 

### 文章のポジティブスコアを取得する関数
def getSentencePositiveScore(_sentArr, _detailFlag = False):
  result = []
  dresult = []
  count = 0    # スコアが入っている単語の数
  all = 0      # 全ての単語の数
  sumScore = 0 # スコア合計
  
  for w in _sentArr:
    ret = getWordPositiveScore(w)
    
    # スコアが0以外のときだけcountを増やす。
    if ret[2] != 0:
      sumScore += ret[2]
      count += 1
      all += 1
    else:
      sumScore += ret[2]
      all += 1
    
    if _detailFlag:
      result.append(ret)
  
  # 計算したスコアを返す。詳細フラグがONならappend、OFFならextendで無駄な多重配列しない
  if len(result) == 0:
    result.extend([sumScore, (sumScore / all), (sumScore / count)])
  else:
    result.append([sumScore, (sumScore / all), (sumScore / count)])
  
  return result

最近覚えたデフォルト引数を使ってみる。

  • ポジネガスコアの合計
  • 単語1語あたりのポジネガスコア
  • ポジネガスコアがついている単語1語あたりのポジネガスコア

を返すために、それぞれカウンターを設けている。

多分見ればわかるけど結構ごり押し。

 

#------------------------------------
#              MAIN関数
#------------------------------------
def main():
  word = '【北京共同】中国政府は10日、肺炎を引き起こす新型コロナウイルスによる中国本土の死者が908人になったと発表した。2002~03年に大流行した重症急性呼吸器症候群(SARS)の世界全体の死者数774人を超えた。感染者は4万171人に増えた。中国や各国は隔離や検疫による対策を急いだが、大規模な流行を防げず、封じ込めは難航している。'
  gin = analyzeSentence(word)
  res = getSentencePositiveScore(gin, True)
  print(word) # 原文
  print('WORD', 'ORG', 'SCORE')
  for w in res:
    print(w[0], w[1], round(w[2], 4))
  
if __name__ == "__main__":
  main()

メイン関数。

今までに作成した関数を読み出すだけ。

 

出力結果

第92回アカデミー賞授賞式が2月10日(日本時間)、米ロサンゼルスのドルビー・シアターで開催され、松たか子がイディナ・ メンゼルら世界各国の“エルサ”と共に「イントゥ・ジ・アンノウン」の歌唱パフォーマンスに参加した。アカデミー賞授賞式での歌唱は日本人として初となる。
 WORD ORG SCORE
 第 第 0
 92 92 0
 回 回 -0.4061
 アカデミー アカデミー 0.1885
 賞 賞 1.3139
 授賞 授賞 0
 式 式 -0.3177
 が が 0
 2 2 0
 月 月 -0.598
 10 10 0
 日 日 -0.5886
 ( ( 0
 日本 日本 0
 時間 時間 -0.6357
 ) ) 0
 、 、 0
 米 米 -0.6038
 ロサンゼルス ロサンゼルス 0
 の の 0
 ドルビー ドルビー 0
 ・ ・ 0
 シアター シアター 0
 で で 0
 開催 開催 0.0915
 さ 為る 0
 れ れる 0
 、 、 0
 松 松 0.0993
 たか子 たか子 0
 が が 0
 イディナ イディナ 0
 ・ ・ 0
 メンゼル メンゼル 0
 ら 等 -0.5106
 世界 世界 -0.471
 各国 各国 0
 の の 0
 “ “ 0
 エルサ エルサ 0
 ” ” 0
 と と 0
 共 共 -0.2628
 に に 0
 「 「 0
 イントゥ イントゥ 0
 ・ ・ 0
 ジ ジ 0
 ・ ・ 0
 アンノウン アンノーン 0
 」 」 0
 の の 0
 歌唱 歌唱 0.018
 パフォーマンス パフォーマンス -0.1239
 に に 0
 参加 参加 -0.1293
 し 為る 0
 た た 0
 。 。 0
 アカデミー アカデミー 0.1885
 賞 賞 1.3139
 授賞 授賞 0
 式 式 -0.3177
 で で 0
 の の 0
 歌唱 歌唱 0.018
 は は 0
 日本人 日本人 0
 と と 0
 し 為る 0
 て て 0
 初 初 -0.1559
 と と 0
 なる 成る -0.4345
 。 。 0
 -2.323794 -0.030983919999999998 -0.1056
【北京共同】中国政府は10日、肺炎を引き起こす新型コロナウイルスによる中国本土の死者が908人になったと発表した。2002 ~03年に大流行した重症急性呼吸器症候群(SARS)の世界全体の死者数774人を超えた。感染者は4万171人に増えた。中国や各 国は隔離や検疫による対策を急いだが、大規模な流行を防げず、封じ込めは難航している。
 WORD ORG SCORE
 【 【 0
 北京 北京 0
 共同 共同 -0.3242
 】 】 0
 中国 中国 0
 政府 政府 -0.4045
 は は 0
 10 10 0
 日 日 -0.5886
 、 、 0
 肺炎 肺炎 -0.6798
 を を 0
 引き起こす 引き起こす 0
 新型 新型 0.2009
 コロナ コロナ -0.0358
 ウイルス ウイルス -0.5221
 に に 0
 よる よる -0.6605
 中国 中国 0
 本土 本土 -0.0188
 の の 0
 死者 死者 0
 が が 0
 908 908 0
 人 人 0
 に に 0
 なっ 成る 0
 た た 0
 と と 0
 発表 発表 -0.1299
 し 為る 0
 た た 0
 。 。 0
 2002 2002 0
 ~ ~ 0
 03 03 0
 年 年 -0.5849
 に に 0
 大 大 0
 流行 流行 -0.5548
 し 為る 0
 た た 0
 重症 重症 -0.6745
 急性 急性 -0.6818
 呼吸器 呼吸器 -0.169
 症候群 症候群 0.0198
 ( ( 0
 SARS SARS 0
 ) ) 0
 の の 0
 世界 世界 -0.471
 全体 全体 -0.647
 の の 0
 死者 死者 0
 数 数 -0.6501
 774 774 0
 人 人 0
 を を 0
 超え 越える 0
 た た 0
 。 。 0
 感染者 感染者 0
 は は 0
 4万171 40171 0
 人 人 0
 に に 0
 増え 増える 0
 た た 0
 。 。 0
 中国 中国 0
 や や 0
 各国 各国 0
 は は 0
 隔離 隔離 -0.2417
 や や 0
 検疫 検疫 -0.0849
 に に 0
 よる よる -0.6605
 対策 対策 -0.1075
 を を 0
 急い 急ぐ 0
 だ た 0
 が が 0
 、 、 0
 大規模 大規模 0.237
 な だ 0
 流行 流行 -0.5548
 を を 0
 防げ 防ぐ 0
 ず ず 0
 、 、 0
 封じ込め 封じ込め 0
 は は 0
 難航 難航 -0.0571
 し 為る 0
 て て 0
 いる 居る -0.2884
 。 。 0
-9.334636599999998 -0.095251393877551 -0.3457

ごらんのとおり、ポジティブだと思っていた文章もこのプログラムにかかればネガティブと化す。

これは単語感情極性対応表が結構ネガティブ寄りに作成されているため。

単純なスコアを見るよりも、相対評価をしたほうが良い気がする。

コメント

タイトルとURLをコピーしました