よっしーの私的空間

機械学習を中心に興味のあることについて更新します

過去記事一覧

過去の記事についてまとめます。

1.画像データ分析

① 画像分析モデルの紹介

画像分析モデルの実装方法について。モデルの概要も記載しています。

② モデルの比較

画像分類モデルを試してみた結果。

③ 前処理
④ XAI(説明可能AI) 

2.テーブルデー

① 前処理
② XAI(説明可能AI) 

 3.株価予測

① LightGBMを使用した株価分析
② 前処理

 3.競馬予測

① データ入手
② 過去戦績に基づくレーティング

4.分析環境の構築

5.再現性確保

6.マルチGPU学習

7.エラー対処

Windows環境のPythonでTalibのインストール

Windows環境のPythonでtalibのインストールに失敗したので、その解決方法をメモっておきます。

1.実行コマンドとエラー内容

実行コマンド:

$ pip install ta-lib

エラー内容:

ERROR: Failed building wheel for ta-lib
Failed to build ta-lib
ERROR: Could not build wheels for ta-lib, which is required to install pyproject.toml-based projects

2.解決方法

Pythonパッケージのダウンロード

Ta-libのリリースページからパッケージのダウンロードする。ダウンロードするのはPythonバージョン、OSが32bitか64bitか、CPUがARMかAMDかで選ぶ。Python 3.12 (64-bit)、AMDの場合はta_lib-0.6.4-cp312-cp312-win_amd64.whlをダウンロードすれば良い。AMDかARMかはコマンドプロンプトでecho %PROCESSOR_ARCHITECTURE%を実行すれば確認できる。

github.com

3.インストール

コマンドプロンプトでパッケージを格納したパスまで移動して以下のコマンドを実行する。

$ py.exe -3.12 -m pip install ta_lib-0.6.4-cp312-cp312-win_amd64.whl

Plotlyで始めるインタラクティブなデータ可視化|Pandasと連携してグラフをもっと自由に!

Pythonでデータをグラフ化するとき、よく使われるのが matplotlibseaborn ですが、よりリッチでインタラクティブなグラフを作りたいなら、Plotly の出番です!

マウス操作でグラフのズーム・ホバー・保存などができるので、ビジネス資料やWebアプリにも最適です。


Plotlyとは?

Plotly は、Webベースのインタラクティブグラフを簡単に作成できるPythonライブラリです。以下のような特徴があります:

  • ズーム・ホバー・凡例のオンオフなどが可能なインタラクティブUI
  • HTMLファイルとして保存・共有ができる
  • Dashと組み合わせればWebアプリも作れる
  • Pandasのデータフレームと相性が良い

1. インストール方法

pip install plotly

必要に応じて pandas も準備しておきましょう。


2. 基本的な使い方:折れ線グラフ

まずはシンプルな折れ線グラフから。

import pandas as pd
import plotly.express as px

# サンプルデータ
df = pd.DataFrame({
    "月": ["1月", "2月", "3月", "4月", "5月"],
    "売上": [120, 150, 170, 130, 190]
})

fig = px.line(df, x="月", y="売上", title="月別売上推移")
fig.show()

fig.show() でブラウザにグラフが表示されます。


3. 棒グラフ:カテゴリ別の可視化

fig = px.bar(df, x="月", y="売上", title="月別売上(棒グラフ)")
fig.show()

棒グラフも1行でOK。px.bar() に変えるだけです。


4. 散布図:2軸で相関を可視化

df2 = pd.DataFrame({
    "身長": [160, 170, 175, 180, 165],
    "体重": [55, 65, 68, 75, 60],
    "性別": ["男", "女", "女", "男", "女"]
})

fig = px.scatter(df2, x="身長", y="体重", color="性別", title="身長と体重の相関")
fig.show()

color 引数でカテゴリごとに色分けが可能です。


5. 円グラフ:割合の可視化

df3 = pd.DataFrame({
    "カテゴリ": ["A", "B", "C", "D"],
    "割合": [40, 25, 20, 15]
})

fig = px.pie(df3, names="カテゴリ", values="割合", title="カテゴリ別の構成比")
fig.show()

ホバーで各カテゴリの割合が表示されるのが魅力。


6. データフレームと連携した応用

Pandasで集計したデータをそのままPlotlyに渡すのが王道です:

# CSVを読み込んで性別ごとの平均年齢をグラフに
df = pd.read_csv("sample.csv")
mean_age = df.groupby("性別")["年齢"].mean().reset_index()

fig = px.bar(mean_age, x="性別", y="年齢", title="性別ごとの平均年齢")
fig.show()

Pandasで集計 → Plotlyで可視化、という流れは非常に実用的です。


7. グラフのカスタマイズ例

fig.update_layout(
    title_font_size=24,
    xaxis_title="月",
    yaxis_title="売上額(万円)",
    template="plotly_white"
)
  • template="plotly_dark" にすればダークテーマにもできます。
  • hover_datamarkers=True など細かいオプションも豊富。

8. グラフの保存

静的画像(PNG)として保存するには kaleido パッケージが必要です:

pip install -U kaleido

保存例:

fig.write_image("graph.png")

HTMLとして保存する場合:

fig.write_html("graph.html")

おわりに

Plotlyは、「見せる」グラフ を簡単に作成できる素晴らしいライブラリです。Pandasと組み合わせれば、簡単にインタラクティブダッシュボードが作れます。

TabPFNはなぜ“学習不要”なのか?

— Prior-trained Transformerによるベイズ最適分類器の仕組みを解説

**Tabularデータにおける機械学習の“最後の砦”**として注目を集める TabPFN。 LightGBMやCatBoostの牙城を脅かすこの手法は、驚くべきことに「学習が不要」です。

この記事では、単なる使用方法ではなく、TabPFNの設計思想とその理論的背景から「なぜ学習不要なのか?」を丁寧に解説します。


🔁 一般的なMLモデルの構造

まず従来のテーブルデータ向けモデル(例:LightGBM, XGBoost)は、次のように**「タスクごとに学習」**する枠組みです:

タスク (D)  →  モデル学習 (fit)  →  予測器 f(x)

この枠組みでは、毎回新しいデータセットに対し、予測関数 $f(x)$ を学習する必要があります。


🧠 TabPFNの核心:学習済みの「タスク予測器」

TabPFNの設計思想は根本的に異なります。 彼らのアプローチでは、以下のように「分類タスクそのもの」を予測するモデルを事前学習します:

(特徴量X, ラベルy)の小サンプル → f_タスク予測器(x_new)

✅ モデルの本質は「汎用タスク推論器」

TabPFNが内部でやっているのは、任意の分類タスクに対する“ベイズ最適分類器”の出力を模倣することです。


🧩 仕組み:Bayes-optimal Classifier を Transformer が近似

1. タスク生成分布の事前定義

  • 仮想的に何百万もの分類タスク(特徴量数・クラス数・ノイズ条件など多様)を合成
  • 各タスクについて、生成過程を完全に把握している(ラベル付け分布が定義済み)

2. ベイズ最適な決定境界を計算

  • 各タスクにおけるBayes Classifierの決定境界を計算可能(解析的 or 数値的)

3. Transformerが近似学習

  • 入力:タスクの少数のサンプル(X, y)+予測対象の特徴量 $x_*$
  • 出力:クラスの予測確率
  • レーニング目標:
  p(y_* | x_*, D) ≈ Transformer(x_*, D)

このTransformerは、任意の「新しい分類タスク」に対して、 その背後にあるデータ生成分布 $P(D)$ に基づいたベイズ最適な予測分布を返すように訓練されます。


📌 重要:なぜ「再学習」が不要なのか?

TabPFNは、以下の意味で「学習が不要(Zero-Shot)」です:

視点 従来モデル TabPFN
学習対象 各タスクに特化した分類関数 あらゆるタスクのベイズ分類境界の近似器
fit() の役割 勾配による重み最適化 データの並び替え+固定モデルへの入力変換
学習パラメータ タスクごとに最適化される 事前に学習済み。推論時は変更されない
モデル本体 タスク依存 タスク非依存(普遍的な“タスク推論器”)

結論として、TabPFNの .fit() は「訓練」ではなく、「入力整形とセットアップ」であり、 分類器本体は一切学習(パラメータ更新)を行いません。


🧪 数式的な補足(ベイズ分類器)

与えられたタスク $D = {(x_i, y_i)}{i=1}^n$ に対し、予測対象 $x*$ におけるラベル分布は以下:

p(y_* | x_*, D) = \int_\theta p(y_* | x_*, \theta) p(\theta | D) d\theta

このベイズ事後分布を、TabPFNは「Transformerで近似的に直接出力」します。


⚠ 限界と応用の方向性

  • ❌ 自前データで事前学習を行う拡張は原理的に困難(生成分布を定義できないため)
  • ✅ 「データが少ない&学習コストをかけたくない分類タスク」に対し、圧倒的に有効
  • ✅ 今後の応用例:AutoMLの初期モデル、医療・製造・金融の少量高価データ分類など

📝 結論

TabPFNが学習不要なのは、そもそも学習を「各タスク単位」ではなく「タスク全体の分布」に対して済ませているからです。 その結果、事前学習済みTransformerだけで新しい分類タスクに即応できるという、実用と理論を両立したアプローチを実現しています。


📚 参考論文

5秒で高精度?TabPFNでテーブルデータ分析の新常識

🔍 TabPFNとは?

TabPFN(Tabular Prior-Data Few-shot Network)は、2023年に登場したTransformerベースの事前学習済みモデルで、特徴的なのは以下のポイント:

  • 学習不要:トレーニングせずに即座に推論可能
  • 数秒で高精度な分類が可能(データセットによってはLightGBM超え)
  • ✅ 小規模なテーブルデータの扱いに最適
  • ✅ PyTorchベースで導入が簡単

このモデルは、"few-shot learning" の考え方をテーブルデータに適用したもので、「分類問題における事前学習済み脳」だと考えるとイメージしやすいです。


🔧 インストール方法

TabPFNはPyPIからインストール可能です。GPU環境が望ましいですが、CPUでも動きます。

pip install tabpfn

初回実行時にモデルが自動でダウンロードされます(約350MB)。


🧪 サンプルコード:Irisデータセットで試してみる

from tabpfn import TabPFNClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# データ読み込み
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# モデル初期化(デフォルトでGPU対応)
model = TabPFNClassifier(device='cuda' if torch.cuda.is_available() else 'cpu')

# 推論(学習ではない)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

# 精度評価
acc = accuracy_score(y_test, y_pred)
print(f"Accuracy: {acc:.4f}")

📝 使用時の注意点

制限 内容
🔢 特徴量数 最大100個まで(それ以上はエラー)
📊 タスク 現在は分類のみ対応(回帰は未対応)
🧪 学習は不要 .fit()は推論用の内部処理で実際にはトレーニングしない
📁 データサイズ 数百件〜数千件のデータが最適(大規模データには不向き)

📚 参考情報

  • 公式GitHub
  • 論文:「Prior-Data Fitted Networks: Meta-Learning with a Single Transformer」

🚀 まとめ

TabPFNは「モデルをチューニングしてる時間がない」「小規模データでサクッと高精度を出したい」場面で、非常に強力な選択肢です。 大規模データや回帰タスクにはまだ課題もありますが、今後の進化が非常に楽しみなテーブルデータ分析の新潮流です。

J-Quantsデータを使用した重要指標(PER,PBR,ROE)推移の算出方法について

株価の割安さや収益性をはかる指標としてPER,PBR,ROEは非常に重要だと思います。ただ、これら指標の過去データの取得方法についてあまり情報が見つかりませんでした。無いなら自分で導こうということで、試行錯誤してみたのでブログにまとめます。

1.各種指標について

指標に関する説明は簡単に整理しますが、詳しくは色んなサイトで解説されています。

① PER(Price Earning Ratio):株価収益率

② PBR(Price Book-value Ratio):株価純資産倍率

ROE(Return On Equity):自己資本利益率

2.データ取得元:J-Quants

J-QuantsはJPX(日本取引所グループ)が個人投資家向けに運営するAPIデータ配信サービスです。API経由で最新の正確な金融データが簡単に取得できるおすすめのサービスですが、いくつか注意点があります。

  • 用途が個人の私的利用に限定されているのでデータの第三者配信やデータを利用したアプリの提供などが禁止されている。
  • 無償プラン、有償プランがあるが、ちゃんと分析しようとすると確実に有償プランが必要になる。

詳しくはJ-Quantsサイトを参照ください。

jpx-jquants.com

3.J-Quantsからのデータ取得方法

まずは上記J-Quantsサイトでアカウントを作成します。アカウント作成時にメールアドレスとパスワードを登録するのですが、それは後程API呼び出し時にも使います。 その後、プランを選択します。お試しで使いたい場合は無料プランで登録しましょう。

ここまで来たら準備完了です。PythonからAPIを呼び出せます。金融データを呼び出すためにはまずはIDトークンが必要になります。IDトークンはアカウント作成時に登録したメールアドレスとパスワードが必要になります。

import requests
import json

# アカウント情報格納
data={"mailaddress":"<YOUR EMAIL_ADDRESS>", "password":"<YOUR PASSWORD>"}

# リフレッシュトークンの取得
r_post = requests.post("https://api.jquants.com/v1/token/auth_user", data=json.dumps(data))
REFRESH_TOKEN = r_post.json()['refreshToken']

# IDトークンの取得
r_post = requests.post(f"https://api.jquants.com/v1/token/auth_refresh?refreshtoken={REFRESH_TOKEN}")
idToken = r_post.json()['idToken']

次に金融データを呼び出します。金融データの種類によって呼び出すAPIは異なります。例えば「株価四本値」の場合は"https://api.jquants.com/v1/prices/daily_quotes"です。以下は2024/4/1~5/1の任天堂の株価四本値を取得してpandas.DataFrameに格納する例です。

import pandas as pd

# リクエストのヘッダー情報とパラメータを設定
headers = {'Authorization': 'Bearer {}'.format(idToken)}
params = {'code': '79740', 'from':'20240401', 'to':'20240501'}

r = requests.get("https://api.jquants.com/v1/prices/daily_quotes",params=params, headers=headers)
df = pd.DataFrame(r.json()['daily_quotes'])

上記のcodeの部分は基本的に4桁の銘柄コードに”0”を末尾に付けたものですが、正確な情報は上場銘柄一覧のAPIを呼び出すことで確認することが可能です。

4.データ取得とPER,PBR,ROEの計算

PER,PBR,ROEを計算する場合は、株価四本値と財務情報のAPIが必要になります。財務情報APIでEPSとBPSを取得、株価四本値APIで株価を取得してそれらを計算することでPER,PBR,ROEを計算します。

import pandas as pd

# リクエストのヘッダー情報とパラメータを設定
headers = {'Authorization': 'Bearer {}'.format(idToken)}
params = {'code': '79740'}

# 株価四本値の取得
r = requests.get("https://api.jquants.com/v1/prices/daily_quotes",params=params, headers=headers)
df_quotes = pd.DataFrame(r.json()['daily_quotes'])

# 財務情報の取得
r = requests.get("https://api.jquants.com/v1/fins/statements", params=params, headers=headers)
df_statements = pd.DataFrame(r.json()['statements'])

EPSは現在値と会社予想値がありますが、将来予測を目的としているため、会社予想値を採用したいと思います。該当する変数は「ForecastEarningsPerShare」です。ただ、データを見ていただければ分かると思いますが、欠損値があります。これは年度末のデータに見られる傾向で、年度末時点でEPSは確定しているため発生しているものと思われます。そのため、欠損値は次年度のEPS「NextYearForecastEarningsPerShare」で補完します。そのうえで、株価データと突合してPERとPBRを計算します。

def replace_null(df, col):
    df.loc[df[col]=='', col] = None
    df[col] = df[col].fillna(method='ffill')
    return df

df_statements .loc[df_statements ['ForecastEarningsPerShare']=='', 'CurrentFiscalYearEndDate'] = df_statements ['NextFiscalYearEndDate']
df_statements .loc[df_statements ['ForecastEarningsPerShare']=='', 'ForecastEarningsPerShare'] = df_statements ['NextYearForecastEarningsPerShare']

df_statements = replace_null(df_statements , 'BookValuePerShare')
df_statements = replace_null(df_statements , 'NextFiscalYearStartDate')

df_statements = replace_null(df_statements , 'ForecastEarningsPerShare')
df_statements = replace_null(df_statements , 'BookValuePerShare')
df_statements ['ForecastEarningsPerShare'] = df_statements ['ForecastEarningsPerShare'].astype(float)
df_statements ['BookValuePerShare'] = df_statements ['BookValuePerShare'].astype(float)

df_adj = df_quotes[~(df_quotes['AdjustmentFactor']==1)].copy()

for index, row in df_adj.iterrows():
    # EPS
    adj_date = row['Date']
    adj_factor = row['AdjustmentFactor']
    df_stats.loc[df_stats['CurrentFiscalYearEndDate']<adj_date, 'ForecastEarningsPerShare'] = df_stats['ForecastEarningsPerShare']*adj_factor
    # BPS
    df_stats.loc[df_stats['NextFiscalYearStartDate']<adj_date, 'BookValuePerShare'] = df_stats['BookValuePerShare']*adj_factor

df_stats = df_stats.loc[~(df_stats.duplicated(subset=['DisclosedDate'], keep='last'))]

df= df_quotes.merge(df_statements , how='left', left_on='Date', right_on='DisclosedDate')
df['ForecastEarningsPerShare'] = df['ForecastEarningsPerShare'].fillna(method='ffill')
df['BookValuePerShare'] = df['BookValuePerShare'].fillna(method='ffill')
df['DisclosedDate'] = df['DisclosedDate'].fillna(method='ffill')
df['per'] = df['AdjustmentClose'] / df['ForecastEarningsPerShare']
df['pbr'] = df['AdjustmentClose'] / df['BookValuePerShare']
df['roe'] = df['pbr'] / df['per']

Pythonのf-stringsを使ったPandas.DataFrameの列名の動的設定

変数を使用してPandas.DataFrameの列名を動的に設定する方法についてまとめます。 Pythonにはフォーマット済み文字列リテラル(f-strings)という記法が存在するのですが、今回はそれを使用します。

1.フォーマット済み文字列リテラル(f-strings)とは

文字列の中に変数や式の値を埋め込む手法です。例を見た方が早いので、以下に例示します。

name = 'Tarou'
print(f'My name is {name}')

以下のように出力されます。

このように、文字列をf''で囲い、その中で変数や式を{}で囲うことで、変数や式の値を文字列に埋め込むことができます。 他にも出力する数字の桁数を指定したり色々とできます。詳細は以下、公式ドキュメントを参照ください。

docs.python.org

2.DataFrameの列名の動的設定

フォーマット済み文字列リテラルはDataFrameにも使えます。これも例を見てみましょう。

import pandas as pd
import plotly.express as px

df = px.data.stocks()
for i in range(1,4):
    df[f'GOOG_{i}'] = df['GOOG'].shift(i)
display(df.head())

こんな感じでラグ変数の変数名を設定するときに使うことができます。その他、変数の掛け合わせ等様々な用途でフォーマット済み文字列リテラルは使えます。

pandasでデータ抽出する際の速度の比較(loc対query)

Pandas Dataframeに対して、locで抽出した方が良いのか、queryで抽出した方が良いのか。 可読性はqueryの方が良さそうですが、今回は性能面で比較してみようと思います。

1.データダウンロード

データはsklearnの「カリフォルニア住宅価格」を使用しました。

import pandas as pd
from sklearn import datasets
df = datasets.fetch_california_housing(as_frame=True).frame

2.処理時間計測

locとqueryそれぞれで%%timeitを使用して実行時間を計測します。

%%timeit -n 100
df.loc[(df['MedInc']>2.5) & (df['MedInc']<5)]

%%timeit -n 100
df.query('2.5<MedInc<5')

3.結果

結果はlocの方が倍ぐらい早いようでした。 複雑な条件になる場合はqueryの方が可読性が高いので、何度も呼び出さない場合はqueryでも良いと思いますが、速度を重視する場合はlocの方が良さそうです。