【証券分析6-3】リターンデータのみからファクターを生成しよう

ファイナンス理論

マルチファクターモデルにおいて用いられるファクターには、ファーマフレンチの3ファクターモデルやマクロファクターモデルのように、あらかじめファクターの意味や計算方法が定義されているものがあります。これらのモデルは、特定の経済理論や実証研究に基づいて、どのファクターが資産価格に影響を与えるかを明示的に決定します。

一方で、あらかじめファクターの定義を決めるのではなく、複数の資産価格に共通する変動要因を機械的に取り出し、それをファクターとする手法も存在します。この場合、必要となるデータはリターンデータのみなので、非常に簡単に試すことができます。今回は、そのようなアプローチの一つである主成分分析(PCA)を用いたファクターの生成、因子分析を用いたファクター生成の方法について紹介します。

主成分分析とは?

主成分分析(Principal Component Analysis, PCA)は、高次元データを低次元に削減するための手法で、データの分散を最大限に説明する新しい変数(主成分)を作成します。これにより、データの最も重要な特徴を捉えつつ、次元を削減することができます。
なぜ、これがファクターの生成につながるのかということを考えてみます。
そもそもファクターというのは、複数の銘柄があった時に、共通して価格が変動する要因のことを示しています。
したがって、たくさんの銘柄が存在する中で、共通する要因を取り出したいわけです。
そのため、主成分分析でデータの中で最も重要度の高い特徴=ファクターと考えることができます。

主成分分析を用いたファクター生成の手順

  1. データの準備
    分析対象とする資産のリターンデータを用意します。例えば、株式市場のリターンデータセットを用意します。

  2. データの標準化
    各資産のリターンを標準化(平均0、分散1)します。これにより、異なるスケールのリターンを同一基準で比較可能にします。

  3. 共分散行列の計算
    標準化したリターンデータの共分散行列を計算します。共分散行列は、資産間の相関関係を表します。

  4. 固有ベクトルと固有値の計算
    共分散行列から固有ベクトルと固有値を計算します。固有ベクトルは主成分の方向を示し、固有値はその主成分がどれだけデータの分散を説明するかを示します。

  5. 主成分の選択
    固有値の大きさに基づいて、重要な主成分を選択します。通常、累積寄与率が80%から90%になるまでの主成分を選びます。

  6. ファクターの生成
    選ばれた主成分を用いて、元のデータを新しい主成分空間に変換します。これにより、資産のリターンを説明するための新しいファクターが生成されます。

言葉で説明するとわかりにくいかと思いますので、実際にコードで見ていきたいと思います。

主成分分析によるファクター生成

それでは実際にTOPIX100の価格データを利用して、主成分分析に基づいたファクター生成を行ってみましょう。
データの取得は価格データのサンプルをランダムに生成して用います。
分析したいデータに合わせて変更してください。

import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# ランダムなリターンデータの生成
np.random.seed(42)  # 再現性のためのシード設定
num_assets = 10     # 資産の数
num_observations = 100  # 観測期間の数

# 平均0%、標準偏差1%の正規分布に従うリターンを生成
mean_returns = np.zeros(num_assets)
cov_matrix = np.identity(num_assets) * 0.01  # 共分散行列(対角成分が0.01)

# 正規分布に従うランダムリターンの生成
returns = np.random.multivariate_normal(mean_returns, cov_matrix, num_observations)

# データフレームに変換
returns_df = pd.DataFrame(returns, columns=[f'Asset_{i+1}' for i in range(num_assets)])
# データの標準化
scaler = StandardScaler()
standardized_returns = scaler.fit_transform(returns_df)

# PCAの適用
pca = PCA()
pca.fit(standardized_returns)

# 累積寄与率を計算
cumulative_variance = np.cumsum(pca.explained_variance_ratio_)

# 累積寄与率が80%を超える主成分数を決定
num_components = np.argmax(cumulative_variance >= 0.80) + 1

# 選ばれた主成分を用いてデータを変換
principal_components = pca.transform(standardized_returns)[:, :num_components]

# ファクターの生成
factors = pd.DataFrame(principal_components, columns=[f'PC{i+1}' for i in range(num_components)])
factors

因子分析とは?

続いて、因子分析を用いる場合を見ていきます。
因子分析(Factor Analysis, FA)は、観測された変数の背後にある潜在因子(ファクター)を特定するための手法です。因子分析は、観測データが少数の潜在変数に依存しているという仮定に基づいて、データの構造をモデル化します。主成分分析はデータから重要そうな特徴を取り出すのに対して、因子分析は共通因子と固有因子にデータを分解し、共通因子を見つけるための手法になります。ファクターを作るというイメージには主成分分析よりもより近い手法になります。

因子分析によるファクター生成

因子分析の場合も基本的な手順は主成分分析の場合と同じですので、さっそく実際のPythonコードを見ていきます。

import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from factor_analyzer import FactorAnalyzer

# ランダムなリターンデータの生成
np.random.seed(42)  # 再現性のためのシード設定
num_assets = 10     # 資産の数
num_observations = 100  # 観測期間の数

# 平均0%、標準偏差1%の正規分布に従うリターンを生成
mean_returns = np.zeros(num_assets)
cov_matrix = np.identity(num_assets) * 0.01  # 共分散行列(対角成分が0.01)

# 正規分布に従うランダムリターンの生成
returns = np.random.multivariate_normal(mean_returns, cov_matrix, num_observations)

# データフレームに変換
returns_df = pd.DataFrame(returns, columns=[f'Asset_{i+1}' for i in range(num_assets)])

# データの標準化
scaler = StandardScaler()
standardized_returns = scaler.fit_transform(returns_df)

# 因子分析の適用
num_components = 3  # 使用する因子の数を設定(例として3を使用)
fa = FactorAnalyzer(n_factors=num_components, rotation='varimax')
fa.fit(standardized_returns)

# 因子スコアの計算
factor_scores = fa.transform(standardized_returns)

# ファクターの生成
fa_factors = pd.DataFrame(factor_scores, columns=[f'Factor{i+1}' for i in range(num_components)])
fa_factors

主成分分析や因子分析を用いたファクターの生成は、あらかじめファクターを定義せず、データから自動的に主要な変動要因を抽出する方法です。このアプローチは、特定の理論や仮定に縛られないので、必要となるデータが非常に少なくて済むのがメリットです。一方で、デメリットとしては、上位いくつの成分をファクターとして、定義すればいいのか、それぞれのファクターがどういった意味を持つのか解釈が難しいといった部分が挙げられる。これらの特徴を理解したうえで、PCAを活用したファクター生成も試してみてください。

今回のコードはこちらのGoogleColabで実行できます。

タイトルとURLをコピーしました