4. 因子计算:基于PageRank的因子、基于社区结构的因子、基于图嵌入的因子

好,咱们进入图因子计算的核心环节。说实话,这部分内容我当年啃了很久才真正吃透。你想想看,传统的因子都是基于价格、成交量这些时间序列数据,而图因子是从股票之间的关联关系中挖出来的。这完全是另一个维度的信息。

我个人习惯把图因子分成三大类:基于PageRank的基于社区结构的基于图嵌入的。这三类各有各的脾气,咱们一个一个来拆解。

4.1 基于PageRank的因子

PageRank,大家可能都听说过,Google当年靠它起家的。但用在股票上,思路完全不一样。在股票关联网络中,PageRank值衡量的是一只股票在网络中的"重要性"或"影响力"

怎么理解?一只股票如果被很多"重要"的股票高度关联,它的PageRank值就高。说白了,它就是网络中的"意见领袖"。

核心逻辑: 一只股票的PageRank值越高,它在整个市场网络中的系统重要性越大,其价格波动可能具有更强的传导效应。

我在项目中遇到过这样的情况:用沪深300成分股构建关联网络,计算PageRank值后,发现排名靠前的股票往往是一些银行股和保险股。嗯,这其实很合理——金融板块的关联性本来就强。

具体计算步骤,我一般这么走:

  1. 构建关联矩阵:用股票收益率的相关系数或偏相关系数,构建N×N的邻接矩阵
  2. 归一化处理:对矩阵进行列归一化,确保每列和为1
  3. 迭代计算:用幂迭代法求解PageRank值,直到收敛
  4. 因子构造:将PageRank值作为因子值,或者取对数、排名等变换
import networkx as nx
import numpy as np

def compute_pagerank_factor(returns, threshold=0.3):
    """
    基于收益率序列计算PageRank因子
    returns: DataFrame, 股票收益率数据 (T x N)
    threshold: 相关系数阈值,低于此值视为无连接
    """
    # 1. 计算相关系数矩阵
    corr_matrix = returns.corr().values
    
    # 2. 构建邻接矩阵(只保留强相关)
    adj_matrix = np.where(np.abs(corr_matrix) > threshold, np.abs(corr_matrix), 0)
    np.fill_diagonal(adj_matrix, 0)  # 去掉自环
    
    # 3. 构建图
    G = nx.from_numpy_array(adj_matrix)
    
    # 4. 计算PageRank
    pagerank = nx.pagerank(G, alpha=0.85)
    
    # 5. 转为因子值
    factor = pd.Series(pagerank).sort_index()
    factor.index = returns.columns
    
    return factor
我的经验: 阈值threshold的选择很关键。设得太低,网络太密,PageRank值区分度差;设得太高,网络太稀疏,很多股票孤立。我一般用0.3-0.5之间,具体要看数据频率。日频数据建议0.3,周频可以放宽到0.25。

4.2 基于社区结构的因子

社区结构,说白了就是"物以类聚,人以群分"。在股票网络中,社区就是那些走势高度同步的股票群体。比如,白酒板块、新能源板块,它们内部关联性强,跨板块关联弱。

基于社区结构的因子,核心思路是:一只股票在其所属社区中的地位。我常用的指标有两个:

  • 模块度贡献度:衡量股票对其所在社区凝聚力的贡献
  • 社区内中心度:股票在社区内部的连接强度

我曾经踩过一个坑:直接用Louvain算法做社区检测,然后取社区编号作为因子。结果回测效果很差。为什么?因为社区编号是离散的、无序的,没法直接作为数值因子使用。

避坑指南: 社区编号本身不能直接作为因子!你需要提取的是连续型指标,比如社区内连接数、社区内PageRank、社区间连接比例等。

我后来改用社区内度中心度作为因子,效果就好多了。具体做法:

def compute_community_factor(returns, threshold=0.3):
    """
    基于社区结构的因子计算
    """
    # 构建图(同上)
    corr_matrix = returns.corr().values
    adj_matrix = np.where(np.abs(corr_matrix) > threshold, 1, 0)
    np.fill_diagonal(adj_matrix, 0)
    G = nx.from_numpy_array(adj_matrix)
    
    # 社区检测
    communities = nx.community.louvain_communities(G, seed=42)
    
    # 计算每个节点的社区内度中心度
    community_factor = {}
    for node in G.nodes():
        # 找到节点所属社区
        for comm_id, comm in enumerate(communities):
            if node in comm:
                # 计算社区内连接数
                internal_edges = sum(1 for neighbor in G.neighbors(node) if neighbor in comm)
                community_factor[node] = internal_edges / (len(comm) - 1)  # 归一化
                break
    
    factor = pd.Series(community_factor).sort_index()
    factor.index = returns.columns
    
    return factor

你想想看,这个因子的逻辑是什么?一只股票在社区内的连接越密集,说明它和同板块股票联动越强。这种股票往往更容易受到板块情绪的影响,波动也更同步。

4.3 基于图嵌入的因子

图嵌入,这是近几年比较火的方向。它的核心思想是:把图中的每个节点(股票)映射到一个低维向量空间中,同时保留节点的拓扑结构信息。

说白了,就是把网络结构"压缩"成一组数值特征。这些特征向量就可以直接作为因子使用。

我常用的图嵌入方法有:

方法 核心思想 适用场景
Node2Vec 随机游走 + Word2Vec 大规模网络,捕捉局部结构
DeepWalk 深度优先随机游走 社区结构明显的网络
LINE 一阶/二阶邻近度 边权重重要的场景
SDNE 自编码器 非线性结构复杂的网络

我个人习惯用Node2Vec。为什么?因为它有p和q两个参数,可以控制游走是偏向BFS还是DFS,灵活性高。

from node2vec import Node2Vec

def compute_node2vec_factor(returns, threshold=0.3, dim=16):
    """
    基于Node2Vec的图嵌入因子
    dim: 嵌入维度,一般取8-32之间
    """
    # 构建图
    corr_matrix = returns.corr().values
    adj_matrix = np.where(np.abs(corr_matrix) > threshold, 1, 0)
    np.fill_diagonal(adj_matrix, 0)
    G = nx.from_numpy_array(adj_matrix)
    
    # Node2Vec嵌入
    node2vec = Node2Vec(G, dimensions=dim, walk_length=30, 
                        num_walks=200, p=1, q=2, workers=4)
    model = node2vec.fit(window=10, min_count=1)
    
    # 提取嵌入向量
    embeddings = np.array([model.wv[str(i)] for i in range(len(G.nodes()))])
    
    # 这里可以取第一维作为因子,或者用PCA降维到1维
    factor = pd.Series(embeddings[:, 0], index=returns.columns)
    
    return factor
我的经验: 嵌入维度dim不要设太大。我试过32维、64维,结果过拟合严重。后来发现8-16维就够用了。另外,p和q参数也很关键:p小(偏向BFS)能捕捉社区结构,q小(偏向DFS)能捕捉结构等价性。我一般先用p=1, q=2试试水。

4.4 三类因子的对比与选择

好,三类因子都讲完了。你可能会问:到底该用哪个?

我个人的经验是:

  • PageRank因子:适合捕捉系统重要性,对大盘股、金融股效果较好
  • 社区结构因子:适合捕捉板块效应,对行业轮动策略有帮助
  • 图嵌入因子:最灵活,但可解释性最差,适合做机器学习模型的输入特征

嗯,这里要注意:图嵌入因子虽然强大,但它的可解释性是个大问题。你很难说清楚"第3维嵌入值高"到底代表什么。所以,如果做学术研究或者需要向领导解释,我建议优先用PageRank和社区结构因子。

最后,我画了一张图,帮你理清这三类因子的关系:

图因子三大流派 股票关联网络 PageRank因子 系统重要性 影响力传导 社区结构因子 板块效应 社区内中心度 图嵌入因子 Node2Vec/DeepWalk 低维向量特征 选择建议 可解释性:PageRank > 社区结构 > 图嵌入 | 灵活性:图嵌入 > 社区结构 > PageRank

这张图把三类因子的定位和关系说清楚了。你写代码的时候,可以对照着这张图,想想自己到底需要哪一类因子。

好了,因子计算这块就讲到这里。记住,图因子不是银弹,它和传统因子是互补关系。我建议你在回测中把图因子和传统因子结合起来用,效果往往更好。

核心要点回顾:
  • PageRank因子:衡量系统重要性,适合大盘股
  • 社区结构因子:捕捉板块效应,适合行业轮动
  • 图嵌入因子:最灵活,但可解释性差
  • 阈值选择、嵌入维度等参数需要仔细调优

公众号:蓝海资料掘金营,微信deep3321