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)
出力
@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')
出力
「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()
# 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()
日経平均株価データを取得し、データ日付と終値だけの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()
# 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()
予めダウンロードしておいた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()
⑤学習データとテストデータに分割
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())
⑥特徴量の作成とラベリング
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()
結果は冒頭でも述べました通り、SGDClassifierの精度が一番高い結果となりました。そして、ある程度のドル円予測がTwitterや株価からできるということがわかりました。ただ、今回検証した期間が短かったので、もっと長期間のデータを用いて検証する必要がありそうですね。ありがとう御座いました!
この記事が気に入ったらサポートをしてみませんか?