LoginSignup
11
5

More than 3 years have passed since last update.

【Python】Watsonを使ってツイートから性格推定をした

Last updated at Posted at 2019-07-22

最近、業務でフォーラムに行く機会があり、そこでIBMの方とお話させてもらった。
そこで知ったのだが、IBMが所有しているAIのWatsonは各種言語向けのAPIを公開しているらしい。
しかも基本無料
(使用量によって料金がかかる課金システム)
スクリーンショット 2019-07-21 22.38.47.png
上記画像のように、Watsonの様々な機能を利用することができる。

今回は興味をもった性格推定(Personality Insights)をPythonで実装してみた。
TwitterのツイートデータをWatsonに食べさせて、性格を推定するといった流れだ。

personality-insights-demo(GitHub)

環境構築

  • Python 3.6.8
  • IBM-Watson 3.1.2
  • Tweepy 3.8.0

パッケージはpipで入る。
ローカルを汚したくなかったので、Cloud9で実装した。

Watsonでの性格推定

Watsonはテキストデータから、書き手の性格を推定できるようだ。
面白いと思ったのは、テキストデータの意味を理解して推定するのではなく、文章の書き方の癖から推定するという点。
直感的なイメージだが、数字が多い人は理論派っぽいみたいな感じだろうか...。

最強のチームはAIが作る!? Watsonの性格分析ツール開発秘話

今回実装した流れ

実装の流れはシンプル
1. 指定したユーザのツイートを取得する
2. ノイズになりそうな部分(後述)を除外する
3. Watson APIに用意したデータを食べさせる
4. jsonで結果を出力する

本当はテストデータに著名人のツイートを使おうと思っていた。
みんな知っているし、なんとなくどんな性格かも予想ができるし。

ただ、IBMは他人のツイートの分析結果をアップロードすることを禁止している。(許可を取ればいいらしい)

仕方なしに今回は自分のツイートデータを入力する。
自分のことを知らない人がみても、推定できているのか否か全くわからないだろうけど...。

入力データ(ツイート取得)

ツイッターからデータを取得する前に、IBMのサンプルデータを確認する。
IBMが公開しているサンプルでも、ツイートを食べさせているのだが、気になった点がある。
下記のjsonファイルはサンプルデータの抜粋。

tweets.json
{
  "contentItems": [
    {
      "content": "Wow, I liked @TheRock before, now I really SEE how special he is. The daughter story was IT for me. So great! #MasterClass",
      "contenttype": "text/plain",
      "created": 1447639154000,
      "id": "666073008692314113",
      "language": "en"
    },
    {
      "content": ".@TheRock how did you Know to listen to your gut and Not go back to football? #Masterclass",
      "contenttype": "text/plain",
      "created": 1447638226000,
      "id": "666069114889179136",
      "language": "en"
    },
    {
      "content": "RT @patt_t: @TheRock @Oprah @RichOnOWN @OWNTV this interview makes me like you as a fellow human even more for being so real.",
      "contenttype": "text/plain",
      "created": 1447637030000,
      "id": "666064097562247168",
      "language": "en"
    }
  ]
}

contentがツイート本文となっているわけだが、見てわかるように、リツイートやリプライ先のユーザIDが入ってしまっているのがわかる。

実際Twitter APIを叩いてツイートを取得すると、
- リツイート
- リプライ先のユーザID
- 本文中のURL
など、ノイズになりそうなものがちらほらある。

今回は取得したツイートから上記3つを間引いて、入力データを作成する。

ツイートを取得する部分はこんな感じ。

twitter_module.py
import tweepy
import re

def export_tweet_as_text(account):

    # TwitterAPIに関するAPIKeyを入力
    CONSUMER_KEY = 'xxxx'
    CONSUMER_SECRET = 'xxxx'
    ACCESS_TOKEN = 'xxxx'
    ACCESS_TOKEN_SECRET = 'xxxx'

    # APIインスタンス生成
    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    api = tweepy.API(auth)

    # 保存用テキストファイルを生成
    with open('../resources/tweets.txt', 'w') as f:

        # ツイートを取得
        tweet_count = 0
        pages=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
        for page in pages:
            tweets=api.user_timeline(account, count=200, page=page)
            for tweet in tweets:
                tweet_text = tweet.text

                # RTを除外
                retweet_flag = False
                if tweet_text.find('RT') != -1:
                    retweet_flag = True
                if retweet_flag:
                    continue

                # ツイートから,URLとリプライ先のユーザIDを削除
                tweet_text = re.sub(r"(https?|ftp)(:\/\/[-_\.!~*\'()a-zA-Z0-9;\/?:\@&=\+\$,%#]+)", "", tweet_text)
                tweet_text = re.sub(r"@[a-zA-Z0-9_]+ ","",tweet_text)

                # ファイルに書き込み
                f.write(tweet_text + '\n')

Twitter APIやTweepyの使い方はこのあたりが参考になります。

Twitter APIの申請手順まとめ【2019年最新版】
TweepyでTwitterの特定のユーザから3200ツイートの取得
API Reference Tweepy

Watsonで性格推定

入力データができたら、あとはWatsonに食べさせるだけ!

ソースはこんな感じ。

watson_module.py
import json
from ibm_watson import PersonalityInsightsV3

def analyze_personality(text_path):

    # APIインスタンスを生成
    service = PersonalityInsightsV3(
        version='2017-10-13',
        url='https://gateway-tok.watsonplatform.net/personality-insights/api',
        iam_apikey='XXXX')

    # 性格を分析
    with open('../resources/tweets.txt', 'r') as profile_text:
        profile = service.profile(
            profile_text.read(),
            'application/json',
            content_language='ja',
            accept_language='ja').get_result()

        # ファイルに書き込み
        with open('../result/result.json', 'w') as f:
            json.dump(profile, f, ensure_ascii=False, indent=2)

IBMのサンプルソースに一部変更を加えた形。
- 入力、出力の言語に日本語を指定
- 出力されたASCIIコードを変換
など、細々と変更。

Watson APIは日本語であまりいい説明がなかったので、リファレンスを参考にするのがいいと思う。
API Reference Watson
公式サンプルソース(GitHub)

後は2つのメソッドをいい感じに動かせば、結果が出力されます。

出力結果

今回の出力結果はこんな感じ。長いです。

tweets.json
{
  "word_count": 1477,
  "processed_language": "ja",
  "personality": [
    {
      "trait_id": "big5_openness",
      "name": "知的好奇心",
      "category": "personality",
      "percentile": 0.3269748764392166,
      "significant": true,
      "children": [
        {
          "trait_id": "facet_adventurousness",
          "name": "大胆性",
          "category": "personality",
          "percentile": 0.851632683688357,
          "significant": true
        },
        {
          "trait_id": "facet_artistic_interests",
          "name": "芸術的関心度",
          "category": "personality",
          "percentile": 0.08248046823602373,
          "significant": true
        },
        {
          "trait_id": "facet_emotionality",
          "name": "情動性",
          "category": "personality",
          "percentile": 0.01269078854956246,
          "significant": true
        },
        {
          "trait_id": "facet_imagination",
          "name": "想像力",
          "category": "personality",
          "percentile": 0.07828538874336671,
          "significant": true
        },
        {
          "trait_id": "facet_intellect",
          "name": "思考力",
          "category": "personality",
          "percentile": 0.3185276327945955,
          "significant": true
        },
        {
          "trait_id": "facet_liberalism",
          "name": "現状打破",
          "category": "personality",
          "percentile": 0.7757134968207737,
          "significant": true
        }
      ]
    },
    {
      "trait_id": "big5_conscientiousness",
      "name": "誠実性",
      "category": "personality",
      "percentile": 0.5968521957686052,
      "significant": true,
      "children": [
        {
          "trait_id": "facet_achievement_striving",
          "name": "達成努力",
          "category": "personality",
          "percentile": 0.4680138014818657,
          "significant": true
        },
        {
          "trait_id": "facet_cautiousness",
          "name": "注意深さ",
          "category": "personality",
          "percentile": 0.2776913924363156,
          "significant": true
        },
        {
          "trait_id": "facet_dutifulness",
          "name": "忠実さ",
          "category": "personality",
          "percentile": 0.646560141519093,
          "significant": true
        },
        {
          "trait_id": "facet_orderliness",
          "name": "秩序性",
          "category": "personality",
          "percentile": 0.9673235293559517,
          "significant": true
        },
        {
          "trait_id": "facet_self_discipline",
          "name": "自制力",
          "category": "personality",
          "percentile": 0.9534233902088189,
          "significant": true
        },
        {
          "trait_id": "facet_self_efficacy",
          "name": "自己効力感",
          "category": "personality",
          "percentile": 0.8047098839215382,
          "significant": true
        }
      ]
    },
    {
      "trait_id": "big5_extraversion",
      "name": "外向性",
      "category": "personality",
      "percentile": 0.886006317418282,
      "significant": true,
      "children": [
        {
          "trait_id": "facet_activity_level",
          "name": "活発度",
          "category": "personality",
          "percentile": 0.05870481709245734,
          "significant": true
        },
        {
          "trait_id": "facet_assertiveness",
          "name": "自己主張",
          "category": "personality",
          "percentile": 0.35164467138634853,
          "significant": true
        },
        {
          "trait_id": "facet_cheerfulness",
          "name": "明朗性",
          "category": "personality",
          "percentile": 0.7584765889006709,
          "significant": true
        },
        {
          "trait_id": "facet_excitement_seeking",
          "name": "刺激希求性",
          "category": "personality",
          "percentile": 0.4626730374972881,
          "significant": true
        },
        {
          "trait_id": "facet_friendliness",
          "name": "友好性",
          "category": "personality",
          "percentile": 0.9993552110743642,
          "significant": true
        },
        {
          "trait_id": "facet_gregariousness",
          "name": "社交性",
          "category": "personality",
          "percentile": 0.821949816324011,
          "significant": true
        }
      ]
    },
    {
      "trait_id": "big5_agreeableness",
      "name": "協調性",
      "category": "personality",
      "percentile": 0.43064808235299346,
      "significant": true,
      "children": [
        {
          "trait_id": "facet_altruism",
          "name": "利他主義",
          "category": "personality",
          "percentile": 0.8011665196131375,
          "significant": true
        },
        {
          "trait_id": "facet_cooperation",
          "name": "協働性",
          "category": "personality",
          "percentile": 0.23474709969090873,
          "significant": true
        },
        {
          "trait_id": "facet_modesty",
          "name": "謙虚さ",
          "category": "personality",
          "percentile": 0.2789880236799839,
          "significant": true
        },
        {
          "trait_id": "facet_morality",
          "name": "強硬さ",
          "category": "personality",
          "percentile": 0.555139731625757,
          "significant": true
        },
        {
          "trait_id": "facet_sympathy",
          "name": "共感度",
          "category": "personality",
          "percentile": 0.33013703370248587,
          "significant": true
        },
        {
          "trait_id": "facet_trust",
          "name": "信用度",
          "category": "personality",
          "percentile": 0.932881844256453,
          "significant": true
        }
      ]
    },
    {
      "trait_id": "big5_neuroticism",
      "name": "感情起伏",
      "category": "personality",
      "percentile": 0.5317695782374742,
      "significant": true,
      "children": [
        {
          "trait_id": "facet_anger",
          "name": "激情的",
          "category": "personality",
          "percentile": 0.1661703194086514,
          "significant": true
        },
        {
          "trait_id": "facet_anxiety",
          "name": "心配性",
          "category": "personality",
          "percentile": 0.2511270165944251,
          "significant": true
        },
        {
          "trait_id": "facet_depression",
          "name": "悲観的",
          "category": "personality",
          "percentile": 0.44009168638198337,
          "significant": true
        },
        {
          "trait_id": "facet_immoderation",
          "name": "利己的",
          "category": "personality",
          "percentile": 0.690512849700951,
          "significant": true
        },
        {
          "trait_id": "facet_self_consciousness",
          "name": "自意識過剰",
          "category": "personality",
          "percentile": 0.05802391279529695,
          "significant": true
        },
        {
          "trait_id": "facet_vulnerability",
          "name": "低ストレス耐性",
          "category": "personality",
          "percentile": 0.2799141848650055,
          "significant": true
        }
      ]
    }
  ],
  "needs": [
    {
      "trait_id": "need_challenge",
      "name": "挑戦",
      "category": "needs",
      "percentile": 0.912788130027943,
      "significant": true
    },
    {
      "trait_id": "need_closeness",
      "name": "親密",
      "category": "needs",
      "percentile": 0.47916836503889804,
      "significant": true
    },
    {
      "trait_id": "need_curiosity",
      "name": "好奇心",
      "category": "needs",
      "percentile": 0.968932858050091,
      "significant": true
    },
    {
      "trait_id": "need_excitement",
      "name": "興奮",
      "category": "needs",
      "percentile": 0.9976361241706758,
      "significant": true
    },
    {
      "trait_id": "need_harmony",
      "name": "調和",
      "category": "needs",
      "percentile": 0.009193757113194367,
      "significant": true
    },
    {
      "trait_id": "need_ideal",
      "name": "理想",
      "category": "needs",
      "percentile": 0.917518963157462,
      "significant": true
    },
    {
      "trait_id": "need_liberty",
      "name": "自由主義",
      "category": "needs",
      "percentile": 0.9970523431240045,
      "significant": true
    },
    {
      "trait_id": "need_love",
      "name": "社会性",
      "category": "needs",
      "percentile": 0.710476275913941,
      "significant": true
    },
    {
      "trait_id": "need_practicality",
      "name": "実用主義",
      "category": "needs",
      "percentile": 0.9942052654351621,
      "significant": true
    },
    {
      "trait_id": "need_self_expression",
      "name": "自己表現",
      "category": "needs",
      "percentile": 0.283590546642394,
      "significant": true
    },
    {
      "trait_id": "need_stability",
      "name": "安定性",
      "category": "needs",
      "percentile": 0.3676226427668019,
      "significant": true
    },
    {
      "trait_id": "need_structure",
      "name": "仕組",
      "category": "needs",
      "percentile": 0.03713112525416268,
      "significant": true
    }
  ],
  "values": [
    {
      "trait_id": "value_conservation",
      "name": "現状維持",
      "category": "values",
      "percentile": 0.1174651842220481,
      "significant": true
    },
    {
      "trait_id": "value_openness_to_change",
      "name": "変化許容性",
      "category": "values",
      "percentile": 0.8841545033162561,
      "significant": true
    },
    {
      "trait_id": "value_hedonism",
      "name": "快楽主義",
      "category": "values",
      "percentile": 0.05959893144723466,
      "significant": true
    },
    {
      "trait_id": "value_self_enhancement",
      "name": "自己増進",
      "category": "values",
      "percentile": 0.9674816463059281,
      "significant": true
    },
    {
      "trait_id": "value_self_transcendence",
      "name": "自己超越",
      "category": "values",
      "percentile": 0.08191121317174338,
      "significant": true
    }
  ],
  "warnings": []
}

percentileがその指標のポイントのようなもの。
正確には、IBMが学習する際に利用した人たちの中で、どのあたりに位置するかを表しているらしい。
下から何%ぐらいという感じだろう。

協働性が下から23%らしい。なんとなく当たっているような。

まとめ

公式リファレンスが充実していたこともあって、割とすんなり実装できた。
ぶっちゃけ、自分のツイートデータを使って性格推定するだけならば、
公式が用意しているグラフィカルなデモの方が100倍わかりやすい。

IBM Personality Insights

ただ、これだと自分のアカウントとしか紐付けできないので、勝手に人の性格を推定したい場合は実装するしかない。

あとは、今回取得したデータを何に活かすかって部分が重要になってくるのだろうけど、
思いつかないので気ままに考えます。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5