Aidemy Tech Blog

機械学習・ディープラーニング関連技術の活用事例や実装方法をまとめる、株式会社アイデミーの技術ブログです。

Twitterからデータセットを作るfor機械学習

前置き

さて、皆さんは機械学習で重要なものって何があると思いますか?

実行するコードの質や、その中で使うパッケージ、実行するマシンのスペックも大きく結果に影響してくるでしょう。

しかしそれらすべてを手に入れられる最高のものを用意したとしても、やりたいことに関するデータセットがなければ何もできないのです!

それでは機械学習で使うデータをどうやって手に入れればいいのでしょうか?

まず第一に様々な企業や研究者などがデータセットを公開してくれているものがあります。これらは機械学習のために作られたものなので、扱いやすく信頼性もある程度高いと思います。しかし公開されているデータの中に自分が使いたいものがあるとは限りません。もしほしいデータがなかったらどうすればいいのか。

f:id:sack_kazu:20170730215245p:plain

自分で作ればいいのです。

そもそも近年ディープラーニングが隆盛してきた理由はマシン性能の向上と、インターネットの普及による大量のデータ入手が可能になったからでした。

インターネット上には膨大な量のさまざまな情報があふれており、これを活用しない手はありません。

さて今回どんなデータセットを作るのかというと、電車の遅延と気象条件の組み合わせた物にしようと思います。
気象情報を説明変数にして、電車が遅延するかを目的変数にするイメージです。

気象情報のデータは気象庁から入手できるのですが、電車の遅延情報をまとめたデータは公開されていないようです。(企業主催のコンペなどで特別に公開されたりはしていたようですが。)

というわけで今回は鉄道会社の公式ツイッターからデータを作ることにします。


twitter.com

今回東急電鉄さんのツイートを利用させてもらいます。

環境について

使用言語
・python3系
使用パッケージ(インストールが必要なもの)
・pandas:DataFrameを使うため
・requests_oauthlib:ツイッターの認証のため

本題

気象データ

まず、気象庁から過去の気象情報をダウンロードします。
 
気象庁|過去の気象データ・ダウンロード

地点は東京、時別値で項目は降水量、現地気圧、相対湿度を選んでみました。

ここが厄介なのですが、ここで一度にダウンロードできるデータ量が制限されており、この三つの項目を選ぶと5か月分くらいしか取得できません。なので期間をずらして必要な分だけ取得しましょう。今回は2016/4/30~2017/7/28(3回分)取得してみました。


まずは気象データのほうを成型していきます。
どんなデータ形式になってるかとりあえず見てみましょう。

import pandas as pd
import codecs

with codecs.open("data0.csv", "r", "Shift-JIS", "ignore") as file:
df =pd.read_table(file, delimiter=",")

df

f:id:sack_kazu:20170730210211p:plain

列の名前がUnnamed:1…となっているのでこれを使って要らない列を削除していきます。降水に関しては量が0でも、現象無し情報が0の行があるので、現象無し情報の方を降水の情報として用います。湿度や気圧に関しては品質情報や均質番号はいらないので消します。

さらに列名がわかりづらいので上4行を消して新しい列名を付けます。

これらの作業を各ファイルから読み取ったDataFrameに行い、最後に一つのDataFrameにまとめます。

最後に日時のデータを参照しやすいように単純な数字に変換しておきます。

これで気象情報の方は完成です。

import codecs

def YmdHMS2(d_time):#日時を数字の列に直す関数
    n_time = time.strptime(d_time, '%Y/%m/%d %H:%M:%S')
    return int(time.strftime("%Y%m%d%H%M%S", n_time))

a_df = []
list = [1,3,4,6,7,9,10]#要らない列番号

for i in range(3):#三個ファイルを開き、それぞれの列を整理する
    with codecs.open("data{}.csv".format(i), "r", "Shift-JIS", "ignore") as file:
        b_df =pd.read_table(file, delimiter=",")
        
    b_df = b_df.drop([0,1,2,3])
    for i in list:#要らない列を削除
        b_df = b_df.drop(['Unnamed: {}'.format(i)],axis=1)
    b_df.columns = ['time','rain','humidity','puressur']
    b_df = b_df.reset_index(drop=True)

    a_df.append(b_df)

df = pd.concat([a_df[2],a_df[1],a_df[0]], ignore_index=True)#3つのDataFrameを結合
for i in df.index:
    df.time[i] = YmdHMS2(df.time[i])
df

f:id:sack_kazu:20170730210642p:plain 

遅延情報の取得

次にツイッターから遅延情報を取得していきましょう。
ツイッターからデータを取得する方法については以下のサイトを主に参考にしました。

TwitterAPI でツイートを大量に取得。サーバー側エラーも考慮(pythonで) | コード7区

指定の路線が遅延したかとその時間のデータを作ります。
アカウントのタイムラインを時系列順に取得し、特定の路線名と「遅れ」の文字が含まれていたツイートの時間に遅延があったと判断します。

# -*- coding: utf-8 -*-

from requests_oauthlib import OAuth1Session
import json
import datetime, time, sys, calendar
import pandas as pd

CK = '##############################'                             # Consumer Key 自分のものを入力
CS = '##################################################'         # Consumer Secret
AT = '##########################################################' # Access Token
AS = '##################################################'         # Accesss Token Secert

session = OAuth1Session(CK, CS, AT, AS)
max_id = 891290216417210368#取得を始めるツイートのid。ツイートへのリンクの末尾の長い数字
res_text = []

N = 40 # Nx100個のツイートを取得(50くらいからエラーになる?仕様は調べてません)
line = "東横線" # 調べる路線
 
url = 'https://api.twitter.com/1.1/statuses/user_timeline.json'

def YmdHMS(created_at):#分以下の情報を切り捨てて数字の列に変換する関数
    time_utc = time.strptime(created_at, '%a %b %d %H:%M:%S +0000 %Y')
    unix_time = calendar.timegm(time_utc)
    time_local = time.localtime(unix_time)
    return int(time.strftime("%Y%m%d%H00", time_local))

for i in range(N):
    res = session.get(url, params = {'user_id':1199983754, 'count':100, 'max_id':max_id})
    res_text_semi = json.loads(res.text) 
  
    if res.status_code != 200:# ステータスコード確認
        print ("Twitter API Error: %d" % res.status_code)
        sys.exit(1)
    
    for tweet in res_text_semi:#今回取得した最古のツイートのid取得
        if tweet['id'] < max_id:
            max_id = tweet['id']

    res_text.extend(res_text_semi)


df1 = pd.DataFrame(columns=["time","delay"])

    
for tweet in reversed(res_text):
    if tweet['text'].find('遅れ') != -1 and tweet['text'].find(line) != -1:#遅れていたらdelayを1にする。
        delay = 1
    else:
        delay = 0
        
    t_df = pd.DataFrame([[YmdHMS(tweet['created_at']),delay]],columns=["time","delay"])
    df1 = df1.append(t_df,ignore_index = True)


df1 = df1.drop_duplicates(['time'])#時間が重複している行を削除
df1

f:id:sack_kazu:20170802004949p:plain
最後に気象データと遅延データを組み合わせます。
気象データは毎時の値がありますが、遅延データはそうではないので、気象データに遅延データをくっつけるようにします。
そしてその間の値は、一度遅延したら次に遅れのないツイートが来るまで遅延していたものとします。
そして最後にcsvファイルとして書き出します。

merged = pd.merge(df,df1,on='time',how='left')#時間をキーに気象データを残す形で結合
flag = False #遅延状態かのフラグ

for i in merged.index:
    if merged.delay[i] == 1:
        flag = True
    elif merged.delay[i] == 0:
        flag = False
    else:
        if flag == True:
            merged.delay[i] = 1
        else:
            merged.delay[i] = 0            

merged.to_csv('delay_data.csv')

f:id:sack_kazu:20170802004920p:plain
こうして無事電車の遅延情報と気象情報を合わせたデータセットができました。
次回はこのデータセットを使って実際に機械学習をやる予定です。