ill-identified diary

所属組織の見解などとは一切関係なく小難しい話しかしません

三国志で学ぶデータ分析 (原稿写し)

概要

この記事は 2019/12/7 に開催された Japan.R の発表原稿である.

github.com
speakerdeck.com

小難しいテクニックを使ったことをアピールせず, なるべく単純な方法だけで, データから何が言えるのか, 何を示せるのかを作業の流れに沿ってチュートリアル風に説明する, というのがコンセプトである. スクレイピングによるデータの取得, 加工, そして要約統計量の計算やグラフの見せ方, といった事柄はほとんどのデータ分析で必要な基礎技術だと思うので, 実践的な例になると踏んでいた. 当初は 5分間のLTの予定だったので要約統計量 (記述統計量) の見方とかだけを話すつもりだったが, 20分枠に変更したことに合わせてボリュームを増そうとしたらバランスが狂った感じになった. (小難しいことをしないとか言いながら色気を出してディープラーニングに手を出そうとしているのはご愛嬌ということで)

注意: 今回の内容は日本で普及しているフォントで表示できない文字が含まれるなどの写植上の制約から, フォントを埋め込んだ pdf 版を公開している. よって, このブログはあくまでコピーとなり, 不完全なものである.

例えば, 花園明朝Bをインストールしていないと表示できない文字などがあるし, 手作業で書き換えるのは疲れたのでこちらの修正はしない. リンク先のpdfをなるべく確認して欲しい.


2020/3/17更新: github pagesで原稿の再編集版を公開した. プログラムの解説が多少増えている. html/pdf/epubの3種類を用意している.

gedevan-aleksizde.github.io


キーワード

三國志, スクレイピング, 名寄せ処理, 自然言語処理 (?), 画像認識, ディープラーニング , 計量距離学習, 多変量解析

イントロダクション

三国志の背景

そこで今回取り上げる「三国志」について, 簡単に解説する.

魏から西晋の時代の歴史家である陳寿によって著された, 魏書・呉書・蜀書のいわゆる三国時代の歴史書を総称して三国志, 通称『正史三国志』と呼ばれる. これは正史, つまり当時の王朝によって正統な歴史書と認定された書物であるから, 必ずしも「真実」が描かれているとは限らない. 現在に残る正史三国志は, 南朝時代の裴松之の註解が付されており, 王朝が変わった後世ということもあってより政権に対して批判的である.

三国志演義』とは正史三国志や, それにまつわる無数の民間伝承や演劇「三国志平話」を羅貫中が編纂したものである. 本場である中国ではそれ以降も多くのバージョンが作られ, 主要な底本も複数存在する. 20世紀になってからも『反三国志(周, 1919)といったメタフィクション作品が作られている. 三国志演義の成立史だけでも膨大な研究が存在するはずだが, ここではそれに触れない.

渡辺 (2011)によれば, 三国志演義の「演義」とは, 義を演繹する, 義を敷衍するという意味であり, 当時の中国における倫理とされていた儒教に規定される道徳心を民衆に教えるという意図がある. よって, 当時の社会情勢や政権の意図が大きく反映されており, 道徳に悖る行動をした人物はみじめに破滅し, 道徳に則った行動を取るものは讃えられるという勧善懲悪の筋書きになっている*1. これは陳寿による史書, いわゆる「正史三国志」とはかなり異なる記述である.

渡辺 (2011) によれば, 『日本書紀』の編纂の時点で三国志の影響が見られると言うから, 日本にはかなり早くに伝わっていた. しかし近年の日本では吉川英治の『三国志(吉川, 1939)が有名ではないだろうか. これは三国志演義をもとに吉川が脚色したものであり, 中国本国の三国志演義正史三国志に忠実な翻訳作品ではない. 横山光輝の漫画『三国志』も, 概ね吉川英治の内容に準拠している.

また, 漫画作品では横山光輝作品の他, 李學仁・王欣太の『蒼天航路』も有名である. これまで悪役とされることが多かったソウソウを主役としている*2など, 従来の三国志人物像に対するメタな作風が特徴である. その他にも日本の大衆文化における三国志をモチーフにした創作には枚挙に暇がない*3.

一方で, 歴史書としての三国志, つまり『正史三国志』が日本で紹介されたのは比較的最近であり, 少なくとも民間向けでは1977年に筑摩書房によって魏書の一部の翻訳*4が出版され, 82, 89年に続いて魏書の残りと蜀書*5, 呉書*6がそれぞれ刊行されている*7. また, 三国志演義よりも正史に取材して書かれた作品としては, 陳舜臣の『秘本三国志(陳, 1974)*8北方謙三の『三国志北方 (1996), 宮城谷昌光の『三国志(宮城谷, 2004)がある*9.

このように, 史書でも創作でも, 書かれた時代や地域によって三国志の人物の扱われ方が異なる.

コーエーテクモのゲーム『三國志』シリーズ

コーエーテクモ (旧, 光栄) 社はこの三国志をモチーフにしたゲーム『三國志』シリーズを発売している. 1作目は1985年で, 最新のものは2016年の『三國志 13』である. コーエーテクモは「歴史シミュレーションゲーム」と銘打っているが, 作品によっては, 中国大陸に割拠する勢力の1つを操作し天下統一を目標とするターン制戦略ゲームであったり, 登場人物の一人となって立身出世を目指すロールプレイング・ゲーム的要素の強いゲームだったりもする.

三國志 英傑伝』『三國志 孔明伝』『三國志 曹操伝』といったナンバーのないタイトルもある.

また, 8以降の作品では, おまけ要素として三国志外の時代の人物, 例えば管夷吾 (管仲) や楽毅, 藺相如といった春秋戦国時代の英雄や, 時系列では後になる南北朝時代高長恭 (蘭陵武王), モンゴルのチンギス=ハン (成吉思汗), 南宋岳飛などが登録されている*10. 一方で最新作の三国志13 (2016年発売) では戦国時代末期の人物が増えており, これは原泰久の漫画『キングダム』の人気を反映していると思われる. さらに2020年発売予定の最新作14では, 田中芳樹原作『銀河英雄伝説』のキャラクタを登場させるようだ*11.

問題提起

正史と演義での人物の評価両方を取り入れようとすると, どうしても矛盾が生じる. 例えば, 演義では曹操は徹底して「奸雄」つまり小狡い悪党として描かれ, 一方でリュウは利益より義を優先する道徳の手本のような人物として描かれる. しかし歴史はそう単純ではなく, 正史での記述は大きく食い違う. もちろんそれは, 魏とその後継王朝である西晋にとって都合の良いように描かれたという側面もある. しかしいま関心があるのは, なにが史実か, なにが真実かではなく「人々の認識がどう変わったか」である.

矛盾する複数の物語を公平に取り入れようとするならば, 人物の評価はいいとこどりにするか, 悪いところどりにするしかないだろう. よって, これまでの物語とは人物像の異なる正史三国志での描写が日本人に膾炙されるようになれば (年表を図1に示す.), それまで三国志演義で悪役として描かれ評価の低かった人物たちの評価があがり, 結果として『三國志』シリーズでステータスの差別化ができなくなっていくと予想する. 今回は, この仮説を検証するまでの過程を「実践的なデータ分析のチュートリアル」として記録する.

f:id:ill-identified:20191209224750p:plain
図1: 現代日本における三国志文化の年表

先行・関連研究

たぶんこんなバカなこと考えるやつは過去にも例がないだろう. よって本研究の新規性・独自性は疑いようがない*12.

前処理

三國志シリーズの登場人物のステータス情報は, インターネット上のいくつかの個人サイトから取得した.

コーエーテクモ公式の資料集も存在するが, 全て紙媒体であり, 購入および転記のコストを考えて利用しなかった.

スクレイピング

まずは rvest パッケージで各ページを取得した. rvest はパイプ演算子スクレイピングした html (xml) ノードデータを取得できるため, 使い勝手が良いパッケージである. 取得したページを rvesttidyverse を使い整然データとする.

しかし, これらのサイトは全て管理者が異なり, 非公式のものであるからフォーマットも違うため, 作品ごとに異なる工程が必要である. 多くは <table> タグを使って掲載されているため, rvest::html_table() 関数を使えば概ねうまくいくが, 特に手間がかかったのは, 表が整然化されていない三國志9と, 表の背景色でデータを表現していた三國志12のページである. 前者は一つのセルに複数の項目が文字列として入っていた (図2) ため, stringr::str_split_fixed() など文字列を処理するパッケージを駆使して分解する必要があった. 後者は, 1名の人物あたり2行で掲載し, なおかつ一部の項目を文字ではなく背景色の塗りつぶしで表現していた (図3). そのため, テキスト情報とタグの属性をそれぞれ別に取得し, 結合する必要があった.

さらに, ここで一部名寄せ処理を行っている. というのも, 三国志には数組の同姓同名の人物がいるからである.

  • チョウオン: 東漢 (後漢) の高級官僚と, 孫呉に仕えた人物

  • チョウガイ: トウケンに仕えた武将と, エンジュツに仕えた武将

  • チョウナン: エンショウに仕えたのち曹操に降伏した武将と, 蜀の武将

  • チュウ: 呉のソンケンに仕えた武将と, 蜀の武将

  • ホウ : 袁術に仕えた武将と, 蜀漢の武将ゲンの子, そして魏の人物

これらは識別できなければならないため, 名前の末尾に「孫呉」「東漢」などと所属勢力を括弧書きで追加した. ただし元のページでは必ずしもどの人物か同定されていないため, 生没年や字の有無, ステータスの数値等から判断した.

この作業のため, 各作品内で名前に重複がないか確認したところ, これ以外にも名前を誤って重複しているものが見られた. ステータス値や字, 生没年などから推理して修正した. この時点で, 7,115件, 1,120名の人物データが入手できた.

ここで説明した処理は scraping.Rtidying.R でなされている.

f:id:ill-identified:20191209225018p:plain
図2: 三國志9 の人物一覧ページ
f:id:ill-identified:20191209225057p:plain
図3: 三國志 12 の人物一覧ページ

さらなる名寄せ処理

今回の情報源は, 複数の個人サイトによるもので, フォーマットも全く異なる. さらに, 表記にもかなりゆらぎがある. 単なる誤変換であるもの, 原典である『正史三国志』と『三国志演義』の間でもすでに食い違っているものなど, 原因は様々である. 使用するデータの品質向上のため, 当初は手動でいくつかの方法を試した.

三国志以外の登場人物を除外する

既に述べたように, 春秋戦国時代や, 魏晉時より後代の人物が隠し要素として存在する. 三国志演義史書とは異なる創作であり, 真実がなんであるかを問題としない以上, 2世紀末の中国でチンギス=ハンが覇を唱えようが織田信長が乱入しようが, 皇帝カイザーラインハルト率いる宇宙艦隊が遠征してこようが, 原則を言えばあらゆる創作を「三国志」として認めなければならない. しかし今回はあくまで, 三国志の人物の評価の変遷を知るのが目的である. こういった企画で採用される人物はその時代を代表する英雄であるため, しばしば非常に高いステータス値が設定されている. そういう人物が後期の作品では数十人ほど登録されており, 要約統計などに対する影響はかなり大きい. よって, 今回は『三国志演義』『正史三国志』『反三国志』および『花関索伝』で言及される人物*14だけを対象とすることにした. この処理によって179名が除外された.

漢字が使われていない名前を検査する

まず, 正規表現で漢字以外の使われている人名を探した. 機種依存文字をカタカナ等で置き換えていたものを見つけた手動で修正した. 有名な例では, UTF-8 が普及する以前はチョウコウの「郃」の字に対応した文字コードがなかったため, インターネット上でしばしば「合β」と表記されていた. この方法では, , , , など同様の原因で, 補正すべき表記のゆらぎが発生している人名を122件発見した.

3文字以上の名前を検査する

三国志の時代では, 多くの人名は姓名が1字づつであることが多く, 3字以上の名前は珍しい. 夏侯, 諸葛, 司馬, 公孫など2字の姓は限られている. 名が2字以上になる人名も カクユウ , サイ などどかなり限られる. それ以外で3字以上の名前の多くは, 於夫羅, 卑弥呼, 都市牛利 など, 非漢民族の発音を当てたものと思われる. そこで, 名前が3字以上のものも手作業で確認してもさほど手間にならないと判断し確認した. その結果, 以下のような表記のゆらぎを19件見つけた. 事例の一部を抜粋する.

  • キョショウ/許子将. 子将は字である*15.

  • キンカンサンケツ/金環結: 後者は三国志3でのみ見られた. 人名に3字までの制約があったのだと思われる.

  • シュクユウ/祝融夫人: これは誤りではないが, 同一人物の表記が異なるとその後の処理に支障を来す. 「夫人」を除外した.

  • シンロク/秦誼: そもそも史書で表記のゆらぎがある.

  • ケイドウエイ/刑道栄: 「邢」をカタカナで置き換えるケースは既に見たが, 「刑」で置き換えているケースも発見.

  • リュウヒョウ/左賢王: 左賢王は南匈奴の称号. 作中のテキストから, 史書で左賢王の地位にあった劉豹と同定される. 劉豹の子.

ただし, 許劭/許子将 や, 秦宜禄/秦誼の組み合わせは, 三国志の知識がなければただちには分からない.

さらに, 本来の意図ではないが, 3字以上の人名に誤記を見つけた. その抜粋は以下.

  • カンキュウケン/母丘倹: 子弟である, にも同様の誤りが見られた.

  • ショカツキン/諸葛謹: オウ偏のの字があまり使われないための誤記と思われる.

  • タイキョウ/太史享: 字の違いは微妙である.

出現頻度の少ない人名を検査する

字数の多い名前での表記のゆらぎはすでに確認できた. しかし, 3字以上の名前だけを見ても, これだけ表記にゆらぎがあるならば, 2字の名前でも同様にゆらぎがあると予想できる. そこで, シリーズ全作品のデータを結合した上で, 出現回数が2回以下のものを確認した. これで, 誤字をいくらか発見できると考えた. しかし, 実際には知名度の低い人物が多くピックアップされただけであり, ここから表記のゆらぎを見つけるのは難しい. 誤記・誤変換ならばソートしても対になる人名が近くにくるとも限らない.

そして機械学習

そこでさらなる名寄せ処理として, どうやって互いに類似する人名を取り出すか, ということを考える.

多くの自然言語処理の研究では, 文章を対象としている. しかし, すでに述べたように人名のほとんどが2字, 多くとも4字である. 形状の似ている文字を見つけるということから, 画像認識の技術を応用できないか考えてみる. 画像認識の一種としての手書き文字の認識は昔から研究されている. しかし, これは癖のある字をどう認識するかという教師あり学習の問題として扱われることが多いため, 今回の問題と合致しない.

今回の問題設定に合致するような先行研究がなかなか見つけられないため, 自分なりのアイディアとして, 人名の文字を画像データと見なし, 画像間の類似度を計算することで似たような字を見つける, と言う方法を採用した. これは表記ゆれを確実かつ漏れなく発見できるわけではないが, 総当りよりも効率よく見つけられると考えられる.

画像として表示するにはフォントが必要である. 入力者がどのフォントを使っていたかは特定できない. また, 一部の人名は標準的な日本語フォントに対応していないものもある. 具体的には, 呉の景帝の太子の一人である「ソン𩅦ワン」である. 「𩅦」の字は Unicode では CJK統合漢字拡張Bのカテゴリに含まれており*16, 日本語フォントで対応しているものは少ない. 中国語圏で普及しているフォントには対応しているものもあるが, 今回の目的は日本人が日本語環境で入力したデータベースの名寄せだから, できる限り日本風のフォントを使う必要がある. これに対応する日本語フォントは花園明朝Bである. よって, 文字画像にはHanazono fontsで提供される花園明朝AおよびBを使うことにした.

まず, 2つの人名文字列のビットマップ情報*17に変換する. それから, ビットマップ情報から特徴量を取り出す.

特徴量の取り出し方は, 今回2通りの方法を試した.

  1. ビットマップ単位の情報をそのまま使う.

  2. 鴨下, 奥村, 高橋, 増村, & 矢野 (1998) の方法に即して特徴量を作成する.

(1) の方法では, 特徴量は 32\times128=4096 次元の数値となる*18. (2) の方法は, ピクセルの並びの全ての行・列それぞれに対して, 背景色・文字色の変化の回数 (これを「微分」と呼ぶ), 文字色の割合 (これを「積分」と呼ぶ) を計算する方法である. これによって, (32+128)\times2=320 次元の特徴量が得られる (実際に使用したのは317次元).

最期に, 2つの文字画像の特徴量ベクトル \boldsymbol{x},\boldsymbol{y} について, 距離 d(\boldsymbol{x},\boldsymbol{y}) を計算する. 今回はこれを min-max 正規化したものを, 類似度 s として, 値の大きい順にならべる.
\begin{align}
s(x,y):= & \frac{d(x,y)-\min d}{\max d-\min d}\end{align}
なお, このような類似度の求め方はテンプレートマッチングと呼ばれる(糟谷 & 山名, 2006). d(x,y) には, ユークリッド距離
\begin{align}
d(\boldsymbol{x},\boldsymbol{y}):= & \left\Vert \boldsymbol{x}-\boldsymbol{y}\right\Vert _{2}=\sqrt{(\boldsymbol{x}-\boldsymbol{y})^{\top}(\boldsymbol{x}-\boldsymbol{y})},\end{align}
マンハッタン距離
\begin{align}
d(\boldsymbol{x},\boldsymbol{y}):= & \left\Vert \boldsymbol{x}-\boldsymbol{y}\right\Vert _{1}=\sum_{k}\left|x_{k}-y_{k}\right|,\end{align}
で計算した. 両者は次元の大きさが全く異なるが, 提示された結果はかなり似ている. 上位30件を確認して発見した表記のゆらぎを表1に抜粋する.

表1: M類似度上位10件, 誤字を強調
于糜4.944.79
車冑4.874.93
王凌4.815.03
夏侯威夏侯咸4.734.79
呉綱4.654.79
薛珝4.594.58
邢道栄道栄4.584.00
全禕金禕4.554.47
王匡士匡4.524.45
劉璝4.464.47

特に紛らわしいのは表2である. これは文字を拡大しないと気づきづらい.

表2: 発見できた紛らわしい表記のゆらぎ例
解説
シャチュウ 車胄 「冑」の下
カン 関彜 「米糸」と「米分」
ショウカイ 鐘会 ではない

新たに多くの表記ゆれを発見できたが, 一方で誤検知もある. 表2では, コウコウカン, ゼン>とキン, オウキョウ>とキョウの組み合わせは別人物である.

今回の2つの方法はいずれも, 1字同じだけでもかなり一致度が高くなってしまう. 結果として勘でやったほうが修正の必要な箇所を多く見つけられたので, より精度が必要である. 一方で, 鴨下 et al. (1998) はかなり古い研究で, 文字のビット数が小さく, さらに特徴量を大きく削減するなど計算量を削減しているが, 上記の結果とあまり変わらない結果が得られた.

そもそもなぜ表記ゆらぎが起きるかと言えば, 登録時点でのミス, 原作時点でのミスである. 前者は音や形状の似た字への誤変換, 普及している日本語フォントではカバーしていない, あるいは IME が対応していない字 (いわゆる機種依存文字) の代用, 後者は同一文献や, 創作物ごとのゆらぎがある*19.

例: 原作からしてゆらぎがある*20

  • カン李湛 (三国志演義と吉川三国志)

  • ヨウシュウ楊修

  • ライドウ雷同

  • チングン陳群

  • デン田予

例: 機種依存文字の影響で間違えやすい字: 部首が違う

  • リュウカイ (正) 劉潰 (誤): 「璝」は日本語ではほぼ使われない

  • オウリョウ (正) と王淩 (誤): ニスイ偏が正しい.

  • ショウカイ (正) と鐘会 (誤): カネではない*21.

  • シツ (正) と 歩隲 (誤): コザト偏の位置

似ているが別人の例として, 既に紹介したもの以外にも以下のようなものがある.

  • トウガイトウ

  • カンカイカンカイ

以上の傾向から, 字形の平均的な一致度ではなく, 部首単位での類似を考慮して類似度を計算することができれば効率的であると思われる. また, 教師データも ground-truth なモデルも用意できないため, 「なるべく少ない労力で, たまたまでもうまく表記ゆらぎを見つけられるような類似度の求め方」が得られれば良い.

以上の処理は, image_recognition.R で実行している.

[草稿] ディープラーニングでなんとかできないか?

このセクションは昨日思いついて試してみたけど時間がたりなかったので書きかけです. 完了していないタスクです. ディープラーニングじたいほとんどやってないので話半分で読んで欲しい.

画像認識と言えば最近はニューラルネットワークを使った話が流行っているので, 何か応用できるものがないか探してみた. 機械学習の問題としてみれば教師なし学習で, かつ2点間の類似度を出せるものがよい. ここまで試したのは2つの文字画像のピクセル\boldsymbol{x},\boldsymbol{y} 間の距離である. 例えばユークリッド距離で,

\begin{align}
d(\boldsymbol{x},\boldsymbol{y}):= & \sqrt{\left\Vert \boldsymbol{x}-\boldsymbol{y}\right\Vert }_{2}\end{align}

を2つの画像の類似度としてきた. しかしこれでは限界があることがわかったので, なんらかの適切な特徴量変換器 \boldsymbol{f} を挟んで,
\begin{align}
s(\boldsymbol{x},\boldsymbol{y}):= & \sqrt{\left\Vert \boldsymbol{f}(\boldsymbol{x})-\boldsymbol{f}(\boldsymbol{y})\right\Vert }_{2}\end{align}
のような類似度計算ができるようになればいい. 機械学習の研究では, これを計量距離学習 (metric learning) という*22.

ここでいくつか関連しそうな研究を紹介しておく.

J. Wang et al. (2014), Hoffer & Ailon (2015), Sanakoyeu, Bautista, & Ommer (2018), Turpault, Serizel, & Vincent (2019) などを参考にすると最近は計量距離学習では triplet network と呼ばれるモデルが流行しているらしい.

Zhang & Komachi (2019) では, CHISE プロジェクトのデータベースから, 文字の部首情報を取り出して教師なしニューラル機械翻訳 (UNMT) をしている*23. しかしこれは画像認識ではない

M. Liu, Rus, Liao, & Liu (2017) は音素も考慮しているが, 今回は日本語での入力の問題なので少し違う. あと教師あり学習.

”In words, this encodes the pair of distances between each of x+ and x− against the reference x.“

J. Wang et al. (2014), Hoffer & Ailon (2015) 前者は多クラス分類だが, 後者はランキング問題

なお私は計量距離学習というトピックをこれまで全く知らなかった. 基本的な考え方を理解するために今回初めて Bellet (2013), Bellet, Habrard, & Sebban (2014) などを参照した程度である (よって見落としているだけということもありうる). このサーベイチュートリアル資料で紹介されているアイディアの多くは教師ありないし半教師あり学習だが, 今回は教師ラベルを作るのが面倒な場合はどうするかというのが問題である. ここでは主に Turpault et al. (2019) の提案する半教師あり学習*24をもとに試してみる. まず, 従来的な2点の比較は双生児 (siamese) ネットワークと呼ばれる:

\begin{align}
s_{\mathit{siamese}}(\boldsymbol{x},\boldsymbol{y}):= & \left\Vert f(\boldsymbol{x})-f(\boldsymbol{y})\right\Vert _{2}.\end{align}

一方で, 基準点 (anchor あるいは query と呼ばれる) \boldsymbol{x}^{a}に対して正例\boldsymbol{x}^{p}, 負例\boldsymbol{x}^{n} の3対 (triplet) (\boldsymbol{x}^{a},\boldsymbol{x}^{p},\boldsymbol{x}^{n}) を考慮したのが triplet network である.
\begin{align}
s_{\mathit{triplet}}(\boldsymbol{x},\boldsymbol{x}^{p},\boldsymbol{x}^{n}):= & \begin{bmatrix}\left\Vert f(\boldsymbol{x}^{a})-f(\boldsymbol{x}^{p})\right\Vert _{2}\\
\left\Vert f(\boldsymbol{x}^{a})-f(\boldsymbol{x}^{n})\right\Vert _{2}
\end{bmatrix}\end{align}

これら3点の相対的な距離をもとに学習するというのが triplet network のアイディアになる. さらに, J. Wang et al. (2014) に従って triplet 損失を
\begin{align}
L_{\mathit{triplet}}(\boldsymbol{x}^{a},\boldsymbol{x}^{p},\boldsymbol{x}^{n};\delta):= & \left\lfloor \left\Vert f(\boldsymbol{x}^{a})-f(\boldsymbol{x}^{p})\right\Vert _{2}-\left\Vert f(\boldsymbol{x}^{a})-f(\boldsymbol{x}^{n})\right\Vert _{2}+\delta\right\rfloor \end{align}
で定義する.

しかし今回は教師ラベルがないため, \boldsymbol{x}^{p}, \boldsymbol{x}^{n} をどう選べばいいかが分からない. そこで, Turpault et al. (2019) の提案するように, 特徴量 \boldsymbol{x} の距離で正例負例を与える.

補足: DBpedia を利用した二重チェック

教師なし学習による探索だけでは心もとないので, Wikipedia の記事を使った二重チェックを行った. DBpedia Japaneseとは, Wikipedia を構造化したデータベースで, SPARQL によってデータを取得できる. 例えばプログラム1 のようなクエリになる.

PREFIX dbpedia: <http://ja.dbpedia.org/resource/>
PREFIX dbp-owl: <http://dbpedia.org/ontology/>
PREFIX rdf: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX category-ja: <http://ja.dbpedia.org/resource/Category:>
SELECT DISTINCT ?article, ?text
WHERE {
         ?article dbp-owl:wikiPageWikiLink category-ja:三国志の登場人物 .
         ?article rdf:comment ?text .
}

プログラム1: SPARQL のクエリ例

Rでは, SPARQLパッケージが用意されている.

三國志」シリーズの人材は年々無個性化しているのか?

以上で一旦名寄せ処理を切り上げる.

次に, 各作品で, 新しく登録された人物と除外された人物が何人かを表してみる. 図4では, 前作から追加された人物が in, 逆に除外された人物を out, 続投している人物を keep で表した. つまり, in + keep が各作品に登場する人数である.

からは, 4, 12 で前作より減っているものの, 基本的に登場人物が増えていることがわかる. よって, 少しづつ正史三国志に記述のある人物が増えていることが分かる*25.

f:id:ill-identified:20191209230123p:plain
図4: 登録・除外フロー

を含め, 以降の画像は全て ggplot2 だけで作成した. ただし, カラーパレットは ggtheme のものを使うと良い. ここでは colorblind シリーズを使用している.

要約統計量を計算するのに役立つのが skimr パッケージである. 要約統計量を表示する関数は, 組み込みの summary() を始めいくつもあるが, skimr

  • summary()よりも見やすい
  • group_by() したデータを与えるとグループ別集計してくれる

といった便利さからおすすめする((発表の反響を踏まえての追記: 組み込みの summary() より見やすい表を提供するパッケージは他にもある. niszet 氏のブログにも 『(R) summarytoolsパッケージ、便利そう… - niszetの日記』という記事がある. 私が skimr を挙げた要因として, プレーンテキストとして扱えるという点も大きいことを補足せねばならない. というのも, 私が資料を作成するときはほぼ LaTeXなので, 表形式に変換しやすい形で, 例えば Hmisc::latex() で変換しやすい形式で出力してくれる skimr を薦めた.)). ただし日本語の情報が少ない. 私の知る限り『TokyoR 72 LTskimrとsummarytoolsパッケージの紹介』の作者が唯一言及しているのみで, しかも現在はさらに仕様が変わっている.

仕様が変わったのは表示する統計量を決める部分である. 以前は skim_with() でグローバルに変更していたが, 現在は関数ジェネレーターのような仕様になっている (プログラム2). 出力例が表3である.

library(moments)
my_skim <- skim_with(numeric = sfl(skew = skewness, kurto = kurtosis, hist = NULL), append = T)
DATA_FRAME %>% group_by(title) %>% my_skim()

skimrによる表 (一部)
1武力15.0036.0057.5078.75100.0057.3724.63-0.001.80 2 武力11.0041.0061.0074.00100.0058.7821.33-0.092.13 3武力15.0052.0064.0071.00100.0061.4017.08-0.463.05 4武力13.0049.2566.0075.00100.0061.3920.25-0.562.63 5武力7.0044.0067.0076.00100.0060.2622.74-0.642.47 6武力16.0042.7562.5073.00100.0058.3620.00-0.322.27 7武力11.0045.2563.0074.0098.0058.7920.37-0.502.26 8武力10.0046.0065.0072.00100.0058.6820.83-0.702.59 9武力0.0036.0065.0072.00100.0055.6324.35-0.662.33 10武力1.0039.0064.0073.00100.0056.4323.37-0.672.45

しかし, 今回は見るべき項目が多いので, グラフで見やすくする必要がある.

そこで, 要約統計量の推移を折れ線グラフで表したのが図5である.

f:id:ill-identified:20191209230850p:plain
図5: シリーズごとの要約統計量の推移

特に気になるのは, レンジの変化である. 三國志シリーズのステータスは基本的に1~100の数値だが, 実際には最小値と最大値の幅が作品ごとに異なることがわかった. そのため, 値域を統一するためにシリーズごとに min-max 正規化を行う. 今回は, 見やすさのため, レンジが100になるよう, 以下のような式で調整している.
\begin{align}
z:= & 100\times\frac{x-\min(x)}{\max(x)-\min(x)}\label{eq:range-normalize}\end{align}

調整後の要約統計量が図6である. ここから, 後期の作品ほど平均が上昇していること, そして分散が低下していることがわかる. 分散の低下という意味では, ステータス値の多様性が乏しくなり「没個性化」しているともとれる. しかし, 要約統計量から得られる情報が全てではない.

f:id:ill-identified:20191209231006p:plain
図6: min-max 正規化後のシリーズごとの要約統計量

ここからは, いくつかの切り口からデータを見ていく. まずは, 4名の人物について, シリーズを通してステータスがどう変化しているかを見る. 主要人物は記述が多く, 演義と正史での評価の差異を細かく説明するのが大変である. そこで, 主要人物ではないが, 差異の分かりやすい人物を挙げる.

  • ユウ
    • 正史: 「トウタクが派遣したシンの配下としてソンケン軍に討たれた」としか書かれていない(呉書孫堅伝)
    • 演義: 董卓配下の猛将で, 孫堅を敗走させる. しかしカンに即敗北する (三国志演義)
  • カンコウ
    • 正史: 「父関羽の死後, 将来を嘱望されるも数年後病死」のみ (蜀記)
    • 演義: 父の仇討ちに成功し, 数度の北伐で活躍
  • ソウシン
    • 正史: ショカツリョウの北伐に対する防衛を指揮し, 二度退ける
    • 演義: 北伐では終始諸葛亮に翻弄され, 最期は罵倒され憤死した
  • ツウ
    • 正史: 曹操の本拠地, 豫州南部を守り抜く (李通伝)
    • 演義: チョウと一騎打ちし即敗北する

図7では, 「演義で活躍の盛られている」代表である華雄, 関興はシリーズを通してあまり変化していない. すくなくとも低下しているようには見えない. 一方で, 李通, 曹真は徐々に上昇しているように見える.

f:id:ill-identified:20191209231206p:plain
図7: 4名のシリーズを通した変化

ということは, もしこれが全体の傾向にも当てはまるのなら, 三国志演義で活躍が誇張されている人物の評価はそのままで, 正史の見直しによって従来ステータスの低い武将の値が底上げされれば, 「没個性化」になりうる. 全体の傾向ならば分布にも現れるはずである. そこで, シリーズの作品ほとんどで存在するステータス項目である, 「武力」「知力」「魅力」*26「政治」を確認してみる. シリーズ間の比較のため, 分布確認にはヒストグラムを使うこともできるが, ここでは geom_violin() を使ってバイオリン図を作図した(図8).


f:id:ill-identified:20191209231417p:plainf:id:ill-identified:20191209231430p:plainf:id:ill-identified:20191209231433p:plainf:id:ill-identified:20191209231438p:plain
図8: 主要能力の作品別バイオリン図

バイオリン図で書くことで, シリーズごとにステータスの分布形状が変動していることがわかった. そして興味深いことに, 後期の作品ほど分布が二極化している. 平均より大きな値域で大きめの峰を, 平均より小さい値域でも小さい峰が発生している. 図7の歪度の推移から, なんらかの形で分布が歪んでいることは予想できたが, 具体的な形状は実際にグラフにしないと分からない.

この分布の二峰化の意味するところを知るため, 武力と知力の散布図に, シリーズ通しての登場回数で色分けしたものを図9に示す. すると, 分布の大きい峰に対応する値では, 登場回数の大きい人物が集中しているように見える. しかし一方で登場回数の少ない人物の分布も密集しており, これだけでは判然としない. さらにこれだけでは他のステータスとの関係も同時に見ることができない.

f:id:ill-identified:20191209231846p:plainf:id:ill-identified:20191209231933p:plain
図9: 登場回数, 初登場作品で色分けした散布図

このセクションは analysis.R で実施している.

補足: データビジュアライゼーションの教科書について

グラフの書き方にも流儀がある. 3D 円グラフはやめよう*27, ユーレイ棒グラフはやめよう*28, という話は昔から喚起されているので知っている人も多いかもしれない. そして体系的なグラフ作成のルールというのがあるのだが, それ含めてをここで説明するのは大変だ. そのうち挑戦してみたくはある.

グラフの書き方に関する本は Tufte (2001) が古典的? であるが, 最近のものとして Healy (2018)Tufte (2001) の思想を受け継ぎつつ全ての図に対して作図した ggplot2 によるコードを公開しているため, タイトル通り ”practical“ である. 一方で, これらはいずれも日本語訳がない*29. Tufte 流の理論に則ったという本では, 藤 & 渡部 (2019) が比較的近い. ただしグラフの例は紹介されているものの実際にどのようなソフトウェアで作成するかといったことは書かれていない.

Japan.R 発表以降の追記

図9は, 主張したいことに対して不明瞭なグラフであった. 結局, 主要なステータスの平均値をバイオリン図にしたものがもっとも端的に主張したいことを伝えられる. 図10の上段は, ステータス値平均*30をタイトルごとにバイオリン図に表したもので, 下段は分布に対応する標準偏差である.

f:id:ill-identified:20191209232157p:plain
図10: シリーズごとの主要パラメータの平均値分布

明らかに分散が減少傾向にあり, かつ後期のシリーズほど尖度が上昇している*31. 個別のパラメータでは多峰性が見られたが, これは後期の作品ほど, 武力や知力が極端に低い設定の人物が増えたのかもしれない. さらに主要パラメータの要約統計量について確認してみる. 個人単位で, 主要パラメータの標準偏差とレンジを求め, それをタイトルごとにバイオリン図にしたのが図11になる. ここでも, レンジや標準偏差の分布は初期の作品ほど裾野が厚く, 後期のものは比較的小さな値に集中している. つまり初期の作品ほど人物の評価項目ごとのばらつきが大きいということが分かった.

f:id:ill-identified:20191209232330p:plain
図11: シリーズごとの主要パラメータ要約統計量のバイオリン図

全ての能力値の項目を使って検証できていないという問題はあるが, 「後期の作品ほど能力値の多様性が乏しくなりつつある 」という仮説を裏付ける結果が得られた.

主成分分析の利用

ステータスの項目は主要な4項目はほとんどのシリーズで採用されているが, 基本的にシリーズごとに設定は異なる*32. 単位を揃えるには標準化だが, 項目数は標準化できない. そこで, 主成分分析によって, 全ての項目を数種類の項目に凝縮してみる. 主成分の計算には組み込みの stat::prcomp() を, グラフの描画には factoextra::fviz_pcabiplot() を使用している.

ただし, バイプロットは負荷量の多い順に第2主成分までを使った散布図であり, 第1・第2主成分の累積寄与率が高くない場合は, ステータス値による特徴をうまく捉えられない場合もある*33(図12).

f:id:ill-identified:20191209232616p:plain
図12: シリーズごとの第2主成分までの累積寄与率

三國志2, 9 についてこの方法で求めた第1・第2主成分でプロットした人物散布図が図13である.

f:id:ill-identified:20191209232750p:plainf:id:ill-identified:20191209232755p:plain
図13: 三國志2および9の主成分バイプロット図

これらの傾向から, 概ね, 知力と武力は別の要素として見られる傾向がある.

魏・呉・蜀の勢力別ひいき

発表中に視聴者からも指摘があったが, 魏の曹操を主役にした漫画『蒼天航路』の人気を反映して, 従来は悪役であることが多い魏の人物の能力を底上げしたことが, 三國志シリーズのプロデューサーによって語られている*34.

三國志シリーズには「相性」というマスクステータス値があり, 主君と配下の値の差で相性が決まるようになっている. 今回参考にしたサイトの中にも相性値を掲載しているものもあったので, それらをもとに登場人物がどこに属するかを分類してステータス値をプロットする. 各人物について, 劉備, 曹操, 孫権, のいずれに最も相性値が近いかによって, 魏・呉・蜀のどれに属するかを判定する*35. 散布図で「武力」と「知力」で表したのが図14で, 主要ステータス数値の平均を, 散布図とバイオリン図でそれぞれ表したのが図15である.

f:id:ill-identified:20191209233140p:plainf:id:ill-identified:20191209233150p:plain
図14: 三国別のステータス分布

f:id:ill-identified:20191209233312p:plainf:id:ill-identified:20191209233322p:plain
図15: 三国別のステータス分布

まとめ

以上の検証から, 各作品の, 1~100の数値で表現される主要な能力値の平均の分布を見ると, 後期の作品ほど分布の分散が上昇し, かつ尖度が上昇している傾向にあることがわかった. これは, 『蒼天航路』や『正史三国志』での再評価を反映した結果, 多くの人物の評価が高いところに集中し, かえって能力の差別化が損なわれているのではないか, という仮説を裏付けるものになる. ただし, 今回の範囲では経時的な変化の検証にとどまっているため, それが正史三國志蒼天航路とどの程度相関があるのか, ということまでは確認できなかった.

では, あらゆる人物の再評価が進み, 能力の差別化がしづらくなる将来の歴史シミュレーションゲームはどうあるべきなのだろうか?

ここはやはり, 三国志3の分布の顕著な特徴に学んで, 水軍の指揮能力をもたせるべきなのだろうか? 例えば, 主成分析によって過去の作品で登場人物がどのように特徴づけられてきたかを再検討し, ばらつきが最大化するように因子分解する, というような機械的な解法も考えられる. しかし, 『三國志』シリーズのゲームデザインを, 人物評価以外の観点から振り返ってみると, 創作や史実で強大とされてきた勢力はそのまま強大でスタート時点から有利であり, 一方で噛ませ犬のように併呑される運命にある弱小勢力も存在する. 『三國志』シリーズでは昔から「ソウヒョウチョウに一騎打ちで勝つ」「キンセンゲンハクで天下統一」といった弱小勢力でのやりこみプレイができるというのも魅力の一つだと考えられる. 近年はリアルタイムストラテジーのような対人を前提とした戦略ゲームが増えているが, 三國志シリーズのゲームデザインもまた差別化の問題に直面しているのかもしれない.

私の発表はある意味毎回1人ハッカソンをしているようなものなのだが, 今回は特にわからないことだらけであった.

  • フォントレンダリングのことなんもわからん

  • Unicode (CJK統合漢字拡張) なんもわからん

  • 応用できそうな画像・文字認識の研究なんもわからん

というように, 不勉強な分野の話が多く要求された.

また, 当初の構想として, 原典を自然言語処理によって構造化し, なんらかの知見を引き出す, というものもあったが, 日本語ソースの人名ですら名寄せがここまで煩雑では, 非常に難しかっただろう*36.

参考文献



*1:是とする道徳心すらも, 長い中国の歴史の中で変遷しており, 時代によって人物描写も変化している. しかし今回はそこに深く入ることはしない. 詳しい話は 渡辺 (2011) を参照.

*2:とはいえ, 曹操を悪役とする作劇は, 日本においては吉川『三国志』の時点でかなり緩和されている気がする. 曹操は相変わらず冷酷・野心家・傲慢な人物ではあるが, 合理的な知恵者としての面も強調されている.

*3:天地を喰らう』はもはやおっさんしか知るまい.

*4:今鷹真・井波律子訳 (1977) 『三国志 魏書』 世界古典文学全集 24A, ISBN: 978-4-480-20324-3.

*5:今鷹真・小南一郎・井波律子訳 (1982) 『三国志 魏書・蜀書』 世界古典文学全集 24B, ISBN: 978-4-480-20324-3.

*6:小南一郎訳 (1989) 『三国志 呉書』 世界古典文学全集 24C, ISBN: 978-4-480-20354-0

*7:現在は全8冊の文庫版『正史三国志』として流通している.

*8:全く関係ないが『インド三国志』も面白い.

*9:宮城谷の三国志はほぼ史書をもとに記述を時系列順に編集し, 著者の人物評などを交えるという形式をとっている.

*10:このへんの人選は田中芳樹の影響を受けている気がする.

*11:三國志14:『銀河英雄伝説』コラボ情報

*12:もちろんこれはジョークである. 研究の新規性・独自性とは, 研究の開拓に対する貢献を伴ったものでなければならない. 単に突飛なだけ, 誰もやらなかったものを初めてやった, だけでは研究の価値を主張したことにならない.

*13:三國志』シリーズの正式名称は, 10作目まではローマ数字だが, ここでは便宜上全てアラビア数字で表記する.

*14:実際には『反三国志』に由来する人物は, ウンリョク, 『花関索伝』由来の人物はホウサンジョウだけである. 花関索伝の主役であるカンサク三国志演義にも登場する.

*15:この表記は 95年発売の『三国志5』にのみ見られた. 陳 (1974) では字で表記ししているので, これの影響か.

*16:Unicode のグリフや対応フォントの情報は, U+29166 (U+29166) Font Supportu29166 (𩅦) - GlyphWiki で確認できる.

*17:今回は既に3字以上の人名の名寄せを手動で行ったが, より汎用的な性能を確認したいため, ここでは3字以上の人名も含めて実施してみる. そのため, 画像のサイズは4文字分で固定し, 字数の少ない人名は横に引き伸ばしてレンダリングしたものを使う.

*18:どの文字画像でも変化のないピクセルは情報を持たないため除外し, 実際には4025次元を使った.

*19:まれなケースとして, 字 (あざな) が使われている場合もあるが, 当時の名の多くは1字である一方, 字の多くは2文字であり, 文字数が多いため手作業でもすぐに見つけることができた.

*20:初期の作品はハードの制約から, より簡単な表記を選んだとも考えられる.

*21:現代の簡体字では統一して同じ字として扱われる.

*22:要はクラスタリングのことだと思うのだが, この単語を見かけるようになったのは最近になってからな気がする.

*23:実装は Pythonhttps://github.com/vincentzlt/textprep に依存している.

*24:Turpault et al. (2019) は画像認識ではなく音声認識のテーマである.

*25:今回のデータは, 各人物が三国志演義正史三国志いずれに登場しているかをはっきり示す情報を含んでいない. 万全を期すならば詳細に調査すべきだが, 名寄せ処理と同様の理由で今回は割愛した.

*26:三國志1のみ「カリスマ」という名称になっている

*27:3D円グラフを使うのはやめよう | Okumura's Blog Wonder Graph Generator, 森藤 & あんちべ (2014)

*28:ユーレイ棒グラフ? | Okumura's Blog

*29:Tufte の名前は日本語文献でもちらほらみられるようになったが, そもそも著作は未だに翻訳されていない. だれかやりましょう?

*30:1~100の数値で表現されるステータス項目はシリーズごとに異なる. 武力, 魅力,知力, 政治, 統率, 陸指 (陸戦指揮), 水指 (水戦指揮) などがある.

*31:三國志3のみ, 瓢箪めいたくびれがあるが, これは「陸指」「水指」という2つのパラメータで能力の差別化がなされているからである. この2項目を除外して平均を取ると, 多峰性は消える.

*32:さらに, 今回参照したページは非公式のものなので, そもそも全ての項目が掲載されているわけではない.

*33:ただし, 作品によっては人物がある技能をもつかどうかのフラグが大量に掲載されているものがあり, これらも変数に含めた結果寄与率が下がっている可能性もある.

*34:三國志:人気歴史ゲームの誕生秘話 シブサワ・コウに聞く - MANTANWEB(まんたんウェブ)

*35:よって, 実際には各陣営に属していなかった群雄が三国に分類されることもある. 例えば, シリーズを通して董卓曹操と相性値が近く, 公孫瓚袁紹とその配下の人物は劉備孫権に近い. 一方で, シリーズによっては相性値が近くともさらに別のマスクステータスで「犬猿の仲」に設定されていることもある. 例: 孫権と張昭, 袁譚袁尚など.

*36:三国志演義は様々な説話を集めて編纂されたので, 話によって文体や人名の呼び方が違ったりする. 例えば, 関羽, 関雲長, 関公, 関将軍, など. ましてや正書法の整備されていない中近世.[