JSON File
銘柄:Sector、Brand
wikipediaで東京証券取引所プライム市場上場企業一覧を取得。
別サイトで33業種区分(Sector)の英訳も取得。
Excelを利用して取得した表からSectorのJSONファイルを作成。
VSCodeで読み込むと容易に整形できる。
[
{
"ctgid": "1",
"name": "ガラス・土石製品",
"english": "Glass and Ceramics Products"
},
{
"ctgid": "2",
"name": "ゴム製品",
"english": "Rubber Products"
},
…
{
"ctgid": "33",
"name": "陸運業",
"english": "Land Transportation"
}
]
同様に、銘柄(Brand)のJSONファイルを作成。(正規化はしない)
[
{
"id": "1301",
"company": "極洋",
"category": "水産・農林業",
"ctgid": "21"
},
{
"id": "1332",
"company": "ニッスイ",
"category": "水産・農林業",
"ctgid": "21"
},
{
"id": "1333",
"company": "Umios",
"category": "水産・農林業",
"ctgid": "21"
},
…
{
"id": "9997",
"company": "ベルーナ",
"category": "小売業",
"ctgid": "17"
}
]
農作物獣害
農林水産省の農作物被害状況のデータをJSONファイルに加工。
[
{
"animal": "スズメ",
"damage": [
{
"name": " イ ネ",
"value": 10116
},
{
"name": "ムギ類",
"value": 220
},
{
"name": "マメ類",
"value": 25
},
{
"name": "雑 穀",
"value": 157
},
{
"name": "果 樹",
"value": 4892
},
{
"name": "飼料作物",
"value": 6
},
{
"name": "野 菜",
"value": 695
},
{
"name": "いも類",
"value": 1
},
{
"name": "工芸作物",
"value": 28
},
{
"name": "その他",
"value": 16
}
]
},
{
"animal": "カラス",
"damage": [
{
"name": " イ ネ",
"value": 6628
},
…
{
"name": "工芸作物",
"value": 4512
},
{
"name": "その他",
"value": 1925
}
]
}
]
JSON Read
view
import json でjsonのファイルが扱える。(json.load)
import json
import os
------------------------------------------------------------------------------------------------------------------------
class ChartsCategoryView(View):
def get(self,request):
# JSONファイルのパスを指定
json_path = os.path.join(settings.BASE_DIR, 'json/category.json')
# 読み込みモード r で開く
with open(json_path, 'r', encoding='utf-8') as f:
json_data = json.load(f)
# Templateに渡す
context = {
'data': json_data,
}
return render(request, 'charts/category.html', context)
JSON Write
view
チャートを書く前にidを元に対象のデータを辞書のリストで取得。
json_path = os.path.join(settings.BASE_DIR, 'json/company.json')
# 読み込みモードで開く r
with open(json_path, 'r', encoding='utf-8') as f:
json_data = json.load(f)
# 辞書のidが引数のidと同じものを辞書のList(Company)として取得
company = [r for r in json_data if r['id'] == id]
履歴のJSONファイルを読み込んで追加するが、重複しないように辞書のid部分をKeyとする辞書を作成する。
#companyもLISTなので最初の1件を記録の配列の要素として追加
history_data.append(company[0])
#記録の配列内の辞書のidをKeyとして辞書自体をValueとする辞書を作成(重複が省かれる)
unique_dict = {item["id"]: item for item in history_data}
# 重複を省いた辞書のValueをListにする。(要素は辞書で元の形式)
result = list(unique_dict.values())
作成した辞書のLISTをJSONファイルを書き込みモード w で開いてdump出力する。
# 書き込みモードで開く w
with open(write_path, "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=4)
Line Chart
作成方法は以前Blogにも書いた。今回は通常のLine Chartは作ってないけどメモだけ。
matplotlib をimportして作成するがXServerではindex.cgiを工夫しないとエラーになる。
import os
os.environ['OPENBLAS_NUM_THREADS'] = "1"
項目とデータのListをそれぞれ用意してPlotするだけ。
マルチラインだと、タイトル:t_list, データ1:a_list, データ2:b_listとすると
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
------------------------------------------------------------------------------------------------------------------------
plt.plot(t_list, a_list, marker ='o', color="darkgreen")
plt.plot(t_list, b_list, marker ='x', color="black")
ARIMA
Time Seriesから予測を行うARIMA(SARIMA)を試す。
ticker = 銘柄コード + T でYahooからデータをデータフレームとして取得する。
import yfinance as yf
import datetime
from dateutil.relativedelta import relativedelta
import pandas as pd
------------------------------------------------------------------------------------------------------------------------
# 今日
today = datetime.date.today()
# 開始日
past120 = today + relativedelta(days=-120)
# 検証開始日
past10=today + relativedelta(days=-10)
# データフレーム取得
df = yf.download(ticker, start=past120, end=today)
ARIMAでは p,d,q および P,D,Qのパラメータを決める必要がある。
d,Dを1固定とし、p,q,P,Qを0~2で変動して最小のBICの組み合わせを採用する。
import statsmodels.api as sm
from statsmodels.tsa.statespace.sarimax import SARIMAX
import matplotlib_fontja
import numpy as np
------------------------------------------------------------------------------------------------------------------------
best_params_ab = selectparameter(df['Close'], 5)
------------------------------------------------------------------------------------------------------------------------
def selectparameter(DATA, s):
dfparm = DATA.reset_index(drop=True)
p = d = q = range(0, 2)
pdq = list(itertools.product(p, d, q))
seasonal_pdq = [(x[0], x[1], x[2], s) for x in list(itertools.product(p, d, q))]
parameters = []
parametersaic = []
BICs = np.array([])
AICs = np.array([])
for param in pdq:
if(param[1] == 1):
for param_seasonal in seasonal_pdq:
if(param_seasonal[1] == 1):
try:
mod = sm.tsa.statespace.SARIMAX(dfparm,
order=param,
seasonal_order=param_seasonal)
results = mod.fit(maxiter=200)
parameters.append([param, param_seasonal, results.bic])
BICs = np.append(BICs, results.bic)
parametersaic.append([param, param_seasonal, results.aic])
AICs = np.append(AICs, results.aic)
except:
print("error")
continue
return {'BIC':parameters[np.argmin(BICs)],'AIC':parametersaic[np.argmin(AICs)]}
AICも取得してみたが、採用したのはBICの最小の組み合わせ。
best_params = best_params_ab['BIC']
bp=best_params[0][0]
bd=best_params[0][1]
bq=best_params[0][2]
bsp=best_params[1][0]
bsd=best_params[1][1]
bsq=best_params[1][2]
#
p, d, q = bp, bd, bq
P, D, Q, s = bsp, bsd, bsq, 5
------------------------------------------------------------------------------------------------------------------------
real_price = df['Close']
------------------------------------------------------------------------------------------------------------------------
real_price = real_price.reset_index(drop=True)
model = SARIMAX(real_price, order=(p, d, q), seasonal_order=(P, D, Q, s))
result = model.fit()
------------------------------------------------------------------------------------------------------------------------
# 3. 将来の予測
forecast_steps = 10
prediction = result.get_forecast(steps=forecast_steps)
predicted_mean = prediction.predicted_mean
------------------------------------------------------------------------------------------------------------------------
# 4. 結果のプロット
plt.figure(figsize=(20,9))
plt.plot(realidx, real_price, color='blue',label='Actual Price')
newindex=pd.date_range(start=endday, periods=forecast_steps + 1)[1:]
plt.plot(pd.date_range(start=endday, periods=forecast_steps + 1)[1:], predicted_mean, color='red', label='Forecast')
Bar Chart
積み上げ棒グラフを作成する。
要素の数だけPLOT(plt.bar)を繰り返せばよい。
ただし、2回目以降はそれまでの高さをbottomに指定して上に乗せる感じで描く。
データのListをListにしてチャート描画に引数として渡す。
xmlist=[]
ymlist=[]
is_first = True
# 動物別Loop
for j in json_data:
tmplist=[]
# 穀物別Loop
for m in j['damage']:
# 動物の穀物別被害のList
tmplist.append(m['value'])
# X軸
if is_first:
ymlist.append(m['name'])
# DataはListのList
xmlist.append(tmplist)
is_first = False
create_bar(xmlist, ymlist)
描画する関数では、データのListを展開して都度Plotする。
bottomを求めるのにnp.arrayでそれまでの要素の値を蓄積する。
def create_bar(x_list,r_list):
plt.cla()
cnt=0
# DataのLoop
for l in x_list:
# 初回はbottom指定ない
if cnt == 0:
plt.bar(r_list,l)
else:
# bottom初期化
bottom_for_next = 0
# cnt内(描画済みのData)Loopしてnp.arrayで配列を蓄積
for i in range(cnt):
bottom_for_next=bottom_for_next + np.array(x_list[i])
# bottomを指定してPlot
plt.bar(r_list,l, bottom = bottom_for_next)
cnt +=1
…
今回はX軸の表示に問題ないがスペースが狭いときには縦書も考慮する。
tmpname = ""
for char in p['name']:
tmpname=tmpname + char+"\n"
一文字ずつ改行を入れるが、Pythonでは文字列もLoopできる。