1. 要旨
単語あるいは文章の分散表現に対し、
例えば「原子力発電」(解析 target)を、
「安全」、「危険」、「地球温暖化」、「技術」(解析 bases)と、
(その他)の5成分で説明したい。
$\overrightarrow{原子力発電} = a \overrightarrow{安全} + b \overrightarrow{危険} + c \overrightarrow{地球温暖化} + d \overrightarrow{技術} + \overrightarrow{その他}$
本稿で実際にやってみると、
$\overrightarrow{原子力発電} = 0.12 \overrightarrow{安全} + 0.08 \overrightarrow{危険} + 0.29 \overrightarrow{地球温暖化} + 0.07 \overrightarrow{技術} + \overrightarrow{その他}$
という結果を得た。
この仕組みを報道文章の成分解析に応用することで、偏向報道を定量的に評価することにもつながるのではないだろうか。
2. 理論
2-1. 単語ベクトルについて
書きかけ
2-2. 分散表現の解析について
一般化すると、次のような ${\rm params}_i$ を求める問題となる。
\displaylines{
\overrightarrow{\rm target} = \sum_{i=0}^{n-1} {\rm params}_i \overrightarrow{{\rm bases}_i} + \overrightarrow{\rm other} \\
{\rm where} \forall{i} \overrightarrow{{\rm bases}_i}\cdot\overrightarrow{\rm other} = 0
}
これを解くと、
\displaylines{
\overrightarrow{\rm target}\cdot\overrightarrow{{\rm
bases}_i} &=&\left(\sum_{j=0}^{n-1} {\rm params}_j \overrightarrow{{\rm
bases}_j}\right)\cdot\overrightarrow{{\rm bases}_i} \\
&=&\sum_{j=0}^{n-1} {\rm params}_j\left(
\overrightarrow{{\rm bases}_j}\cdot \overrightarrow{{\rm
bases}_i}
\right)
}
となるので ${\rm params}_i$ について解けばよい。
これは行列方程式として、まとめて
\left(\begin{array}{ccc}
\overrightarrow{\text { bases }_0} \cdot \overrightarrow{\text { bases }_0} & \cdots & \overrightarrow{\text { bases }_{n-1}} \cdot \overrightarrow{\text { bases }_0} \\
\vdots & \ddots & \vdots \\
\overrightarrow{\text { bases }_{n-1}} \cdot \overrightarrow{\text { bases }_0} & \cdots & \overrightarrow{\text { bases }_{n-1}} \cdot \overrightarrow{\text { bases }_{n-1}}
\end{array}\right)\left(\begin{array}{c}
{\rm params}_0 \\
\vdots \\
{\rm params}_{n-1}
\end{array}\right)=\left(\begin{array}{c}
\overrightarrow{\text { target }} \cdot \overrightarrow{\text { bases }_0} \\
\vdots \\
\vdots \\
\overrightarrow{\text { target }} \cdot \overrightarrow{\text { bases }_{n-1}}
\end{array}\right)
と書ける。
3. 実験
3-1. 解析クラスの作成
numpy ベクトル (一次元配列) target と numpy ベクトル配列 ($n$行の行列) bases を渡すと、 numpy ベクトル params を返すクラス及びメソッドparams = Analyzer(bases).analyze(target)を作ろう。
import sympy as sp
import numpy as np
class Analyzer:
def __init__(self, bases):
"""
bases: 基底とする単語ベクトルのリスト
"""
self.bases = sp.Matrix(np.array(bases))
self.n = np.array(bases).shape[0]
def analyze(self, target):
"""
target: 解析対象の単語ベクトル
"""
target = sp.Matrix(np.array(target).reshape(-1, 1))
bases = self.bases
n = self.n
params = sp.Matrix(sp.var("params_0:{}".format(n)))
# Mp = v
M = np.zeros((n,n), dtype=object)
for i in range(n):
for j in range(n):
M[i,j] = bases[i,:].dot(bases[j,:])
M = sp.Matrix(M)
v = np.zeros((n,1), dtype=object)
for i in range(n):
v[i,0] = target.dot(bases[i,:])
v = sp.Matrix(v)
eq = sp.Eq(M*params, v)
sol = sp.solve(eq, params)
return np.array([sol[params[i]] for i in range(n)])
3-2. 学習済み分散表現を実際に解析してみる
実例として、「原子力発電」を「安全」、「危険」、「地球温暖化」、「技術」、(その他) の組み合わせとして解析してみる。
↑こちらの記事でも借りたモデル (コーパス: 日本語版 Wikipedia)を利用する。
- 上記モデル (jawiki.doc2vec.dmpv300d.model と 他 3 ファイル(合計4ファイル)) がカレントディレクトリに置く
- バージョン 3.8.3 の gensim と、MeCab、numpy と matplotlib を pip により環境にインストールしておく。
- 前節で書いた
analyzer.pyをカレントディレクトリに置く
from analyzer import Analyzer
from gensim.models.doc2vec import Doc2Vec
import numpy as np
base_words = ["安全", "危険", "地球温暖化", "技術"]
model = Doc2Vec.load("jawiki.doc2vec.dmpv300d.model")
bases = np.array([
model.docvecs[base_word]
for base_word in base_words
])
target = model.docvecs["原子力発電"]
params = Analyzer(bases).analyze(target)
for param, base_word in zip(params, base_words):
print(base_word, param)
4. 結果
次の結果を得た。
安全 0.120704356617005
危険 0.0836215456477310
地球温暖化 0.299135002292953
技術 0.0714315926246206
$\overrightarrow{原子力発電} = 0.12 \overrightarrow{安全} + 0.08 \overrightarrow{危険} + 0.29 \overrightarrow{地球温暖化} + 0.07 \overrightarrow{技術} + \overrightarrow{その他}$
ということである。
原子力発電は、「危険」より「安全」の要素が1.5倍ほど強く、また、
「地球温暖化」との関連がさらに強いことが定量的に評価出来た。
5. 考察
doc2vec を利用すれば、未知の文章に対するベクトル表現の推測が可能である。
そのため、例えば任意の報道記事を、今回提案した手法で成分解析することも可能である。
これにより、偏向報道を定量的に評価することにもつながるのではないだろうか。