
deeplearningで、MNISTデータを使用しました。データを変えて、少し遊んでみたいと思います。
今回は、Pythonとyfinanceの学習がメインです。yfinaceから受信したデータを整形する基本を習得します。
実用性は無いですが、ファイル読み込み、基本統計値の算出を行います。株価と為替データをもとに、回帰直線で、株価の妥当性を分析しています。
データは、yfinance yahoo!Financeを利用させてもらいました。
登録不要ですぐ動くPythonライブラリーyfinanceが一番ハードルが低いです。
DNN(deeplearnig neural network)に学習させる前段としての、データの準備学習になっています。
※「分類問題(種類を当てる)」「回帰問題(値を当てる)」
回帰問題の準備になります。
■ yfinanceとは
yfinanceは、Yahoo! Finance(米国版)から金融データを取得するための、Pythonのオープンソースライブラリです。 APIキーの登録などが不要で、インストールするだけで手軽に過去の株価、為替レート、仮想通貨の価格、財務データなどを取得できるため、金融データ分析の学習や個人の研究用として世界中で広く利用されています。
■ 主な特徴
1.無料で手軽に使える
APIキーの発行や複雑な認証プロセスが不要です。
2.Pandasとの親和性が高い
取得したデータは自動的に pandas.DataFrame 形式で返されるため、そのまま matplotlib でグラフ化したり、移動平均を計算したりといった分析にスムーズに移行できます。
3.取得できるデータの種類が豊富
株価: 日経平均(^N225)、Apple(AAPL)などの始値・高値・安値・終値・出来高。
為替・暗号資産: ドル円(JPY=X)やビットコイン(BTC-USD)。
ファンダメンタルズ: 企業のバランスシート、キャッシュフロー、配当情報など。
■ 注意点(重要)
非公式ライブラリである: Yahoo! Financeが公式に提供しているAPIではなく、有志によって開発されているツール(スクレイピングベース)です。そのため、Yahoo側の仕様変更により突然使えなくなったり、取得データの形式が変わったりするリスクがあります。
商用利用・高頻度取引には向かない: データの遅延や取得制限(レートリミット)があるため、リアルタイム性が求められるシステムや商用アプリには向きません。あくまで学習・研究用として利用しましょう。
■ バージョンによる挙動の違い
最近のアップデート(v0.2系以降)により、データを取得した際のカラム構造が変更されています。特に複数の銘柄を一度に取得した場合、以前よりも厳格な MultiIndex(階層型インデックス) として返されるようになっています。 今回のコードでは、この階層構造を適切に処理するために data.xs や isinstance を使用して、バージョンや取得銘柄数に左右されずにデータを抽出できるように実装しています。
コード解説
1. ライブラリのインポートと初期設定
基本的なデータ分析ライブラリと、システム操作用のライブラリを読み込んでいます。
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
from pathlib import Path
import os, sys
# 日本語表示のズレを防ぐ設定
pd.set_option('display.unicode.east_asian_width', True)
・ポイント: display.unicode.east_asian_width を True にすることで、DataFrameをprintした際に日本語(全角文字)が含まれていても列がズレにくくなります。
2. データの「キャッシュ(保存済みファイル)」確認ロジック
APIへの過剰なアクセスを防ぎ、再実行を高速化するために、ローカルにCSVがあるかを確認しています。
# ファイル検索**********************************************
NoFileExist = False
# 現在のフォルダ('.')の中で、パターンに合うファイルを探す
files = list(Path('.').glob('market_comparison_*.csv'))
if files:
# 見つかったファイルのうち、一番新しいもの(または最初の一つ)を使う
# ファイル名に日付が入っているので、ソートすると最新が最後(-1)に来ます
targetFile = sorted(files)[-1]
print(f"✅ ファイルがみつかりました。{targetFile}")
NoFileExist = False
else:
print(f"✖ ファイルが見つかりません")
NoFileExist=True
if not NoFileExist:
print("input 'y' is reading from yahoo finance")
print("please input:")
initDataMode = input()
else:
initDataMode = 'y'
# データ取り込み*********************************************
if initDataMode!='y' :
#ローカルPCフォルダから読み込み
if targetFile.exists():
# index_col=0 で1列目(Date)をインデックスにし、parse_dates=True で日付型として認識させる
df_NJPY = pd.read_csv(targetFile,index_col=0, parse_dates=True)
print(f"ローカルファイル{targetFile}から取り込み完了----")
else:
print(f"ファイルが見つかりません")
sys.exit()
else:
#yahoo financeから読み込み
print("Yahooからデータを取得中...........")
#複数のtickerを一度に取得
data = yf.download(["^N225", "JPY=X"], period="1y")
#data.to_csv('sample.csv', encoding='utf-8-sig')
print("data:\n\r",data[:3])
#終値(Close)だけで保存
now = datetime.datetime.now().strftime('%Y%m%d_%H%M')
filename = f"market_comparison_{now}.csv"
# isinstance:data.columns が「MultiIndex(2階建て)」かどうかをチェック
if isinstance(data.columns, pd.MultiIndex):
#Pandasのxs(クロスセクション)メソッドは、
# マルチインデックス(階層型インデックス)を持つDataFrameやSeriesから、
# 特定のレベルの値に基づいてデータを抽出する機能です。
# locと異なり、内側の階層や、特定のレベル(level引数)の値を、
# 指定したカラム(axis引数)に基づいて直感的に抽出でき、
# デフォルトでは選択したレベルが結果から削除されます。
df_NJPY = data.xs('Close', axis=1, level=0)
else:
# 1階建てなら、普通に辞書のように取り出す
df_NJPY = data['Close']
#csvファイルの保存
df_NJPY.to_csv(filename, encoding='utf-8-sig')
print(f"ファイルを保存しました。{filename}")
print("取り込み完了----------------------")
Path('.').glob('market_comparison_*.csv') で、特定のパターンを持つファイルを検索しています。
sorted(files)[-1] でファイル名の日付をもとにソートし、最新のファイルを取得する工夫がされています。
ファイルがある場合のみ input() でユーザーに「再ダウンロードするか、既存ファイルを使うか」を尋ねる親切設計です。
3. Yahoo Financeからのデータ取得と整形(重要!)
# ... (yfinance取得部分) ...
data = yf.download(["^N225", "JPY=X"], period="1y")
# MultiIndex(2階建てカラム)の処理
if isinstance(data.columns, pd.MultiIndex):
# 'Close'列の階層だけを抜き出す
df_NJPY = data.xs('Close', axis=1, level=0)
else:
df_NJPY = data['Close']
yf.download は複数のティッカーを指定すると、カラムが (Price, Ticker) のようなマルチインデックス(階層構造)で返されることがあります(特に最新バージョンのyfinance)。
data.xs('Close', axis=1, level=0) を使うことで、Close(終値)のデータだけをスマートに抽出しています。これは loc を使うよりも直感的で可読性が高い方法です。
4. 統計計算と回帰分析(Numpy vs Pandas)
#NumpyとPandasの値を比較する。
#共分散covariance
print("----- numpy vs pandasDataFrame ----")
N = len(df_NJPY[dfName[0]]) #総数
nx = df_NJPY[dfName[0]] #USD/JPY
ny = df_NJPY[dfName[1]] #n225
nMx = np.mean(nx) #USD/JPY 平均
nSx = np.std(nx) #USD/JPY 標準偏差
nMy = np.mean(ny) #n225 平均
nSy = np.std(ny) #n225 標準偏差
nSxy = np.dot((nx-nMx),(ny-nMx)) / N #numpy USD/JPY,n255共分散
dfcov = df_NJPY[[dfName[0],dfName[1]]].cov() #pandas covariance
print(f"numpy 共分散:{nSxy:.5f}")
print(f"DF 共分散:{dfcov.iloc[0,1]:.5f}")
#相関係数 correlation coefficient
rxy = nSxy/(nSx*nSy)
print(f"numpy 相関係数:{rxy:.5f}")
print(f"DF 相関係数:{corrMatrix.iloc[0,1]:.5f}")
#回帰直線
x = df_NJPY[dfName[0]] # USD/JPY
y = df_NJPY[dfName[1]] # n225
# np.polyfit(x, y, 1) -> 1は「1次関数」の意味
# 戻り値: a (傾き), b (切片)
a, b = np.polyfit(x, y, 1)
# 分析結果 *********************************************************
print("-"*30)
print(" [分析結果] ")
print(f"回帰式: 日経平均 = {a:.2f} × ドル円 + {b:.2f}")
print(f"感応度: ドル円が1円動くと、日経平均は約{a:.0f}円動きます")
#現在との乖離判定
current_usd = x.iloc[-1] #直近のドル円
current_n225 = y.iloc[-1] #直近の日経平均
theoretical_n225 = a * current_usd + b #理論値を計算
diff = current_n225 - theoretical_n225 #乖離幅
print(f"現在のドル円: {current_usd:.2f} 円")
print(f"理論株価: {theoretical_n225:.0f} 円")
print(f"実際株価: {current_n225:.0f} 円")
print(f"乖離: {diff:+.0f} 円")
Numpy vs Pandas: 共分散や相関係数を、Numpyの数式(np.dot等)とPandasのメソッド(.corr等)の両方で計算し、結果が一致することを確認しています。学習用として非常に有益なプロセスとして、比較しました。
回帰分析(np.polyfit): 「ドル円が1円動くと日経平均が何円動くか(傾き a)」を算出しています。
割安・割高判定: 現在のドル円レートから「理論上の日経平均」を計算し、実勢価格との乖離(Diff)を見ることで、現在の市場が過熱しているかどうかの目安を出しています。
5. データの可視化(Matplotlib & Seaborn)
3つのグラフを1つの画面(Figure)にまとめて表示しています。
# ... (グラフ描画部分) ...
fig = plt.figure(figsize=(18,5))
# 1. 折れ線グラフ(2軸)
ax1.plot(...) # 日経平均
ax2 = ax1.twinx() # 右軸を作成
ax2.plot(...) # ドル円
# 2. ヒートマップ(相関係数)
sns.heatmap(corrMatrix, annot=True, cmap='coolwarm', ...)
# 3. 散布図+回帰直線
sns.regplot(data=df_NJPY, ...)
2軸グラフ (twinx): 単位の違う「株価(数万円)」と「為替(百数十円)」を重ねて表示するために、右側のY軸を追加しています。
Seabornの活用: sns.heatmap で相関の強さを色で表現し、sns.regplot で散布図の上に自動的に回帰直線を引いています。これにより、視覚的に相関関係を一目で理解できます。
共分散の値:numpyと、pandasのデータにすこし、違いがあります。自由度が、numpyは"n", pdは"n-1"です。
pandasのデータフレームは、標本データを前提にしています。その違いです。
日経vsUSD/JPY 簡易分析
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
from pathlib import Path
import os, sys
pd.set_option('display.unicode.east_asian_width', True)
# ファイル検索**********************************************
NoFileExist = False
# 現在のフォルダ('.')の中で、パターンに合うファイルを探す
files = list(Path('.').glob('market_comparison_*.csv'))
if files:
# 見つかったファイルのうち、一番新しいもの(または最初の一つ)を使う
# ファイル名に日付が入っているので、ソートすると最新が最後(-1)に来ます
targetFile = sorted(files)[-1]
print(f"✅ ファイルがみつかりました。{targetFile}")
NoFileExist = False
else:
print(f"✖ ファイルが見つかりません")
NoFileExist=True
if not NoFileExist:
print("input 'y' is reading from yahoo finance")
print("please input:")
initDataMode = input()
else:
initDataMode = 'y'
# データ取り込み*********************************************
if initDataMode!='y' :
#ローカルPCフォルダから読み込み
if targetFile.exists():
# index_col=0 で1列目(Date)をインデックスにし、parse_dates=True で日付型として認識させる
df_NJPY = pd.read_csv(targetFile,index_col=0, parse_dates=True)
print(f"ローカルファイル{targetFile}から取り込み完了----")
else:
print(f"ファイルが見つかりません")
sys.exit()
else:
#yahoo financeから読み込み
print("Yahooからデータを取得中...........")
#複数のtickerを一度に取得
data = yf.download(["^N225", "JPY=X"], period="1y")
#data.to_csv('sample.csv', encoding='utf-8-sig')
print("data:\n\r",data[:3])
#終値(Close)だけで保存
now = datetime.datetime.now().strftime('%Y%m%d_%H%M')
filename = f"market_comparison_{now}.csv"
# isinstance:data.columns が「MultiIndex(2階建て)」かどうかをチェック
if isinstance(data.columns, pd.MultiIndex):
#Pandasのxs(クロスセクション)メソッドは、
# マルチインデックス(階層型インデックス)を持つDataFrameやSeriesから、
# 特定のレベルの値に基づいてデータを抽出する機能です。
# locと異なり、内側の階層や、特定のレベル(level引数)の値を、
# 指定したカラム(axis引数)に基づいて直感的に抽出でき、
# デフォルトでは選択したレベルが結果から削除されます。
df_NJPY = data.xs('Close', axis=1, level=0)
else:
# 1階建てなら、普通に辞書のように取り出す
df_NJPY = data['Close']
#csvファイルの保存
df_NJPY.to_csv(filename, encoding='utf-8-sig')
print(f"ファイルを保存しました。{filename}")
print("取り込み完了----------------------")
# データクレンジング******************************************
#欠損値を含む行を削除。
df_NJPYf = df_NJPY.dropna().copy()
df_NJPY = df_NJPYf.copy()
#DateFrame変数名の取得
print("DataFrame Index:",df_NJPY.columns.tolist())
dfName = df_NJPY.columns.tolist()
#平均値、標準偏差の算出
jpyMean = df_NJPY[dfName[0]].mean()
jpyStd = df_NJPY[dfName[0]].std()
N225Mean = df_NJPY[dfName[1]].mean()
N225Std = df_NJPY[dfName[1]].std()
print("--- 平均、標準偏差---")
print(f"N225 mean:{N225Mean:.3f} std:{N225Std:.3f}")
print(f"JPY mean:{jpyMean:.3f} std:{jpyStd:.3f}")
#相関係数
corrMatrix = df_NJPY[[dfName[0],dfName[1]]].corr()
print(corrMatrix)
#Numpy vs Pandas.Dataframe************************************
#NumpyとPandasの値を比較する。
#共分散covariance
print("----- numpy vs pandasDataFrame ----")
N = len(df_NJPY[dfName[0]]) #総数
nx = df_NJPY[dfName[0]] #USD/JPY
ny = df_NJPY[dfName[1]] #n225
nMx = np.mean(nx) #USD/JPY 平均
nSx = np.std(nx) #USD/JPY 標準偏差
nMy = np.mean(ny) #n225 平均
nSy = np.std(ny) #n225 標準偏差
nSxy = np.dot((nx-nMx),(ny-nMx)) / N #numpy USD/JPY,n255共分散
dfcov = df_NJPY[[dfName[0],dfName[1]]].cov() #pandas covariance
print(f"numpy 共分散:{nSxy:.5f}")
print(f"DF 共分散:{dfcov.iloc[0,1]:.5f}")
#相関係数 correlation coefficient
rxy = nSxy/(nSx*nSy)
print(f"numpy 相関係数:{rxy:.5f}")
print(f"DF 相関係数:{corrMatrix.iloc[0,1]:.5f}")
#回帰直線
x = df_NJPY[dfName[0]] # USD/JPY
y = df_NJPY[dfName[1]] # n225
# np.polyfit(x, y, 1) -> 1は「1次関数」の意味
# 戻り値: a (傾き), b (切片)
a, b = np.polyfit(x, y, 1)
# 分析結果 *********************************************************
print("-"*30)
print(" [分析結果] ")
print(f"回帰式: 日経平均 = {a:.2f} × ドル円 + {b:.2f}")
print(f"感応度: ドル円が1円動くと、日経平均は約{a:.0f}円動きます")
#現在との乖離判定
current_usd = x.iloc[-1] #直近のドル円
current_n225 = y.iloc[-1] #直近の日経平均
theoretical_n225 = a * current_usd + b #理論値を計算
diff = current_n225 - theoretical_n225 #乖離幅
print(f"現在のドル円: {current_usd:.2f} 円")
print(f"理論株価: {theoretical_n225:.0f} 円")
print(f"実際株価: {current_n225:.0f} 円")
print(f"乖離: {diff:+.0f} 円")
if diff > 0:
print("判定: 割高です(理論値より上に浮いています)")
else:
print("判定: 割安です(理論値より下に沈んでいます)")
print("-" * 30)
#グラフ作成------------------------------------------------------------------------
#fig,ax1 = plt.subplots(figsize=(12,6))
fig = plt.figure(figsize=(18,5))
ax1 = fig.add_subplot(1,3,1)
#左軸:日経平均
ax1.plot(df_NJPY.index, df_NJPY[dfName[1]], color='royalblue', label='Nikkei 225')
ax1.set_ylabel('Nikkei 225(JPY)', color='royalblue')
ax1.tick_params(axis='y', labelcolor='royalblue')
ax1.set_title("Nikkei 225 vs USD/JPY (1 Year)")
ax1.grid(True, linestyle='--')
#右軸:ドル円
ax2 = ax1.twinx()
ax2.plot(df_NJPY.index, df_NJPY[dfName[0]], color='orange', label='USD/JPY')
ax2.set_ylabel('USD/JPY', color='orange')
ax2.tick_params(axis='y', labelcolor='orange')
#相関係数
ax3 = fig.add_subplot(1,3,2)
ax3.set_box_aspect(1)
ax3.set_title('correlation coefficient')
ax3.set_xlabel('N225')
ax3.set_ylabel('USD/JPY')
sns.set_theme(style='whitegrid')
sns.heatmap(
corrMatrix,
annot=True,
cmap = 'coolwarm',
vmin=-1,vmax=1,
ax = ax3,
# cbar_kws の shrink で長さを調整(0.8なら80%のサイズに)
cbar_kws={"shrink": 0.6}
)
#散布図
ax4 = fig.add_subplot(1,3,3)
ax4.set_box_aspect(1)
ax4.set_title('Nikkei vs USD/JPY')
ax4.set_xlabel(dfName[0])
ax4.set_ylabel(dfName[1])
"""sns.scatterplot(
data = df_NJPY,
x = dfName[0],
y = dfName[1],
s = 100,
color = 'blue',
ax = ax4
)"""
sns.regplot(
data = df_NJPY,
x = dfName[0],
y = dfName[1],
scatter_kws={'s':33, 'color':'blue'},
line_kws = {'color':'red'},
ax = ax4
)
plt.tight_layout()
plt.show()

