Elasticsearch Twitter 利用者性別判定

ElasticsearchをベースにTwitter利用者の性別判定システムを構築する。


Twitter 利用者の趣味嗜好など興味分野の分析であれば、以前公開した「Elasticsearch Twitter ツィート情報リアルタイム分類」のようにツィートの内容をベースに名詞系の品詞に特徴が出てくるのでそれほど難しくはないのですが、性別判定の場合はちょっと勝手が違います。

Twitter のブログを見ると、性別ターゲティングを使ったプロモーションを提供するために、Twitterのハンドル名やフォロー傾向をもとに性別を推測する方法を採用しているそうです。(日本語版ブログはこちら

感覚的にこの方法だと、すごいノウハウの蓄積と仕組みがないと真似できなそうなので、却下。

他に方法がないかと調べていると「Twitter 利用者の性別判定システムの構築」というのがあったので目を通してみました。色々数式とか難しいことが書いてありますが、目を細めて遠くから見てみると、要するに、

Twitter 上の文章は口語的な記述が多いから、代名詞(主に人称系代名詞)と終助詞の使い方に男女の特徴が出るよ〜。

ということらしい。

代名詞とは、「僕」、「わたし」、「あなた」、「われわれ」 、「これ」など名詞または名詞句の代わりに用いられる語。

終助詞とは、「(そうだよ)ね」、「(なぜ)かしら?」、「(元気)かい?」など、文の終わりにあって、疑問・詠嘆・感動・禁止などの意を表す語。

この考え方ならなんとなくしっくりくる。例えば、「今日の天気は晴れかしら?」の文章からは女性が話していると読み取れる。それは「かしら」という終助詞は一般的には女性が使うからだ。

もちろんリアルの性別ではなく男性的か、女性的かと言う Twitter 上での性別判定となるが、この考え方をベースに Elasticsearch を使用して仕組みを考えてみようと思う。

システム概要

基本的なシステムの概要は、「Elasticsearch Twitter ツィート情報リアルタイム分類」とほぼ同じです。過去のツィート情報から特徴を抽出し、その特徴を使ってパーコレータクエリーを作成して分類します。違いは、その特徴を抽出する対象が、今回は代名詞及び終助詞となり、新しいツィートを分類するためのパーコレータークエリーもその代名詞終助詞の使われ方を対象にするところが今回の特徴です。

以下はその流れ。

  1. 代名詞、終助詞が過去の集計できるようにアナライザー・マッピング定義を設計
  2. ツィート情報をインデックス
  3. 特徴的な代名詞、終助詞を性別ごとに分析する
  4. 分析して得た特徴的な代名詞、終助詞を使って、性別ごとにパーコレータクエリーを作成
  5. 新しくフィードされてきたツィートを性別判定パーコレーターに付き合わせて分類する。
  6. 性別分類された過去のツィートを対象に、任意のユーザーの性別傾向(男性的か女性的か)を分析する

代名詞、終助詞抽出準備

まずは、マッピング定義です。Twitter Stream API のツィートの内容は、text フィールドに入ってくるので、マルチフィールドを使って、 代名詞用のフィールド(noun_pronoun_misc)と、終助詞用のフィールド(particle_final)を定義します。それぞれの analyzer (インデックス側のアナライザー)は後ほど定義しますが、search_analyzer (サーチ側のアナライザー)は、keyword アナライザーを使用して、言語処理しないようにします。

Example Mapping:

{
"mappings": {
"tweets": {
"properties": {
"text": {
"type": "string",
"fields": {
"noun_pronoun_misc": {
// 代名詞
"type": "string",
"search_analyzer": "keyword",
"analyzer": "noun_pronoun_misc_analyzer"
},
"particle_final": {
// 終助詞
"type": "string",
"search_analyzer": "keyword",
"analyzer": "particle_final_analyzer"
}
}
}
}
}
}
}

次に、代名詞、終助詞用のインデックスアナライザーの定義ですが以下の例のように、ツィートテキスト情報から対象品詞の語句のみインデックスするように設定します。

※アナリシスプラグインはICUとkuromojiを使用しています。

Example Analyzers:

{
"settings": {
"analysis": {
"analyzer": {
"noun_pronoun_misc_analyzer": {
// 代名詞インデックスアナライザー
"type": "custom",
"char_filter": [
"icu_normalizer"
],
"tokenizer": "japanese_normal",
"filter": [
"noun_pronoun_misc"
]
},
"particle_final_analyzer": {
// 終助詞インデックスアナライザー
"type": "custom",
"char_filter": [
"icu_normalizer"
],
"tokenizer": "japanese_normal",
"filter": [
"particle_final"
]
}
},
"filter": {
"noun_pronoun_misc": {
// 代名詞フィルター
"type": "kuromoji_part_of_speech",
"stoptags": [
"名詞",
"名詞-一般",
"名詞-固有名詞",
"名詞-固有名詞-一般",
"名詞-固有名詞-人名",
"名詞-固有名詞-人名-一般",
"名詞-固有名詞-人名-姓",
"名詞-固有名詞-人名-名",
"名詞-固有名詞-組織",
"名詞-固有名詞-地域",
"名詞-固有名詞-地域-一般",
"名詞-固有名詞-地域-国",
"名詞-代名詞",
// "名詞-代名詞-一般",
"名詞-代名詞-縮約",
"名詞-副詞可能",
"名詞-サ変接続",
"名詞-形容動詞語幹",
"名詞-数",
"名詞-非自立",
"名詞-非自立-一般",
"名詞-非自立-副詞可能",
"名詞-非自立-助動詞語幹",
"名詞-非自立-形容動詞語幹",
"名詞-特殊",
"名詞-特殊-助動詞語幹",
"名詞-接尾",
"名詞-接尾-一般",
"名詞-接尾-人名",
"名詞-接尾-地域",
"名詞-接尾-サ変接続",
"名詞-接尾-助動詞語幹",
"名詞-接尾-形容動詞語幹",
"名詞-接尾-副詞可能",
"名詞-接尾-助数詞",
"名詞-接尾-特殊",
"名詞-接続詞的",
"名詞-動詞非自立的",
"名詞-引用文字列",
"名詞-ナイ形容詞語幹",
"接頭詞",
"接頭詞-名詞接続",
"接頭詞-動詞接続",
"接頭詞-形容詞接続",
"接頭詞-数接続",
"動詞",
"動詞-自立",
"動詞-非自立",
"動詞-接尾",
"形容詞",
"形容詞-自立",
"形容詞-非自立",
"形容詞-接尾",
"副詞",
"副詞-一般",
"副詞-助詞類接続",
"連体詞",
"接続詞",
"助詞",
"助詞-格助詞",
"助詞-格助詞-一般",
"助詞-格助詞-引用",
"助詞-格助詞-連語",
"助詞-接続助詞",
"助詞-係助詞",
"助詞-副助詞",
"助詞-間投助詞",
"助詞-並立助詞",
"助詞-終助詞",
"助詞-副助詞/並立助詞/終助詞",
"助詞-連体化",
"助詞-副詞化",
"助詞-特殊",
"助動詞",
"感動詞",
"記号",
"記号-一般",
"記号-読点",
"記号-句点",
"記号-空白",
"記号-括弧開",
"記号-括弧閉",
"記号-アルファベット",
"その他",
"その他-間投",
"フィラー",
"非言語音",
"語断片",
"未知語"
]
},
"particle_final": {
// 終助詞フィルター
"type": "kuromoji_part_of_speech",
"stoptags": [
"名詞",
"名詞-一般",
"名詞-固有名詞",
"名詞-固有名詞-一般",
"名詞-固有名詞-人名",
"名詞-固有名詞-人名-一般",
"名詞-固有名詞-人名-姓",
"名詞-固有名詞-人名-名",
"名詞-固有名詞-組織",
"名詞-固有名詞-地域",
"名詞-固有名詞-地域-一般",
"名詞-固有名詞-地域-国",
"名詞-代名詞",
"名詞-代名詞-一般",
"名詞-代名詞-縮約",
"名詞-副詞可能",
"名詞-サ変接続",
"名詞-形容動詞語幹",
"名詞-数",
"名詞-非自立",
"名詞-非自立-一般",
"名詞-非自立-副詞可能",
"名詞-非自立-助動詞語幹",
"名詞-非自立-形容動詞語幹",
"名詞-特殊",
"名詞-特殊-助動詞語幹",
"名詞-接尾",
"名詞-接尾-一般",
"名詞-接尾-人名",
"名詞-接尾-地域",
"名詞-接尾-サ変接続",
"名詞-接尾-助動詞語幹",
"名詞-接尾-形容動詞語幹",
"名詞-接尾-副詞可能",
"名詞-接尾-助数詞",
"名詞-接尾-特殊",
"名詞-接続詞的",
"名詞-動詞非自立的",
"名詞-引用文字列",
"名詞-ナイ形容詞語幹",
"接頭詞",
"接頭詞-名詞接続",
"接頭詞-動詞接続",
"接頭詞-形容詞接続",
"接頭詞-数接続",
"動詞",
"動詞-自立",
"動詞-非自立",
"動詞-接尾",
"形容詞",
"形容詞-自立",
"形容詞-非自立",
"形容詞-接尾",
"副詞",
"副詞-一般",
"副詞-助詞類接続",
"連体詞",
"接続詞",
"助詞",
"助詞-格助詞",
"助詞-格助詞-一般",
"助詞-格助詞-引用",
"助詞-格助詞-連語",
"助詞-接続助詞",
"助詞-係助詞",
"助詞-副助詞",
"助詞-間投助詞",
"助詞-並立助詞",
// "助詞-終助詞",
"助詞-副助詞/並立助詞/終助詞",
"助詞-連体化",
"助詞-副詞化",
"助詞-特殊",
"助動詞",
"感動詞",
"記号",
"記号-一般",
"記号-読点",
"記号-句点",
"記号-空白",
"記号-括弧開",
"記号-括弧閉",
"記号-アルファベット",
"その他",
"その他-間投",
"フィラー",
"非言語音",
"語断片",
"未知語"
]
}
},
"tokenizer": {
"japanese_normal": {
"mode": "normal",
"type": "kuromoji_tokenizer",
}
}
}
}
}

kuromoji_part_of_speech フィルターをカスマイズ設定して、代名詞アナライザーなら、代名詞以外を全てフィルタリングしたフィルターを設定し、終助詞も同じように検索用途では通常しないような特殊なアナライザーを設定しています。

以上の設定で、ツィート情報から代名詞、終助詞を分析・集計できる準備が整いました。

代名詞、終助詞の特徴抽出その1

男性的な代名詞・終助詞、女性的な代名詞・終助詞はどうやって定義すればよいでしょうか?

ウィキペディアによると、

男性語(Wikipedia)

  • 「俺」「僕」「私」「わし」「おいら」「自分」など一人称表現が多彩。
  • 私的な場所では、「お前」「てめぇ」「あいつ」「奴」「連中」など二人称・三人称ではやや乱暴な表現がある。
  • 男性特有の語尾表現には「ぜ」「だろ」といったものがあり、いずれもやや乱暴な表現。

女性語(Wikipedia)

  • 「わたし」や「あたし」など男性に比べて一人称表現の自由度が低い。
  • 語尾表現(終助詞)には「かしら」「かしらん」「こと」「して」「て」「ちょうだい」「ね」「のよ」「もの」「よ」「わ」「わね」「わよ」「わよね」など多彩だが、ユニセックスな言い回しが好まれるようになり、「てよだわ言葉」の流れをくむ女性語は中年以上の女性が用いるほかは、オネエ言葉に誇張された形で残っている。
  • 女性が使うとされてる終助詞にも、男性でも一般的な語が存在する。「(そうだ)ね」とか
  • 一人称代名詞に関しては以前と男女差が強く意識されており、「僕」や「俺」を常用する女性は極めて少数派。

ということらしいです。

実際、男性語と女性語の使い方は、中性化しているのが現代という感じがするので、上記の内容はあくまでもベースの条件として、ツィートの内容から男性的、女性的な言語表現を抽出したいと思います。以下はそのクエリー例です。

女性的な言語表現抽出クエリー例:

GET|POST /twitter/tweets/_search
{
"size": 0,
"query": {
"bool": {
"filter": [{
"range": {
"created_at": {
"gte": "now-1M",
"lte": "now"
}
}
}, {
"match": {
"source": "\"Twitter for iPhone\" \"Twitter for Android\" \"Twitter Web Client\" \"Twitter for iPad\""
}
}],
"must_not": [{
"match": {
"text": "RT"
}
}, {
"terms": {
"text.noun_pronoun_misc": ["俺", "おれ", "オレ", "僕", "ぼく", "ボク", "わし", "おいら", "自分", "お前", "君", "てめぇ", "あいつ", "奴", "連中", "やつ", "奴ら", "奴等", "僕ら", "おまえ", "おめぇー", "ヤツ", "我々", "我ら", "おら", "てめえ", "われ", "吾輩", "おのれ", "わい", "小生", "彼奴", "われわれ"]
}
}, {
"terms": {
"text.particle_final": ["ぜ", "ぞ", "な", "だろ"]
}
}],
"should": [{
"terms": {
"text.noun_pronoun_misc": ["わたし", "あたし", "うち", "あたくし", "あたい", "きみ", "あんた", "あーた", "あなた"]
}
}, {
"terms": {
"text.particle_final": ["かしら", "かしらん", "こと", "して", "て", "ちょうだい", "ね", "の", "のよ", "もの", "よ", "わ", "わね", "わよ", "わよね"]
}
}],
"minimum_should_match": 1
}
},
"aggs": {
"noun_pronoun_misc": {
"significant_terms": {
"field": "text.noun_pronoun_misc",
"exclude": "これ|それ|あれ|どれ|ここ|そこ|あそこ|どこ|こっち|そっち|あっち|どっち|こちら|そちら|あちら|どちら|こいつ|あいつ|どいつ|こなた|そなた|あなた|どなた|この|その|あの|どの|こう|そう|ああ|どう|こんな|そんな|あんな|どんな|どっか|どこぞ|よそ|これら|ここら|それら|あれこれ|かなた|なあに|あちこち|そんじょそこら|何れ|何|なん|なに|いつ|何時|いくつ|そっ|何処|みんな|皆|みなさん|誰|だれ|私|彼女|彼",
"size": 100,
"min_doc_count": 100
}
},
"particle_final": {
"significant_terms": {
"field": "text.particle_final",
"size": 100,
"min_doc_count": 100
}
}
}
}
クエリーの説明:
ツィート日時が現在から過去1ヶ月以内のツィートかつマニュアルで投稿(ソース元がTwitter for iPhoneなど)しているツィートを対象に、リツィートと男性的な代名詞・終助詞表現を含まず、女性的な代名詞または終助詞を含むツィートの中から、こそあど言葉、時制、共通人称系の語句を除外した代名詞の特徴語と終助詞の特徴的な語を抽出。

男性的な言語表現抽出クエリー例:

GET|POST /twitter/tweets/_search
{
"size": 0,
"query": {
"bool": {
"filter": [{
"range": {
"created_at": {
"gte": "now-1M",
"lte": "now"
}
}
}, {
"match": {
"source": "\"Twitter for iPhone\" \"Twitter for Android\" \"Twitter Web Client\" \"Twitter for iPad\""
}
}],
"must_not": [{
"match": {
"text": "RT"
}
}, {
"terms": {
"text.noun_pronoun_misc": ["わたし", "あたし", "うち", "あたくし", "あたい", "きみ", "あんた", "あーた", "あなた"]
}
}, {
"terms": {
"text.particle_final": ["かしら", "かしらん", "こと", "して", "て", "ちょうだい", "ね", "の", "のよ", "もの", "よ", "わ", "わね", "わよ", "わよね"]
}
}],
"should": [{
"terms": {
"text.noun_pronoun_misc": ["俺", "おれ", "オレ", "僕", "ぼく", "ボク", "わし", "おいら", "自分", "お前", "君", "てめぇ", "あいつ", "奴", "連中", "やつ", "奴ら", "奴等", "僕ら", "おまえ", "おめぇー", "ヤツ", "我々", "我ら", "おら", "てめえ", "われ", "吾輩", "おのれ", "わい", "小生", "彼奴", "われわれ"]
}
}, {
"terms": {
"text.particle_final": ["ぜ", "ぞ", "な", "だろ"]
}
}],
"minimum_should_match": 1
}
},
"aggs": {
"noun_pronoun_misc": {
"significant_terms": {
"field": "text.noun_pronoun_misc",
"exclude": "これ|それ|あれ|どれ|ここ|そこ|あそこ|どこ|こっち|そっち|あっち|どっち|こちら|そちら|あちら|どちら|こいつ|あいつ|どいつ|こなた|そなた|あなた|どなた|この|その|あの|どの|こう|そう|ああ|どう|こんな|そんな|あんな|どんな|どっか|どこぞ|よそ|これら|ここら|それら|あれこれ|かなた|なあに|あちこち|そんじょそこら|何れ|何|なん|なに|いつ|何時|いくつ|そっ|何処|みんな|皆|みなさん|誰|だれ|私|彼女|彼",
"size": 100,
"min_doc_count": 100
}
},
"particle_final": {
"significant_terms": {
"field": "text.particle_final",
"size": 100,
"min_doc_count": 100
}
}
}
}
クエリーの説明:
ツィート日時が現在から過去1ヶ月以内のツィートかつマニュアルで投稿(ソース元がTwitter for iPhoneなど)しているツィートを対象に、リツィートと女性的な代名詞・終助詞表現を含まず、男性的な代名詞または終助詞を含むツィートの中から、こそあど言葉、時制、共通人称系の語句を除外した代名詞の特徴語と終助詞の特徴的な語を抽出。

それぞれのクエリーで、以下のような実際のツィートで使われている代名詞・終助詞の特徴語を抽出することができます。

女性的な言語表現抽出結果例:

"took": 2466,
"timed_out": false,
"_shards": {
"total": 24,
"successful": 24,
"failed": 0
},
"hits": {
"total": 294610,
"max_score": 0,
"hits": []
},
"aggregations": {
"particle_final": {
"doc_count": 294610,
"buckets": [{
"key": "よ",
"doc_count": 143976,
"score": 3.1924138305859215,
"bg_count": 728829
}, {
"key": "ね",
"doc_count": 102212,
"score": 2.319482009514826,
"bg_count": 507107
}, {
"key": "わ",
"doc_count": 30732,
"score": 0.5234586314069047,
"bg_count": 194717
}, {
"key": "の",
"doc_count": 20077,
"score": 0.395772807403095,
"bg_count": 112455
}, {
"key": "かしら",
"doc_count": 1266,
"score": 0.034629388213908346,
"bg_count": 5329
}, {
"key": "なぁ",
"doc_count": 4740,
"score": 0.026488395883874024,
"bg_count": 68297
}, {
"key": "さ",
"doc_count": 1977,
"score": 0.013109556255373708,
"bg_count": 25523
}, {
"key": "ねー",
"doc_count": 2277,
"score": 0.009858905292760633,
"bg_count": 38154
}, {
"key": "なあ",
"doc_count": 1534,
"score": 0.009164662544596637,
"bg_count": 21192
}, {
"key": "ねぇ",
"doc_count": 1305,
"score": 0.00897698006066961,
"bg_count": 16441
}, {
"key": "ん",
"doc_count": 1045,
"score": 0.008713300961331154,
"bg_count": 11528
}, {
"key": "なー",
"doc_count": 1776,
"score": 0.004245382354636825,
"bg_count": 39736
}, {
"key": "ねえ",
"doc_count": 419,
"score": 0.003251233085189947,
"bg_count": 4862
}, {
"key": "よー",
"doc_count": 1920,
"score": 0.0030817410193978508,
"bg_count": 49706
}, {
"key": "け",
"doc_count": 1011,
"score": 0.002676480389047805,
"bg_count": 21658
}, {
"key": "べ",
"doc_count": 771,
"score": 0.0023912276343132323,
"bg_count": 15362
}, {
"key": "ねん",
"doc_count": 626,
"score": 0.0015657133469789517,
"bg_count": 13743
}, {
"key": "もん",
"doc_count": 221,
"score": 0.0013109387995281355,
"bg_count": 3067
}, {
"key": "かい",
"doc_count": 351,
"score": 0.0008698056143174593,
"bg_count": 7736
}, {
"key": "なぁー",
"doc_count": 130,
"score": 0.0008401185663820661,
"bg_count": 1707
}, {
"key": "で",
"doc_count": 285,
"score": 0.0005128649790399161,
"bg_count": 7102
}, {
"key": "や",
"doc_count": 291,
"score": 0.000490937200741849,
"bg_count": 7412
}, {
"key": "っけ",
"doc_count": 459,
"score": 0.0004892938786419669,
"bg_count": 13319
}, {
"key": "ネ",
"doc_count": 122,
"score": 0.0004245483067778081,
"bg_count": 2297
}, {
"key": "かぁ",
"doc_count": 263,
"score": 0.00032133463999664324,
"bg_count": 7374
}]
},
"noun_pronoun_misc": {
"doc_count": 294610,
"buckets": [{
"key": "わたし",
"doc_count": 7480,
"score": 0.28103779163186815,
"bg_count": 23632
}, {
"key": "あたし",
"doc_count": 1597,
"score": 0.0531061647185349,
"bg_count": 5640
}, {
"key": "きみ",
"doc_count": 420,
"score": 0.010047207706923071,
"bg_count": 1990
}, {
"key": "あんた",
"doc_count": 430,
"score": 0.00900896619177791,
"bg_count": 2286
}, {
"key": "キミ",
"doc_count": 146,
"score": 0.0007918140452207429,
"bg_count": 2143
}]
}
}
}

男性的な言語表現抽出結果例:

{
"took": 1570,
"timed_out": false,
"_shards": {
"total": 24,
"successful": 24,
"failed": 0
},
"hits": {
"total": 149776,
"max_score": 0,
"hits": []
},
"aggregations": {
"particle_final": {
"doc_count": 149776,
"buckets": [{
"key": "な",
"doc_count": 78679,
"score": 6.749258618452671,
"bg_count": 426431
}, {
"key": "ぞ",
"doc_count": 13758,
"score": 0.8442832274864359,
"bg_count": 101323
}, {
"key": "ぜ",
"doc_count": 9566,
"score": 0.7207241962664124,
"bg_count": 58446
}, {
"key": "ねー",
"doc_count": 4045,
"score": 0.1878080446428746,
"bg_count": 38169
}, {
"key": "ねん",
"doc_count": 829,
"score": 0.01950961579037791,
"bg_count": 13751
}, {
"key": "っけ",
"doc_count": 584,
"score": 0.008927011059948385,
"bg_count": 13325
}, {
"key": "なー",
"doc_count": 1113,
"score": 0.008179403797069504,
"bg_count": 39766
}, {
"key": "なぁ",
"doc_count": 1577,
"score": 0.0077057603728039395,
"bg_count": 68344
}, {
"key": "で",
"doc_count": 355,
"score": 0.006517095476950254,
"bg_count": 7106
}, {
"key": "け",
"doc_count": 665,
"score": 0.005777478297015659,
"bg_count": 21689
}, {
"key": "さ",
"doc_count": 699,
"score": 0.004922419395166479,
"bg_count": 25533
}, {
"key": "べ",
"doc_count": 502,
"score": 0.004859738517117259,
"bg_count": 15379
}, {
"key": "なあ",
"doc_count": 601,
"score": 0.004520419651849054,
"bg_count": 21212
}, {
"key": "ねぇ",
"doc_count": 473,
"score": 0.003654919774465415,
"bg_count": 16456
}, {
"key": "かい",
"doc_count": 264,
"score": 0.0027503271902577097,
"bg_count": 7739
}, {
"key": "や",
"doc_count": 233,
"score": 0.002111787047804726,
"bg_count": 7418
}, {
"key": "よー",
"doc_count": 888,
"score": 0.0020150207696926813,
"bg_count": 49743
}, {
"key": "ん",
"doc_count": 284,
"score": 0.0016071743983802986,
"bg_count": 11537
}, {
"key": "かぁ",
"doc_count": 202,
"score": 0.0014216138799878362,
"bg_count": 7381
}]
},
"noun_pronoun_misc": {
"doc_count": 149776,
"buckets": [{
"key": "俺",
"doc_count": 17107,
"score": 1.0391375846378226,
"bg_count": 127152
}, {
"key": "やつ",
"doc_count": 12927,
"score": 0.8657601575793761,
"bg_count": 87956
}, {
"key": "僕",
"doc_count": 7019,
"score": 0.3446395419769054,
"bg_count": 63060
}, {
"key": "奴ら",
"doc_count": 2833,
"score": 0.25610579070012635,
"bg_count": 14624
}, {
"key": "ぼく",
"doc_count": 1717,
"score": 0.1410904347987098,
"bg_count": 9684
}, {
"key": "君",
"doc_count": 3104,
"score": 0.14016082699435542,
"bg_count": 30010
}, {
"key": "お前",
"doc_count": 3843,
"score": 0.1339175352285954,
"bg_count": 46378
}, {
"key": "わい",
"doc_count": 990,
"score": 0.11148196861064211,
"bg_count": 4159
}, {
"key": "おれ",
"doc_count": 1433,
"score": 0.05852638022769674,
"bg_count": 15112
}, {
"key": "奴",
"doc_count": 1826,
"score": 0.05308916485155782,
"bg_count": 25595
}, {
"key": "おら",
"doc_count": 360,
"score": 0.04759229659010781,
"bg_count": 1299
}, {
"key": "わし",
"doc_count": 261,
"score": 0.04716360792997444,
"bg_count": 698
}, {
"key": "我々",
"doc_count": 444,
"score": 0.02372782862636907,
"bg_count": 3701
}, {
"key": "おまえ",
"doc_count": 363,
"score": 0.02181704769834235,
"bg_count": 2724
}, {
"key": "ボク",
"doc_count": 383,
"score": 0.021301410176239256,
"bg_count": 3081
}, {
"key": "おいら",
"doc_count": 144,
"score": 0.017397477570255032,
"bg_count": 566
}, {
"key": "僕ら",
"doc_count": 296,
"score": 0.009000164039431952,
"bg_count": 4000
}, {
"key": "我ら",
"doc_count": 229,
"score": 0.008075959881788834,
"bg_count": 2736
}, {
"key": "オレ",
"doc_count": 594,
"score": 0.005681165374990237,
"bg_count": 18328
}]
}
}
}
ひとりごと:
結果例見るとわざわざ分析して抽出するまでもないような気もする。。リアルの性別は置いておいて、女性的文章なのか男性的な文章なのかを分類できれば良いので、一般的な女性語・男性語の代名詞・終助詞をそのままのちに記載するパーコレータークエリーにしても良いかも。

代名詞、終助詞の特徴抽出その2

「代名詞、終助詞の特徴抽出その1」では、一般的な男性語、女性語をベースに、実際に使われているそれぞれの性別での特徴語を抽出しましたが、別の方法も考えたので紹介します。

それは性別が分かっているアカウントのツィートから特徴を得る方法です。

Twitter アカウントは有名人や芸能人など、利用者の性別が分かっているアカウントが存在します。これらのアカウントのツィート内容を分析すれば、男性、女性それぞれの代名詞・終助詞の特徴を分析できると考えました。

Elasticsearch にインデックス済みのツィートから、例えば男性的な代名詞・終助詞を抽出するには、男性 Twitter アカウント名の一覧を条件に、代名詞、終助詞インデックスフィールドに対して、Significant Terms Aggregation を使用して、集計するとその特徴が得られるはずです。

Example Query:

GET|POST /twitter/tweets/_search
{
"size": 0,
"query": {
"bool": {
"must": [{
"terms": {
"user.screen_name": ["ariyoshihiroiki", "masason", "motohage", "atsushilonboo", "tokuiyoshimi", "takapon_jp", "faridyu", "t_ishin", "HIDEO_KOJIMA_EN", "BAKARHYTHM", "S_Kagawa0317", "t_masahiro18", "sosotakei", "GekidanHitori", "matayoshi0"]
}
}],
"filter": [{
"range": {
"created_at": {
"gte": "now-1M",
"lte": "now"
}
}
}]
}
},
"aggs": {
"noun_pronoun_misc": {
"significant_terms": {
"field": "text.noun_pronoun_misc",
"exclude": "これ|それ|あれ|どれ|ここ|そこ|あそこ|どこ|こっち|そっち|あっち|どっち|こちら|そちら|あちら|どちら|こいつ|あいつ|どいつ|こなた|そなた|あなた|どなた|この|その|あの|どの|こう|そう|ああ|どう|こんな|そんな|あんな|どんな|どっか|どこぞ|よそ|これら|ここら|それら|あれこれ|かなた|なあに|あちこち|そんじょそこら|何れ|何|なん|なに|いつ|何時|いくつ|そっ|何処|みんな|皆|みなさん|誰|だれ|私|彼女|彼",
"size": 100,
"min_doc_count": 100
}
},
"particle_final": {
"significant_terms": {
"field": "text.particle_final"
"size": 100,
"min_doc_count": 100
}
}
}
}
クエリーの説明:
ツィート日時が現在から過去1ヶ月以内のツィートを対象に、列挙した男性 Twitter アカウントいずれかに該当するツィートの中から、こそあど言葉、時制、共通人称系の語句を除外した代名詞の特徴語と終助詞の特徴的な語を抽出。

代名詞、終助詞のそれぞれの特徴語が「代名詞、終助詞の特徴抽出その1」と同じようにランキングされます。

なんとなく「その2」の方法の方が、リアルな結果を得られそうな気がしますが、ピックアップしたTwitterアカウントのツィート情報がすでにインデックスされている必要があるため、そのTwitterアカウントの選定が結構大変です。。

性別判定パーコレーター

「代名詞、終助詞の特徴抽出その1」または「代名詞、終助詞の特徴抽出その2」で得た結果を使用して、男性、女性を判定するパーコレータークエリーをそれぞれ作成してください。

以下は男性判定パーコレータークエリー例です。

POST /twitter/.percolator/101
{
"id": "101",
"type": "gender",
"category": "男性",
"query": {
"bool": {
"should": [{
"terms": {
"text.noun_pronoun_misc": ["やつ", "俺", "僕", "お前", "奴", "君", "奴ら", "奴", "おれ"]
}
}, {
"terms": {
"text.particle_final": ["な", "ぞ", "ぜ", "ねー", "っけ", "ねん", "で", "ねぇ", "よー", "なぁ"]
}
}],
"minimum_should_match": 1
}
},
"created": "2015-12-28 18:30:40"
}
クエリーの説明:
男性的な代名詞または、男性的な終助詞のいずれかの条件にマッチ。

ちなみに、idtypecategorycreated などの属性は任意のメタ情報です。このメタ情報を使って、パーコレーターでマッチンスさせるときに、フィルタリングや集計などで使用することができますので必要であれば追加してください。

同じ要領で女性判定パーコレーターも作成します。

ツィートの分類

作成した性別判定パーコレーターを使用して、ツィート単位で男性的か女性的かに分類します。

Percolator API を使用して、新しいツィートの文章を条件に、マッチする性別判定パーコレータークエリーを得るには、以下のようにリクエストします。

リクエスト例:

GET|POST /twitter/tweets/_percolate
{
"doc": {
"text": "Elasticsearch で性別判定も作れるぜ!"
},
"filter": {
"term": {
"type": "gender"
}
}
}

レスポンス例:

{
"took": 11,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"total": 1,
"matches": [{
"_index": "twitter",
"_id": "101" // 男性
}]
}

このように、Percolator API を使用してマッチングすると、ツィートの文章に対してマッチする性別判定パーコレーターIDを取得することができるので、この結果をオリジナルツィートのメタ情報として付与しインデックスします。

PUT /twitter/tweets/xxxxxxxxxxxxxxxxx
{
"created_at": "Wed Jan 06 01:44:48 +0000 2016",
"id": xxxxxxxxxxxxxxxxx,
"id_str": "xxxxxxxxxxxxxxxxx",
"text": "Elasticsearch で性別判定も作れるぜ!",
"source": "<a href=\"http://twitter.com/download/android\" rel=\"nofollow\">Twitter for Android</a>",
...
  "gender": "男性"    // メタ情報として付与
}

性別傾向分析

あとは、Kibana や クエリーを使って、性別付与済みのツィート情報を対象にクエリーを投げて結果を取得するだけです。

例えば、あるユーザーの Twitter ハンドル名 で絞り込んだツィート情報を先ほどの性別がタグ付けされている gender フィールドを対象に集計すればそのユーザーの性別傾向の結果を得ることができます。

また、絞り込み条件を興味分野に変えて、例えば「サッカー」で絞り込んで性別で集計すれば女性・男性のどちらの方がサッカーに興味を持っているのかなど、様々な分析をすることができるはずです。

サッカーに興味の有る性別傾向を分析するクエリー例:

GET|POST /twitter/tweets/_search
{
"size": 0,
"query": {
"bool": {
"filter": [{
"range": {
"created_at": {
"gte": "now-1M",
"lte": "now"
}
}
}, {
"match": {
"source": "\"Twitter for iPhone\" \"Twitter for Android\" \"Twitter Web Client\" \"Twitter for iPad\""
}
}],
"must": [{
"simple_query_string": {
"query": "サッカー",
"fields": ["text"]
}
}]
}
},
"aggs": {
"genders": {
"terms": {
"field": "gender"
}
}
}
}
One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.