機械学習で「はてな匿名ダイアリー」の投稿の著者の性別を当てる

tl;dr

何をトチ狂ったのか、ここ一ヶ月くらい「はてな匿名ダイアリーに投稿された記事のタイトル及び本文から機械学習で著者の性別を当てる」という試みをしていました。結果、こんな感じで「人気記事アーカイブ」のページに推定された著者の性別を表示する Chrome 拡張ができました。

chrome.google.com

例えば、同一の男性による投稿(とされている)「彼女できないぞ日本死ね」と「皆さんへのご報告、やっぱりダメでした日本死ね」はどちらも男性と推定されました。

また、「保育園落ちた日本死ね!!!」は女性と推定されました。一方で、「おっさんが流行りのゲームを作るやってみた結果」は男性と推定されてほしかったのですが、女性と推定されてしまいました。

今後の展望としては、今より分類精度を向上させたいのと、年代など他の著者情報も推定してみたいです。

以降の文章には、分類モデルやシステムの実装について詳しく書いてあります。興味があればぜひ。

モチベーション

一般的なブログサービスでは、ふつう、ブログの記事本文を読む前に書き手の情報を知ることができます。本人の公開設定によりますが、例えば名前、性別、年代、職業、家族構成などが考えられます。

当然、はてな匿名ダイアリーでそれらの情報を知ることはできません。しかし、できないと言われたらよりやりたくなるのが男の子のサガです。性だけに!*1

とは言いつつも、本当にできないことをしようとするのは時間が勿体無いので、できそうかどうかの見通しを立てる必要があります。文章から著者の性別を当てるということは、そもそも可能でしょうか?

いいんちょチャン、オハヨウ〜😄😃✋(^з<)😍お弁当のおにぎり🍙が美味しくて、それと一緒にいいんちょチャンのことも食べちゃいたいな〜❗😚😆ナンチャッテ(^з<)❗😘 #おじさん文章ジェネレーター

この文章は「おじさんがLINEやメールで送ってきそうな文を生成するサービス」であるところの「おじさん文章ジェネレーター」で自動生成された文章です。

oji.netlify.com

確かに、我々はこの文章から「めんどくさい中高年の男性感」を色濃く感じられますが、それは何故でしょうか?おじさんっぽさとの因果関係はさておき、この文章には以下の特徴があります。

  • 二人称が〇〇チャン
  • 絵文字が多用されている
  • 下ネタが使われている

もし、これらの特徴がおじさんっぽさと関係しているとすれば、文章からこれらの特徴がどの程度表れているかを定量的に求めることで「文章の著者がおじさんかどうか」をプログラムで判断することができそうです。わかりやすい例としておじさんを挙げましたが、著者が女性(男性)かどうかを判断する場合についても、特徴が何かさえわかれば同じことが言えるでしょう。

リサーチ

大抵、自分が思いついたことというのは他の人が先に考えているもので、今回も例に漏れず国内外で多くの似たような研究が既に行われていました。

例えば池田ら(2006)*2は、日本語で記述されたブログ記事を男女で分類するために以下を素性としています。

Yahoo! Blogなどから大量の男女のブログ記事を収集し、記事からこれらの素性を抽出してLinear SVMで学習したところ、88.9%の精度で自動分類可能な分類モデルが作成されたことを報告しています。また、実際に素性として使われることはなかったものの、「甘いお菓子は女性の方が好む」といった意味論的な分析に踏み込むことも有効であろうとのことです。

財津ら(2017)*3はblog記事本文からの著者性別推定に有効な素性は何かを調査し、カイ二乗検定・t検定の結果から、ひらがな・片仮名・漢字の使用率、読点の使用頻度、小書き文字の「っ」、「ゃ」などが有用であることを報告しています。また、池田らの研究をはじめ多くの先行研究でSVMによる分類が採用されていましたが、ランダムフォレストとSVMで分類の精度を比較したところランダムフォレストの方が明らかに良い精度が得られたことも報告しています。

泉ら(2008)*4は10代・20代・30代のブログ記事を大量に収集し、提案手法で重要度が高いとされた2-gramを特徴量として、ナイーブベイズで未知のブログ記事を10代・20代・30代・その他にF値71%で分類できたことを報告しています。

さて、先行研究のありがたい報告の数々をふまえて、以下のように実装の見通しを立てました。

  1. 性別の推定は年代の推定と比べて分類の精度が高く、よりシンプルなので、まずは性別の推定に挑戦する
  2. 素性には池田ら、泉らの報告で有用とされたものを組み合わせて使う。どの組み合わせが最も良いかは実際に訓練および評価して確認する

分類モデルを実装する

先行研究の内容を参考に、データセットを構築し、特徴量を抽出して訓練することで分類モデルを生成し、そしてモデルを評価します。

今回使うプログラムはすべてF#というプログラミング言語で実装しました。.NET環境では機械学習のためのフレームワークとして最近ML.NETなるものが出てきたそうなので、これをF#から使うことにします。

またまた余談ですが、F#は素晴らしいプログラミング言語だと思うので、プログラマの方はぜひ一度使ってみてほしいと思います。F#がどのようなプログラミング言語でどんなシーンで活躍するのかについては以下の記事が詳しいです。

qiita.com

データセットの構築

分類モデルを生成するために、まずデータセットを用意する必要があります。データセットとはすなわち、分類モデルの訓練および評価に利用する男女別のブログ投稿です。当初ははてな匿名ダイアリーから記事をスクレイピングすることを検討しましたが、はてな匿名ダイアリーでは著者のユーザプロファイルが不明であり、いわゆるラベル的な情報が存在しません。記事を一件ずつ人手で読んで、性別のラベリングをしなければならないのです。これはつらそうです。日本死ね!みたいな記事を読み続けたらつらい気持ちになることは間違いないでしょう。

 ここでまたもや先行研究が道標をくれました。池田らは、Yahoo!ブログおよび楽天ブログにおけるブログから選択した612件のブログうち、著者のプロフィール欄の性別がブログ本文から読み取れる性別と一致した割合は95.3%であったと報告しています。かなりの高確率です。そこで、今回は簡単のために、はてな匿名ダイアリーではなく、プロフィール欄から著者の性別がわかる他のブログサービスから収集したブログ記事をプロフィール欄の性別情報を信用してそのままデータセットに使うことにしました。Amebaブログから男性・女性のブログ投稿をそれぞれ4000件ずつスクレイピングし、1:4で訓練データとテストデータに分類しました。

訓練

関連研究を参考に、分類につかう素性とアルゴリズムを以下の通りに決定しました。

一部の素性について追加で詳しく説明します。

データセットにおいて、男女間でカイ二乗値の高い形態素を調べる

「男女間でカイ二乗値の高い形態素」は、まずデータセットにおいて30回以上出現する形態素をリストアップし、それらの形態素についてカイ二乗検定を行うことで求めました。データセットに出現する全形態素についてカイ二乗検定を行うことは、計算量的に現実的でないためです。池田らは、カイ二乗値の高い形態素上位10・50・100・500個の出現頻度を素性として分類したところ、上位50個を使った場合に最も高い精度を得られたことを報告しています。したがって今回は上位50個の形態素を素性に組み込みました。

実際の「カイ二乗値の高い形態素ランキングtop50」はこんな感じでした。

  1. ワタシ
  2. ケド
  3. チャ
  4. アワセ
  5. コンナ
  6. ハート
  7. キラキラ
  8. タラ
  9. オイ
  10. ノデ
  11. ナー
  12. クレ
  13. タノシ
  14. マシ
  15. ッテ
  16. タリ
  17. アワ
  18. ステキ
  19. カッ
  20. トイアワセ
  21. オイシ
  22. デス
  23. トモダチ
  24. テル
  25. ハシ
  26. チャウ
  27. アエ
  28. トッテモ
  29. エミ
  30. タベ
  31. タチ
  32. ハシッ
  33. キモチ
  34. ココロ
  35. カエ
  36. アッ
  37. カワイイ
  38. イッパイ
  39. モーシコミ
  40. デキ
  41. シアイ
  42. ムスコ

女性がよく使いそうな形態素が並んでいることがわかります。これは期待通りの結果です。読みのデータを利用したため、少々見づらいですが…🙇‍♂️

池田らが2003年当時のYahoo! Blogの記事中の形態素に対してカイ二乗検定を行った際と同様、「ワタシ」が最もカイ二乗値の高い形態素となりました。面白かったのは、「ダンナ」「ダンセイ」などの形態素カイ二乗値が高くなりそうな形態素であり、「前述のデータセットにおいて30回以上出現する形態素」にも存在していたものの、ランクインは果たされなかったという点です。私のミスで具体的に何位だったのかのデータを取り忘れてしまったので、時間のある時に確認しておきたいです。「50位以内には入っていないけれど51位〜100位の間に入っていて、上位50位ではなくそれらの形態素を含むように上位80位くらいを使うようにしたほうが精度が上がる」ということも考えられます。

先行研究で有用とされていたが、今回のデータセットではそうでなかった素性

財津らの報告によると、男女間でカタカナの使用頻度に有意な差があるとされていますが、今回のデータセットでは確認できなかったため除外しました。また、読点「、」や小書き文字「っ」「ゃ」の出現回数が有効と報告されていて、実際に女性の記事ではこれらの形態素の出現回数が男性の記事における出現回数より高かったのですが、カイ二乗値の高かった形態素上位50個にこれらの形態素が含まれていなかったため、さほど重要でないと判断し素性には組み込みませんでした。

分類アルゴリズム

分類アルゴリズムには先行研究で用いられていたSVMとRandom Forestに加えてLogistic Regressionを検討しましたが、結果的に最も精度の良かったRandom Forestを採用しました。この結果は財津らの報告と一致しています。

分類モデルの評価

前項で説明した内容で訓練し生成されたモデルを、テストデータを用いて評価しました。なお、1(Positive)の場合は男性、0(Negative)の場合を女性としています。モデルの評価結果は以下のようになりました。

男性の記事を男性として分類できた割合は0.74で、女性の記事を女性として分類できた割合は0.79でした。全体の正解率は76.31%でした。

考察

モデルの評価でNegative PrecisionがPositive Precisionより高くなりました。これは先行研究でも報告されているように、女性のほうが「私」「~ちゃ」などのカイ二乗値の高い形態素をよく使う傾向にあり、判別されやすいためだと考えています。

また、76.5%は先行研究で報告されている精度より7%ほど低い値となりました。その理由の一つは、先行研究が特定のユーザの過去のブログ投稿すべてを推定に利用できた一方で、今回の取り組みでは投稿一つのみから推定したためと考えています。ただし、はてな匿名ダイアリーの人気記事アーカイブ全記事の文字数の中央値は831であった一方で、今回利用したデータセットの文字数の中央値は279でした。したがって「文字数が少ないから精度が低かった」という仮説が正しければ、はてな匿名ダイアリーの人気記事アーカイブの記事に対しては、テストデータ中の記事より高い精度で性別を推定できることが期待できます。

そして、これは一番悔しかったことですが、「人間が読んだら書き手の性別が数秒でわかってしまうような記事でも、今回の分類モデルでは分類できなかった」というケースが多く存在しました。例えば、旦那の話をしているのに男性と推定してしまったり、嫁の話をしているのに男性と推定してしまったりすることが多くありました。本来、「嫁」「旦那」は先の「カイ二乗値の高い形態素ランキング」にランクインするはずなのですが、今回私が楽をしてデータセットを構築したことで(はてな匿名ダイアリーではなくべつのブログサービスのデータを使ってしまったので)こうした残念な結果を招いてしまったのかもしれません…。

また、今回は文章の書き方的な特徴を学習して分類するアプローチを取りましたが、文章中で触れられている話題を解釈して分類する、という方法も考えられます(池田らもこのアプローチが有用であろうとしています)。もしそれが可能なら、嫁/旦那問題にも対応できそうです。あくまで予想ですが、話題の解釈などの意味論的なアプローチと、今回試した書き方の特徴から分類するアプローチをいい感じに組み合わせるとすごく高精度になる予感がしています。

Chrome拡張の実装

さいごに、作成した分類モデルをつかって、著者の性別推定結果を実際のanondのページ上に表示する仕組みをつくっていきます。

直感的に実装を考えると、今話題のtensorflow.jsなどをつかってブラウザ上で推定を行うなどが思い浮かびます。しかし、今回はML.NETでモデルを作成してしまったため、tensorflow.jsでモデルを使うことはできません*5。なので、すこし面倒ですが以下のようなアーキテクチャを組むことにしました。

f:id:E_ntyo:20191224174116p:plain

あらかじめ記事を推定し結果をデータベースなどに永続化しておき、ブラウザではその結果を取得するだけというアーキテクチャです。あらかじめ過去の人気記事をすべてまとめて推定しておき(10時間くらいかかりました)、あとは一日ごとに定期実行で、新着記事や人気記事を取得し推定して結果をデータベースに挿入していくようにしています。

さいごに

僕は機械学習NLPも素人なので、この手の取り組みに詳しい人がいたら教えてください 🙇‍♂️

また、僕は承認欲求が強い方なので、このブログやはてなブックマークのコメント欄に「すごい」とか肯定的なことを書いてもらえたりすると励みになります。そうなるとそれに味をしめて、今後またこういう取り組みをする可能性が高まります!

最後までご覧いただきありがとうございました。増田ユーザの方は、去年はてなインターンでつくったAlexaスキル「はてな匿名ダイアリーのいい話」もよろしくお願いいたします。こちらは公式です。

gigazine.net

*1:この記事の著者の性別は男です

*2:Daisuke, Ikeda. blog の著者の性別推定. 言語処理学会第12回年次大会発表論文集. 2006. p. 356–359.

*3:亘 財津, 明哲 金. ランダムフォレストによる著者の性別推定 -犯罪者プロファイリング実現に向けた検討-. 情報知識学会誌. 2017, vol. 27, no. 3, p. 261–274.

*4:Izumi, Masataka, Miura, Takao, Shioya, Isamu. Entropy-Based Age Estimation of Blog Authors. Computer Software and Applications Conference (COMPSAC), IEEE Annual International. 2008, p. 795–800.

*5:どうやらML.NETでは内部でTensorflowを使っているようなので、自分でTensorflowのモデルのファイルフォーマット -> Tensorflow.jsのモデルのファイルフォーマットなプログラムを書くことで使えるようになるのかもしれないです。そんなことできるのか?