基本面因子计算入门
第二阶段:因子与指标计算 - 详解盈利能力、估值与成长性三大类基本面因子
一、问题引入:如何用量化方法系统评估公司的财务健康状况和估值水平?
在传统投资分析中,投资者通过阅读财务报表、分析行业趋势、评估管理层能力等定性方法来判断一家公司的投资价值。然而,这种方法存在几个核心挑战:
- 主观性过强:不同分析师对同一家公司可能得出截然相反的结论
- 效率低下:手动分析几百家公司的财务报表需要大量时间和精力
- 难以横向比较:不同公司、不同行业间的财务指标缺乏标准化对比方法
- 滞后性明显:财务报告通常按季度发布,无法反映最新的经营状况
这正是基本面量化分析要解决的核心问题:如何用数学和统计学方法,将抽象的"好公司"概念转化为可计算的量化指标体系?
我们今天要解决的问题:
- 理解基本面因子的三大类别:盈利能力、估值、成长性
- 掌握核心基本面因子的计算公式与经济意义
- 用Python实现PE、PB、ROE、营收增长率等关键因子的计算函数
- 可视化展示基本面因子在不同行业、不同公司间的分布特征
- 分析基本面因子在量化策略中的应用价值与局限性
二、知识铺垫:基本面因子的三大类别与经济意义
基本面因子是通过公司财务报表数据计算得出的量化指标,用于系统性评估公司的财务状况、估值水平和成长潜力。根据其经济意义,基本面因子可分为三大类别:
2.1 盈利能力因子:衡量公司"赚钱能力"
盈利能力因子反映公司运用股东资金创造利润的能力,是价值投资者最关注的指标之一。
核心指标1:净资产收益率(ROE)
计算公式:
ROE = 净利润 / 平均净资产 × 100%
经济意义:
- 衡量公司运用股东每1元投资能创造多少利润
- 巴菲特认为"ROE长期保持在20%以上"是好公司的重要标志
- ROE持续上升通常意味着公司竞争优势在增强
示例:
- 奶茶店净资产50万,年净利润10万 → ROE = 20%(每100元本金赚20元)
- ROE高于15%通常被认为是优秀的盈利能力
核心指标2:毛利率(Gross Margin)
计算公式:
毛利率 = (营业收入 - 营业成本)/ 营业收入 × 100%
经济意义:
- 反映公司产品或服务的定价权与成本控制能力
- 高毛利率通常意味着公司在产业链中有较强议价能力
- 毛利率趋势变化能提前预警公司竞争力变化
2.2 估值因子:衡量公司"价格贵不贵"
估值因子帮助投资者判断当前股价是否合理,是否存在安全边际。
核心指标1:市盈率(PE)
计算公式:
PE = 股价 / 每股收益(EPS)
经济意义:
- 相当于"如果公司每年利润不变,需要多少年回本"
- 低PE意味着估值便宜,但需注意是否陷入"价值陷阱"
- 行业间PE差异巨大:银行通常5-10倍,科技股可能30-50倍
示例:
- 奶茶店年利润10万,售价100万 → PE = 10(10年回本)
- 奶茶店年利润20万,售价100万 → PE = 5(5年回本)
核心指标2:市净率(PB)
计算公式:
PB = 股价 / 每股净资产(BPS)
经济意义:
- 衡量"买公司家底的折扣率"
- PB < 1 意味着可以按低于净资产的价格购买公司
- 但需警惕"破净陷阱":净资产质量可能存在问题(如过时设备、巨额商誉)
示例:
- 奶茶店净资产50万,售价100万 → PB = 2(花2倍净资产的钱买)
- 奶茶店净资产50万,售价40万 → PB = 0.8(按8折买家底)
2.3 成长性因子:衡量公司"未来潜力"
成长性因子反映公司的扩张能力和未来增长前景。
核心指标1:营收增长率(Revenue Growth Rate)
计算公式:
营收增长率 = (本期营业收入 - 上期营业收入)/ 上期营业收入 × 100%
经济意义:
- 反映公司业务规模的扩张速度
- 持续高增长通常意味着公司在抢占市场份额
- 但需结合利润增长分析增长质量(避免"增收不增利")
判断标准:
- 营收增长率 > 10%:处于成长期
- 营收增长率 5-10%:处于稳定期
- 营收增长率 < 5%:可能进入衰退期
核心指标2:净利润增长率(Net Profit Growth Rate)
计算公式:
净利润增长率 = (本期净利润 - 上期净利润)/ 上期净利润 × 100%
经济意义:
- 反映公司盈利能力的提升速度
- 高净利润增长通常意味着公司经营效率提升
- 可持续的净利润增长是股价长期上涨的核心动力
2.4 因子间的关系:构建完整的分析框架
基本面因子不是孤立存在的,它们之间存在内在联系:
盈利能力与估值的关系:
- 高ROE的公司通常享受估值溢价(PE较高)
- 但高ROE + 低PE是典型的"价值股"特征
- 需要警惕ROE下滑但估值仍高的风险
成长性与估值的关系:
- 高增长的公司通常享有高估值(增长溢价)
- 但当增长预期落空时,估值回归可能导致"双杀"
- PEG指标(PE/净利润增长率)有助于平衡增长与估值
盈利能力与成长性的关系:
- 高ROE + 高增长是典型的"成长股"特征
- 但高增长可能侵蚀利润率(如市场扩张期的价格战)
- 需要分析增长的质量与可持续性
三、代码实战:Python实现基本面因子计算与可视化
3.1 环境准备与数据获取
首先,我们导入必要的Python库并准备数据。由于真实财务数据需要专业数据源,我们这里使用模拟数据进行演示,但代码结构完全支持真实数据接入。
python
# 导入基础库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 金融数据获取(如果有安装yfinance或tushare)
try:
import yfinance as yf
YFINANCE_AVAILABLE = True
except ImportError:
YFINANCE_AVAILABLE = False
print("提示:如需获取真实股票数据,请安装yfinance库")
print("安装命令: pip install yfinance")
3.2 核心因子计算函数实现
以下是基本面因子的核心计算函数,每个函数都包含清晰的参数说明和异常处理:
python
def calculate_pe(price, eps):
"""
计算市盈率(PE)
参数:
price: 股价(每股价格)
eps: 每股收益
返回:
float: 市盈率(如果EPS<=0则返回NaN)
"""
if eps <= 0:
return np.nan
return price / eps
def calculate_pb(price, bps):
"""
计算市净率(PB)
参数:
price: 股价(每股价格)
bps: 每股净资产
返回:
float: 市净率(如果BPS<=0则返回NaN)
"""
if bps <= 0:
return np.nan
return price / bps
def calculate_roe(net_profit, equity):
"""
计算净资产收益率(ROE)
参数:
net_profit: 净利润
equity: 净资产(股东权益)
返回:
float: 净资产收益率(百分比,如果equity<=0则返回NaN)
"""
if equity <= 0:
return np.nan
return (net_profit / equity) * 100
def calculate_revenue_growth(current_revenue, previous_revenue):
"""
计算营收增长率
参数:
current_revenue: 本期营业收入
previous_revenue: 上期营业收入
返回:
float: 营收增长率(百分比,如果previous_revenue<=0则返回NaN)
"""
if previous_revenue <= 0:
return np.nan
return ((current_revenue - previous_revenue) / previous_revenue) * 100
3.3 模拟财务数据生成
当真实数据不可用时,我们生成模拟数据进行演示:
python
def generate_sample_financial_data():
"""
生成模拟财务数据(当真实数据不可用时)
返回:
pandas DataFrame: 包含多个公司财务数据的模拟数据
"""
np.random.seed(42)
# 创建10家模拟公司
companies = [
'科技巨头_AAA', '消费龙头_BBB', '金融银行_CCC', '医药创新_DDD',
'能源资源_EEE', '制造业_FFF', '公用事业_GGG', '房地产_HHH',
'交通运输_III', '零售服务_JJJ'
]
# 生成模拟数据
data = {
'company': companies,
'industry': ['科技', '消费', '金融', '医药', '能源', '制造', '公用事业', '房地产', '运输', '零售'],
'price': np.random.uniform(20, 200, 10).round(2),
'eps': np.random.uniform(0.5, 8, 10).round(2),
'bps': np.random.uniform(10, 50, 10).round(2),
'net_profit': np.random.uniform(100, 1000, 10).round(2),
'equity': np.random.uniform(500, 5000, 10).round(2),
'revenue_current': np.random.uniform(1000, 10000, 10).round(2),
'revenue_previous': np.random.uniform(800, 9000, 10).round(2),
}
df = pd.DataFrame(data)
# 计算基本面因子
df['PE'] = df.apply(lambda row: calculate_pe(row['price'], row['eps']), axis=1)
df['PB'] = df.apply(lambda row: calculate_pb(row['price'], row['bps']), axis=1)
df['ROE'] = df.apply(lambda row: calculate_roe(row['net_profit'], row['equity']), axis=1)
df['revenue_growth'] = df.apply(lambda row: calculate_revenue_growth(
row['revenue_current'], row['revenue_previous']), axis=1)
return df
3.4 可视化分析函数
生成专业图表展示因子分布特征:
python
def plot_factor_distribution(df, factor_col, title):
"""
绘制因子分布直方图
参数:
df: 包含财务数据的DataFrame
factor_col: 因子列名
title: 图表标题
"""
plt.figure(figsize=(10, 6))
factor_data = df[factor_col].dropna()
plt.hist(factor_data, bins=20, edgecolor='black', alpha=0.7)
plt.axvline(factor_data.mean(), color='red', linestyle='--', linewidth=2,
label=f'平均值: {factor_data.mean():.2f}')
plt.axvline(factor_data.median(), color='green', linestyle='--', linewidth=2,
label=f'中位数: {factor_data.median():.2f}')
plt.title(title, fontsize=14, fontweight='bold')
plt.xlabel(factor_col, fontsize=12)
plt.ylabel('公司数量', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
return plt
def plot_factor_by_industry(df):
"""
绘制按行业分类的因子箱线图
"""
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
# PE按行业分布
pe_data = df[['industry', 'PE']].dropna()
if not pe_data.empty:
pe_data.boxplot(column='PE', by='industry', ax=axes[0, 0], rot=45)
axes[0, 0].set_title('市盈率(PE)按行业分布', fontsize=12)
# ROE按行业分布
roe_data = df[['industry', 'ROE']].dropna()
if not roe_data.empty:
roe_data.boxplot(column='ROE', by='industry', ax=axes[0, 1], rot=45)
axes[0, 1].set_title('净资产收益率(ROE)按行业分布', fontsize=12)
# PB按行业分布
pb_data = df[['industry', 'PB']].dropna()
if not pb_data.empty:
pb_data.boxplot(column='PB', by='industry', ax=axes[1, 0], rot=45)
axes[1, 0].set_title('市净率(PB)按行业分布', fontsize=12)
# 营收增长率按行业分布
growth_data = df[['industry', 'revenue_growth']].dropna()
if not growth_data.empty:
growth_data.boxplot(column='revenue_growth', by='industry', ax=axes[1, 1], rot=45)
axes[1, 1].set_title('营收增长率按行业分布', fontsize=12)
plt.suptitle('基本面因子按行业分布对比', fontsize=16, fontweight='bold')
plt.tight_layout()
return plt
3.5 完整分析流程
以下是完整的分析流程,包括数据获取、因子计算、可视化生成:
python
def analyze_fundamental_factors():
"""
基本面因子分析主函数
"""
print("基本面因子计算入门分析")
print("=" * 70)
# 获取财务数据
print("\n1. 获取财务数据...")
df = generate_sample_financial_data()
print(f" 数据样本数: {len(df)} 家公司")
# 显示因子描述性统计
print("\n2. 基本面因子描述性统计:")
factor_cols = ['PE', 'PB', 'ROE', 'revenue_growth']
for factor in factor_cols:
factor_data = df[factor].dropna()
if len(factor_data) > 0:
print(f" {factor}: 平均值={factor_data.mean():.2f}, 中位数={factor_data.median():.2f}")
# 保存数据
df.to_csv("outputs/可视化/Day13_基本面因子计算结果.csv", index=False)
# 生成可视化图表
print("\n3. 生成可视化图表...")
for factor in ['PE', 'PB', 'ROE', 'revenue_growth']:
plt = plot_factor_distribution(df, factor, f'{factor}分布')
plt.savefig(f'outputs/可视化/Day13_{factor}_分布图.png', dpi=300)
plt.close()
plt = plot_factor_by_industry(df)
plt.savefig('outputs/可视化/Day13_因子行业分布图.png', dpi=300)
plt.close()
print("\n4. 分析完成!")
return df
4.1 行业对比分析
不同行业在基本面因子上呈现显著差异:
估值特征:
- 科技行业:高PE、高PB,反映市场对成长性的溢价
- 金融行业:低PE、低PB,反映行业成熟度高与杠杆特性
- 公用事业:稳定PE、中等PB,反映防御性与稳定现金流
盈利能力特征:
- 消费行业:稳定ROE,反映品牌护城河与稳定需求
- 能源行业:周期性ROE,受大宗商品价格影响显著
- 医药行业:持续高ROE,反映研发投入带来的技术壁垒
4.2 因子相关性分析
基本面因子之间存在复杂的相关关系:
PE与ROE的相关性:
- 一般情况下,高ROE公司享有估值溢价(PE较高)
- 但当ROE过高时,可能引发市场对可持续性的担忧
- 理想情况是"合理ROE + 合理PE",即PEG(PE/净利润增长率)适中
PB与ROE的相关性:
- 根据杜邦分析公式:ROE = 净利润率 × 总资产周转率 × 权益乘数
- PB反映市场对净资产质量的认可度
- 高ROE + 低PB是典型的价值投资标的特征
营收增长与盈利质量:
- 高营收增长应伴随毛利率稳定或提升
- "增收不增利"是危险信号,可能反映竞争加剧或成本失控
4.4 投资策略启示
价值投资框架:
- 寻找优质公司:ROE > 15%,且趋势稳定或上升
- 等待合理价格:PE < 行业平均水平,PB < 2
- 关注成长性:营收增长率 > 10%,净利润增长同步
风险警示信号:
- PE极高但ROE下滑:可能存在估值泡沫
- PB极低但ROE极低:可能存在"价值陷阱"
- 营收高增长但毛利率下滑:增长质量存疑
五、拓展思考:基本面因子在量化策略中的应用与局限性
5.1 进阶应用场景
多因子模型构建
将基本面因子与技术面因子、情绪面因子结合,构建更全面的选股模型:
python
# 多因子综合评分示例
def multi_factor_score(df):
"""
计算多因子综合得分
"""
# 标准化处理
factors = ['PE', 'PB', 'ROE', 'revenue_growth']
normalized = {}
for factor in factors:
if factor in df.columns:
# 归一化到0-10分
normalized[factor] = 10 * (df[factor] - df[factor].min()) / \
(df[factor].max() - df[factor].min())
# 赋予不同权重(示例)
weights = {
'ROE': 0.4, # 盈利能力最重要
'revenue_growth': 0.3, # 成长性次重要
'PE': 0.2, # 估值第三
'PB': 0.1 # 净资产质量最后
}
# 计算综合得分
total_score = pd.Series(0, index=df.index)
for factor, weight in weights.items():
if factor in normalized:
total_score += normalized[factor] * weight
return total_score
行业中性化处理
消除行业差异对因子的影响,更纯粹地比较公司质量:
python
def industry_neutralization(df, factor_col):
"""
行业中性化处理
"""
neutralized = pd.Series(index=df.index, dtype=float)
for industry in df['industry'].unique():
industry_mask = df['industry'] == industry
factor_values = df.loc[industry_mask, factor_col]
# 计算行业内的Z-score
mean_val = factor_values.mean()
std_val = factor_values.std()
if std_val > 0:
neutralized.loc[industry_mask] = (factor_values - mean_val) / std_val
else:
neutralized.loc[industry_mask] = 0
return neutralized
5.2 局限性分析与应对策略
局限性1:财报发布滞后
- 问题:财务报表按季度发布,存在1-3个月的滞后
- 影响:基于历史财报的因子无法反映最新经营状况
- 应对 :
- 结合高频数据(如月度经营数据)
- 使用分析师预期数据作为补充
- 关注管理层指引和行业调研信息
局限性2:会计政策差异
- 问题:不同公司、不同行业的会计处理方法不同
- 影响:直接比较原始财务数据可能产生误导
- 应对 :
- 进行财务数据标准化处理
- 使用现金流指标(受会计政策影响较小)
- 关注非GAAP调整后的财务数据
局限性3:财务数据操纵风险
- 问题:公司可能通过会计手段美化财务报表
- 影响:基于失真数据的因子分析结论不可靠
- 应对 :
- 增加财务质量检查(如应计利润分析)
- 关注审计意见和管理层诚信记录
- 结合非财务信息交叉验证
5.3 未来发展方向
机器学习在基本面分析中的应用
- 特征自动挖掘:利用算法发现传统分析忽略的有效指标
- 非线性关系建模:捕捉因子与股价间的复杂非线性关系
- 动态权重调整:根据市场环境变化自动调整因子权重
另类数据整合
- 供应链数据:反映公司实际经营活动的实时数据
- 舆情分析:通过NLP分析新闻、研报、社交媒体的情感倾向
- 卫星图像:观测工厂开工率、仓储物流等物理指标
六、学习要点与下步行动
6.1 今日核心收获
- 基本面因子分类:掌握盈利能力(ROE)、估值(PE、PB)、成长性(营收增长率)三大类核心指标
- 计算方法:学会用Python实现基本面因子的计算函数,处理真实或模拟财务数据
- 可视化分析:掌握因子分布、行业对比、相关性分析的专业图表生成方法
- 投资应用:理解基本面因子在价值投资框架中的实际应用价值
学习提示:基本面量化分析的核心在于理解指标背后的经济逻辑,而非单纯追求复杂的数学模型。建议在掌握基本方法后,重点培养对行业特性和商业模式的理解能力,这才是量化分析与价值投资的真正结合点。