Python炒股新手如何用聚类分析找出相似股票

发布时间:2026-10-17 13:23阅读:10053评论:0

为什么要对股票做聚类分析

打开行情软件,几千只股票看得眼花缭乱。你可能会想,有没有办法把那些“脾气”差不多的股票归到一起?聚类分析干的就是这件事。它不需要你提前告诉机器哪只股票属于哪个行业,而是让算法自己根据数据特征把相似的股票聚成团。这对做轮动策略、构建投资组合或者单纯想找替代品都有实际意义。

举个例子,你持有某只消费股,想找一只走势逻辑相近的备选,手动翻看F10资料效率太低。用聚类分析跑一遍,同一簇里的股票大概率在涨跌节奏、波动幅度上高度同步。

获取股票数据

做聚类的前提是有干净的数据。A股数据可以用akshare或者tushare获取。这里以akshare为例,它免费且接口稳定。我们需要的是每只股票一段时期内的日线行情,通常取最近一年的收盘价序列。

Python炒股新手如何用聚类分析找出相似股票


import akshare as ak

import pandas as pd

# 获取沪深300成分股列表

hs300 = ak.index_stock_cons(symbol="000300")

codes = hs300['品种代码'].tolist()[:50]  # 取前50只做演示

# 定义获取单只股票历史数据的函数

def get_stock_data(code, start_date="20230101", end_date="20231231"):

    df = ak.stock_zh_a_hist(symbol=code, period="daily", start_date=start_date, end_date=end_date, adjust="qfq")

    df['日期'] = pd.to_datetime(df['日期'])

    df = df.set_index('日期')

    return df['收盘']

# 批量获取并合并成一个DataFrame

price_data = {}

for code in codes:

    try:

        price_data[code] = get_stock_data(code)

    except:

        pass

price_df = pd.DataFrame(price_data)

price_df = price_df.dropna(axis=1, how='any')  # 剔除数据不全的股票

print(price_df.shape)

特征工程:把走势变成可比较的数字

直接把收盘价丢给聚类算法会出问题——不同股票价格绝对值差异太大,高价股和低价股会被强行分开,但它们的走势形态可能很像。我们需要做两步处理:

  1. 收益率标准化:计算每日收益率,消除价格量级影响。

  2. 特征提取:用收益率序列的统计特征来代表一只股票,比如年化波动率、偏度、峰度、与大盘的相关性、换手率均值等。这些特征能捕捉股票的“性格”。

更直接的做法是把每只股票的收益率序列当成一个向量,计算股票之间的相关性距离。但向量维度太高(一年250个交易日),聚类效果会打折扣。所以通常先降维,再用聚类。


# 计算日收益率

returns_df = price_df.pct_change().dropna()

# 构建特征矩阵:每只股票一行,列为各种统计量

features = pd.DataFrame(index=returns_df.columns)

features['年化波动率'] = returns_df.std() * (252 ** 0.5)

features['偏度'] = returns_df.skew()

features['峰度'] = returns_df.kurt()

features['平均换手率'] = ...  # 需要换手率数据,此处省略获取步骤

features['与大盘相关性'] = returns_df.corrwith(returns_df.mean(axis=1))  # 用等权平均代替大盘

# 标准化特征

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()

features_scaled = scaler.fit_transform(features)

用KMeans给股票分组

KMeans是最常用的聚类算法,核心思想是让同一簇内的点尽量靠近,不同簇的中心尽量远离。需要提前指定簇的数量K。对于股票聚类,K取5到10比较合理,对应不同的风格板块。


from sklearn.cluster import KMeans

import matplotlib.pyplot as plt

# 用肘部法辅助确定K值

inertia = []

for k in range(2, 11):

    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)

    kmeans.fit(features_scaled)

    inertia.append(kmeans.inertia_)

plt.plot(range(2, 11), inertia, marker='o')

plt.xlabel('簇数量')

plt.ylabel('簇内误差平方和')

plt.title('肘部法确定最佳K值')

plt.show()

# 假设选择K=5

kmeans = KMeans(n_clusters=5, random_state=42, n_init=10)

clusters = kmeans.fit_predict(features_scaled)

features['簇标签'] = clusters

# 查看每个簇包含哪些股票

for i in range(5):

    print(f"簇 {i}:", features[features['簇标签']==i].index.tolist())

聚类结果怎么用

聚类本身不产生买卖信号,它的价值在于辅助决策。

构建股票池:如果你看好某个行业但不确定选哪只,可以在该行业所属的簇里挑波动率适中、与大盘相关性较低的股票。

风险分散:持仓如果集中在同一簇,一旦风格切换容易集体回撤。聚类结果能帮你检查持仓的分散程度。

轮动策略:当某个簇整体涨幅落后时,可以关注簇内基本面没问题的个股,等待补涨。

配对交易:同一簇内走势高度相关的两只股票,价差拉大时存在统计套利机会。

别踩这些坑

数据频率:日线数据噪音大,用周线收益率聚类结果更稳定。

时间窗口:不同年份的聚类结果会变化,建议每季度重新跑一次模型。

特征选择:不要塞太多相关性高的特征,否则相当于给某个维度加权,聚类会失真。

缺失值处理:停牌多的股票直接剔除,否则会扭曲簇的形状。

聚类分析是量化投资的入门砖,它帮你把主观的“感觉像”变成客观的“数据像”。Python让这件事的门槛降到了会复制粘贴就能跑通的程度。跑完一遍,你对股票之间关系的理解会上升一个层次。

上一篇股票投资需要有哪五个“一定”?这五条铁律你做到了吗什么股票的涨跌幅度不限?科创板创业板st股交易规则一文说清下一篇
联系管理员
联系管理员