vlambda博客
学习文章列表

期权数据的PCA与K均值聚类算法

本号专注于方法归纳和量化实现,是我与读者互动的唯一平台,若有以我名义讲座授课,加好友拉群,理财开户等烦请协助告发,事后必谢。内容不构成投资建议,如需转载请注明出处


我的数据都是一个个手工从上交所官网上弄下来的。所以在这里也拜托各位如果谁在期权这块知道更好的免费的数据源,请后台留言给我,万分感谢。

数据来源:上交所官网网址

http://www.sse.com.cn/assortment/options/price/


以下是我import的所有内容

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.cluster import SpectralClustering


我的表单里没啥空白数据,这里也可以不用dropna。主要是把相关数据拿出来,做个标准化,标准化也是聚类算法里面最常用的。

df = pd.read_csv('./50ETFDaily.csv')
df.dropna(inplace=True)
Selected_Columns = (['Total_Vol', 'Call_Vol', 'Put_Vol', 'Put_Call_Ratio',
'Total_OpenInt', 'Call_OpenInt', 'Put_OpenInt', '50IV'])
df = df.loc[:, Selected_Columns]
processed_data = StandardScaler().fit_transform(df)

我在这里为了看图方便,没有直接选用explained variance数据,而是乘以了100。

pca = PCA(n_components=df.shape[1])
pca.fit_transform(processed_data)
pev = np.round(pca.explained_variance_ratio_*100, decimals=2)
fig_scree = plt.figure(figsize=(6, 4))
plt.scatter(range(1, df.shape[1]+1), pev)
plt.plot(range(1, df.shape[1]+1), pev)
plt.title('Scree Plot')
plt.xlabel('Components')
plt.ylabel('Percentage of Explained Variance')
plt.axhline(y=10, c="red")
plt.grid()


期权数据的PCA与K均值聚类算法

从上图可以看出,我们只要选择3个components就足够了,所以为了偷懒,我写了下面这段语句,自动帮我算出3个

cum_evr = pev.cumsum()/pev.sum()
n_pc = 1+df.shape[1]-np.sum(cum_evr >= 0.9)

计算降维后的数据

pca = PCA(n_components=n_pc)
reduced_data = pca.fit_transform(processed_data)
df_pca = pd.DataFrame(data=reduced_data)
hm_data = pd.DataFrame(np.abs(pca.components_), columns=df.columns)
fig_heatmap = plt.figure(figsize=(13, 3))
ax = sns.heatmap(hm_data, annot=True, cmap="seismic")
ax.yaxis.set_tick_params(labelsize=9)
ax.xaxis.set_tick_params(labelsize=9)
plt.title('PCA Heatmap')
plt.savefig('PCA.png', dpi=100)


生成热图便于我们更加直观的观察,当然如果涉及的内容较多会看起来很不清晰,所以我们可以把图片给保存了,再打开看,这样会比直接在python程序运行时看要清晰很多。

期权数据的PCA与K均值聚类算法


通常主成分选择2或3个才可能做成散点图,所以同样为了偷懒,我干脆把作图套进了条件语句,如果我选择的主成分数量不符合作图要求,就提示;如果是2个或者3个,那么就作出对应的图。

if n_pc == 2:
fig_PCA_Scatter = plt.figure(figsize=(6, 4))
plt.scatter(df_pca[0], df_pca[1])
plt.title('PCA Scatter')
plt.xlabel('PC1 - {0}%'.format(pev[0]))
plt.ylabel('PC2 - {0}%'.format(pev[1]))
elif n_pc == 3:
fig_PCA_Scatter = plt.figure(figsize=(6, 4))
ax1 = plt.axes(projection='3d')
ax1.scatter(df_pca[0], df_pca[1], df_pca[2], c='r', marker='^')
plt.title('PCA Scatter')
ax1.set_xlabel('PC1 - {0}%'.format(pev[0]))
ax1.set_ylabel('PC2 - {0}%'.format(pev[1]))
ax1.set_zlabel('PC3 - {0}%'.format(pev[2]))
else:
print('主成分数量为: ', n_pc, ' 不适合画散点图')


我们现在可以看清在三维结构中,以三个主成分为向量的散点图结构

期权数据的PCA与K均值聚类算法


下面我们来做kmeans聚类

fig_Kmeans_clusters = plt.figure(figsize=(6, 4))
model = SpectralClustering(n_clusters=n_pc, affinity='nearest_neighbors', assign_labels='kmeans')
labels = model.fit_predict(reduced_data)
ax2 = plt.axes(projection='3d')
ax2.scatter(reduced_data[:, 0], reduced_data[:, 1], reduced_data[:, 2], c=labels, s=25, cmap='plasma')
kmeans = KMeans(n_clusters=n_pc)
kmeans.fit(reduced_data)
centers = kmeans.cluster_centers_
ax2.scatter(centers[:, 0], centers[:, 1], centers[:, 2], c='black', s=50, marker='x')
plt.title('Kmeans Clusters')
ax2.set_xlabel('PC1 - {0}%'.format(pev[0]))
ax2.set_ylabel('PC2 - {0}%'.format(pev[1]))
ax2.set_zlabel('PC3 - {0}%'.format(pev[2]))


同样的图上这次三个聚类被区分开来并标注出了各自的中心,这个聚类图是比较简单的,大家可以在我这个模板的基础上进一步研究不同指标,不同日期(例如周一到周五)的聚类。


我们还可以用within cluster sum of square来看下聚类的效果

fig_wc_ss = plt.figure(figsize=(6, 4))
wc_ss = []
k = range(1, 8)
for i in k:
estimator = KMeans(i)
estimator.fit(reduced_data)
wc_ss_iter = estimator.inertia_
wc_ss.append(wc_ss_iter)
plt.title('Elbow Plot')
plt.xlabel('k')
plt.ylabel('within-cluster sum of squares')
plt.plot(k, wc_ss, 'o-')
plt.grid()

使用elbow图的形式会非常的直观,我们可以看出选3个或者4个clusters都是可以的,大家也可以试试看k=其他数值的结果。


我又要被派去当志愿者了,正在赶往点位的地铁上。所以这次的文章先简单讲解些代码,下回会用DBSCAN等,做更具体的讲解。