見出し画像

Twitter感情分析を用いて、FXのドル円予測をPythonでやってみた

日経平均株価が上昇すれば円安、逆に下降すれば円高、みたいな相関性があると言われておりますが、トランプ大統領の発言なども株式マーケットに影響し、そしてそれが為替に影響するのではと思い今回検証してみることにしました。

自己紹介:テキサスの大学のCS学部を卒業→医療機器メーカーで約2年→アイデミー(AIプログラミングスクール)を受講

結果

先に結果から述べます。

--Method: LogisticRegression --
Cross validatin scores:0.5757575757575758

--Method: RandomForestClassifier --
Cross validatin scores:0.6060606060606061

--Method: SVC --
Cross validatin scores:0.5151515151515151

--Method: SGDClassifier --
Cross validatin scores:0.696969696969697

--Method: GaussianNB --
Cross validatin scores:0.5151515151515151

--Method: KNeighborsClassifier --
Cross validatin scores:0.3939393939393939

--Method: Perceptron --
Cross validatin scores:0.5757575757575758

簡単に言うとドル円の値が前日よりもプラスになるかマイナスになるかを予測したのですが、SGDClassifierが70%近くあり、一番精度がいいですね。

では、どのように分析を行ったのか説明していきます!

分析フロー

分析フローは以下の通りです。
① ツイートを感情分析
②日経平均株価データを取得
③日足のUSD/JPYデータを取得
④それぞれのデータを合体
⑤学習データとテストデータに分割
⑥特徴量の作成とラベリング
⑦予測モデルを構築し、予測精度を計測

① ツイートを感情分析

ツイート取得のコード

import tweepy
import csv

consumer_key = ""        # Consumer Keyを記載してください
consumer_secret = ""   # Consumer Secretを記載してください
access_key = ""            # Access Tokenをここに記載してください
access_secret = ""     # Accesss Token Secertをここに記載してください

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_key, access_secret)
api = tweepy.API(auth)

# ツイート取得
tweet_data = []

for tweet in tweepy.Cursor(api.user_timeline,screen_name = "@POTUS",exclude_replies = True).items():
   tweet_data.append([tweet.id,tweet.created_at,tweet.text.replace('\n','')])

print(tweet_data[0]) 
print(tweet_data[-1]) 
print(len(tweet_data)) 

# csv出力
with open('./6050_stock_price_prediction_data/tweets_Trump.csv', 'w',newline='',encoding='utf-8') as f:
   writer = csv.writer(f, lineterminator='\n')
   writer.writerow(["id","text","created_at"])
   writer.writerows(tweet_data)

出力

画像1

@realDonaldTrumpだとツイートの期間レンジが2020/7/16までと狭かったので、ツイートの取得先を@POTUSにしております。

感情分析のコード

import re
import pandas as pd
import numpy  as np
import matplotlib.pyplot as plt
from textblob import TextBlob

df_tweets = pd.read_csv('./6050_stock_price_prediction_data/tweets_Trump.csv', names=['id', 'date', 'text'], index_col='date')
df_tweets = df_tweets[['text']].sort_index(ascending=True)
print(df_tweets.tail(10))

# 最初の"RT @..."と"https..."を削除
tweet_list = []
for tweet in df_tweets['text']:
   word = tweet.split(':')
   if ' https' in word:
       tweet_list.append(None) 
   else:
       s = str(word[1:]).strip("[]")
       tweet_list.append(s) 
tweet_list = np.copy(tweet_list) 
df_tweets['text'] = tweet_list

# NANを排除、最後の行を削除
print() 
print(df_tweets.isnull().sum()) 
df_tweets = df_tweets.dropna()
df_tweets = df_tweets.drop(df_tweets.index[[-1]]) 
print(df_tweets.tail()) 

# ツイートのpolarityを入力
polarity_list = []
for tweet in df_tweets['text']:
   testimonial = TextBlob(tweet)
   polarity_list.append(testimonial.sentiment.polarity)
polarity_list = np.copy(polarity_list)
x_std = (polarity_list - polarity_list.mean()) / polarity_list.std()
df_tweets['pn'] = x_std

# プロット
df_tweets = df_tweets.drop('text', axis=0)
df_tweets.index = pd.to_datetime(df_tweets.index)
df_tweets =  df_tweets.resample('D', how='mean')
df_tweets = df_tweets.dropna() 
x = df_tweets.index
y = df_tweets.pn
plt.plot(x,y)
plt.grid(True)
plt.show() 
print(df_tweets.head())
print()
print(df_tweets.isnull().sum()) 

# CSVファイルとして出力
df_tweets.to_csv('./6050_stock_price_prediction_data/df_tweets_Trump.csv') 

出力

画像2

画像3

「RT @... 」と「https://... 」と最後の行は感情分析に必要ないので削除します。そして、TextBlobを使用してツイートのpn valueを取得し、dateと標準化されたpn値だけのDataframeを作ります。

②日経平均株価データを取得

import pandas as pd
from io import StringIO
import urllib

url = "https://indexes.nikkei.co.jp/nkave/historical/nikkei_stock_average_daily_jp.csv"
def read_csv(url):
   res = urllib.request.urlopen(url)
   res = res.read().decode('shift_jis') 
   df = pd.read_csv(StringIO(res)) 
   df = df.drop(df.shape[0]-1)
   return df

df = read_csv(url) 
# 出力
df.head() 

画像4

# indexを日付にする
df['データ日付'] = pd.to_datetime(df['データ日付'], format='%Y/%m/%d')
df = df.set_index('データ日付')

# カラムから'始値', '高値', '安値'を削除し、日付を古い順に並べる
df = df.drop(['始値', '高値', '安値'], axis=1) 
df = df.sort_index(ascending=True) 
df.head() 

画像5

日経平均株価データを取得し、データ日付と終値だけのDataframeを作成。

③日足のUSD/JPYデータを取得

import pandas as pd

df_usd_jpy = pd.read_csv('./6050_stock_price_prediction_data/01_USDJPY_D.csv', encoding='cp932')
df_usd_jpy.head()

画像6

# indexを日付にする
df_usd_jpy['日付'] = pd.to_datetime(df_usd_jpy['日付'], format='%Y/%m/%d')
df_usd_jpy = df_usd_jpy.set_index('日付')

# カラムから'始値', '高値', '安値', '通貨ペア'を削除し、日付が古い順に並べる
df_usd_jpy = df_usd_jpy.drop(['始値', '高値', '安値', '通貨ペア'], axis=1) 
df_usd_jpy = df_usd_jpy.sort_index(ascending=True) 
df_usd_jpy.columns = ['終値FX']
df_usd_jpy.head() 

画像7

予めダウンロードしておいたUSD/JPYデータを展開し、日付と終値FXだけのDataframeにする。

④それぞれのデータを合体

import pandas as pd

# dfとdf_tweetsの二つのテーブルを結合し、Nanを消去
df_tweets = pd.read_csv('./6050_stock_price_prediction_data/df_tweets_Trump.csv', index_col='date')
table = df_tweets.join(df, how='right')
table = table.join(df_usd_jpy, how='left').dropna() 

# table_fx.csvとして出力
table.to_csv("./6050_stock_price_prediction_data/table_fx.csv")
table.head()

画像8

⑤学習データとテストデータに分割

from sklearn.model_selection import train_test_split

X = table.values[:, 0:2] # pn value and close price 
y = table.values[:, 2] # close_fx price

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0, shuffle=False)


# df_trainというテーブルを作りそこにindexを日付、カラム名をpn値、終値、終値FXにしてdf_train_fx.csvという名前でdataフォルダ内に出力
df_train = pd.DataFrame({'pn':X_train[:,0], '終値':X_train[:,1], '終値FX': y_train}, columns=['pn', '終値', '終値FX'], 
                       index=table.index[:len(X_train)]) 
df_train.to_csv('./6050_stock_price_prediction_data/df_train_fx.csv')
print(df_train.head())

# テストデータについても同様にdf_testというテーブルを作り、df_test_fx.csvという名前でdataフォルダ内に出力
df_test = pd.DataFrame({'pn':X_test[:,0], '終値':X_test[:,1], '終値FX': y_test}, columns=['pn', '終値', '終値FX'],
                      index=table.index[len(X_train):])
df_test.to_csv('./6050_stock_price_prediction_data/df_test_fx.csv')
print(df_test.head()) 

画像9

⑥特徴量の作成とラベリング

rates_fd = open('./6050_stock_price_prediction_data/df_train_fx.csv', 'r')
rates_fd.readline()  
next(rates_fd)  

exchange_dates = []

pn_rates = []
pn_rates_diff = []

close_rates = []
close_rates_diff = []

close_fx_rates = []
close_fx_rates_diff = [] 

prev_pn = df_train['pn'][0]
prev_close = df_train['終値'][0]
prev_close_fx = df_train['終値FX'][0] 

for line in rates_fd:
   splited = line.split(",")
   time = splited[0]   # table.csvの1列目日付
   pn_val = float(splited[1])   # table.csvの2列目PN値
   close_val = float(splited[2])  # table.csvの3列目株価の終値
   close_fx_val = float(splited[3]) # FX close price 
   exchange_dates.append(time)  # 日付

   pn_rates.append(pn_val)
   pn_rates_diff.append(pn_val - prev_pn)   # PN値の変化

   close_rates.append(close_val)
   close_rates_diff.append(close_val - prev_close)   # 株価の変化
   
   close_fx_rates.append(close_fx_val)
   close_fx_rates_diff.append(close_fx_val - prev_close_fx) # FXの変化

   prev_pn = pn_val
   prev_close = close_val
   prev_close_fx = close_fx_val
   
rates_fd.close()
print(pn_rates_diff)
print(close_rates_diff)
print(close_fx_rates_diff) 

前日との変化量をリストとして格納

import numpy as np
INPUT_LEN = 3
data_len = len(pn_rates_diff)
tr_input_mat = []
tr_angle_mat = []

for i in range(INPUT_LEN, data_len):
   tmp_arr = []
   for j in range(INPUT_LEN):
       tmp_arr.append(close_rates_diff[i-INPUT_LEN+j])
       tmp_arr.append(close_fx_rates_diff[i-INPUT_LEN+j])
       tmp_arr.append(pn_rates_diff[i-INPUT_LEN+j])   
   tr_input_mat.append(tmp_arr)  # i日目の直近3日間の株価とネガポジの変化

   if close_fx_rates_diff[i] >= 0:  # i日目のFXの上下、プラスなら1、マイナスなら0
       tr_angle_mat.append(1)
   else:
       tr_angle_mat.append(0)   
train_feature_arr = np.array(tr_input_mat)
train_label_arr = np.array(tr_angle_mat)
   
print(train_feature_arr)
print(train_label_arr)
print(len(train_label_arr)) 

直近3日間の変化量(pn値、株価、ドル円)を特徴量とし、i日目のドル円の値がプラスなら1、マイナスなら0とラベリングします。

import numpy as np

rates_fd = open('./6050_stock_price_prediction_data/df_test_fx.csv', 'r')
rates_fd.readline()  
next(rates_fd)  

exchange_dates = []

pn_rates = []
pn_rates_diff = []

close_rates = []
close_rates_diff = []

close_fx_rates = []
close_fx_rates_diff = [] 

prev_pn = df_train['pn'][0]
prev_close = df_train['終値'][0]
prev_close_fx = df_train['終値FX'][0] 

for line in rates_fd:
   splited = line.split(",")
   time = splited[0]   # table.csvの1列目日付
   pn_val = float(splited[1])   # table.csvの2列目PN値
   close_val = float(splited[2])  # table.csvの3列目株価の終値
   close_fx_val = float(splited[3]) # FX close price 
   exchange_dates.append(time)  # 日付

   pn_rates.append(pn_val)
   pn_rates_diff.append(pn_val - prev_pn)   # PN値の変化

   close_rates.append(close_val)
   close_rates_diff.append(close_val - prev_close)   # 株価の変化
   
   close_fx_rates.append(close_fx_val)
   close_fx_rates_diff.append(close_fx_val - prev_close_fx) # FXの変化

   prev_pn = pn_val
   prev_close = close_val
   prev_close_fx = close_fx_val
   
rates_fd.close()

INPUT_LEN = 3
data_len = len(pn_rates_diff)
test_input_mat = []
test_angle_mat = []

for i in range(INPUT_LEN, data_len):
   test_arr = []
   for j in range(INPUT_LEN):
       test_arr.append(close_rates_diff[i-INPUT_LEN+j])
       test_arr.append(close_fx_rates_diff[i-INPUT_LEN+j])
       test_arr.append(pn_rates_diff[i-INPUT_LEN+j])   
   test_input_mat.append(test_arr)  # i日目の直近3日間の株価とネガポジの変化

   if close_fx_rates_diff[i] >= 0:  # i日目のFXの上下、プラスなら1、マイナスなら0
       test_angle_mat.append(1)
   else:
       test_angle_mat.append(0)    
test_feature_arr = np.array(test_input_mat)
test_label_arr = np.array(test_angle_mat)

同様にテストデータから特徴量を作成し、ラベリングを行います。

⑦予測モデルを構築し、予測精度を計測

# train_feature_arr, train_label_arr,test_feature_arr, test_label_arrを特徴量にして、予測モデルを構築し予測精度を計測
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.linear_model import SGDClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import Perceptron

for model in [LogisticRegression(), RandomForestClassifier(n_estimators=500, max_depth=10, random_state=0), SVC(),
             SGDClassifier(),GaussianNB(),KNeighborsClassifier(n_neighbors = 3),Perceptron()]:
   model.fit(train_feature_arr, train_label_arr)
   print("--Method:", model.__class__.__name__, "--")
   print("Cross validatin scores:{}".format(model.score(test_feature_arr, test_label_arr)))
   print() 

画像10

結果は冒頭でも述べました通り、SGDClassifierの精度が一番高い結果となりました。そして、ある程度のドル円予測がTwitterや株価からできるということがわかりました。ただ、今回検証した期間が短かったので、もっと長期間のデータを用いて検証する必要がありそうですね。ありがとう御座いました!


この記事が気に入ったらサポートをしてみませんか?