35 上市公司净利润增长率的计算
35.1 引言增长率的价值发现功能
净利润增长率的重要性:
净利润增长率是衡量上市公司盈利能力和成长性的核心指标,在价值投资和成长投资中都具有关键作用。
理论背景:企业价值与增长
根据戈登增长模型(Gordon Growth Model),股票价值为:
\[ P_0 = \frac{D_1}{r - g} \]
其中: - \(P_0\): 当前股票价格 - \(D_1\): 下一期预期股息 - \(r\): 必要收益率(股权成本) - \(g\): 股息永续增长率
关键洞见: - 增长率越高,企业价值越大: g越接近r,股价越高 - 增长质量重于数量: 可持续的增长优于短期爆发 - 增长率递减: 随着企业成熟,增长率会逐步下降
净利润增长率的金融意义:
- 成长性评估:
- 识别高增长企业(成长股)
- 区分周期性增长与趋势性增长
- 评估增长可持续性
- 估值依据:
- DCF模型的关键输入
- PEG比率的核心要素
- 相对估值的基础
- 投资决策:
- 价值投资:低增长+低估值
- 成长投资:高增长+合理估值
- GARP策略:合理价格增长
- 业绩预警:
- 增长率放缓可能预示业绩拐点
- 负增长需警惕企业衰退
- 波动率反映经营风险
35.2 数据读取与预处理
35.2.1 财务数据获取
补充说明:上市公司财务报告体系
中国上市公司财务报告披露周期:
- 季度报告(Q1, Q2, Q3):
- 每季度结束后1个月内披露
- 包含简化的资产负债表、利润表
- 不需要审计
- 年度报告(Q4/年报):
- 会计年度结束后4个月内披露
- 包含完整的三张报表
- 必须经过审计
- 附详细的管理层讨论与分析
- 业绩快报与预告:
- 业绩快报:实际数据但未经审计
- 业绩预告:预计数据范围
- 时间早于正式报告
利润表的层次结构:
一、营业收入
减:营业成本
营业税金及附加
销售费用
管理费用
财务费用
-----------------------------------
二、营业利润(Operating Profit) ← 本章使用
加:营业外收入
减:营业外支出
-----------------------------------
三、利润总额(Total Profit)
减:所得税费用
-----------------------------------
四、净利润(Net Profit) ← 更常用
# =============================================================================
# 题目: 读取上市公司财务数据
# =============================================================================
# 本代码块演示如何从Excel文件读取上市公司财务数据。上市公司财务数据
# 通常以Excel格式公开披露,包含多个年度的利润表、资产负债表和现金流量表。
# 数据读取是财务分析的第一步,需要正确处理表头、索引和数据类型。
# ==================== 导入必要的库 ====================
import pandas as pd # 导入pandas库,用于数据处理和分析
import numpy as np # 导入numpy库,用于数值计算
import matplotlib.pyplot as plt # 导入matplotlib库,用于可视化
# ==================== 设置中文字体 ====================
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为黑体,避免中文乱码
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方块的问题
# ==================== 读取Excel文件 ====================
url = 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20230410/xls/1645298865123385344.xls' # 数据文件URL
df = pd.read_excel(url) # 使用pandas读取Excel文件,默认读取第一个sheet
# ==================== 输出原始数据预览 ====================
print('原始数据:') # 打印标题
print(df.head(10)) # 打印前10行数据,快速了解数据结构
print(f'\n数据类型: {type(df)}') # 确认数据类型为DataFrame
print(f'\n数据形状: {df.shape}') # 打印数据维度(行数,列数)代码深度解析:
pd.read_excel()参数:- 默认读取第一个sheet
header=0: 第一行为列名index_col: 指定索引列
- 在线数据读取:
- 支持HTTP/HTTPS URL
- 自动处理编码
- 适合快速原型开发
- 数据结构检查:
shape: (行数, 列数)head(): 前几行数据预览type(): 确认DataFrame类型
35.2.2 数据提取与转换
补充说明:时间序列的索引处理
时间序列分析的关键步骤:
- 索引设置:
set_index(): 将某列设为索引- 索引必须是唯一的
- 时间索引便于切片操作
- 索引类型:
- 字符串: ‘2020’, ‘2021’
- 整数: 2020, 2021
- Datetime: 2020-01-01(推荐)
- 索引排序:
sort_index(): 按索引排序- 升序或降序
- 确保时间顺序正确
# 注:该代码块读取远程平台数据文件,且变量名与下方代码不匹配,渲染时无法正确执行
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd # 导入Pandas数据分析库
#读取excel文件
df = pd.read_excel('https://huoran.oss-cn-shenzhen.aliyuncs.com/20230410/xls/1645298865123385344.xls')
#把index设置为Unnamed: 0
df.set_index('Unnamed: 0', inplace=True)
#提取index为“四、营业利润(亿元)”的行
df = df.loc['四、营业利润(亿元)']
#输出数据格式
print(type(df))
#修改index为当前index的前4个字符
df.index = df.index.str[:4]
#将index转换为int类型
df.index = df.index.astype(int)
#将index从小到大排序
df.sort_index(inplace=True)
#计算净利润增长率
result = df.pct_change()
#输出结果
print(result)代码深度解析:
loc[]索引器:- 基于标签的索引
df.loc[row_label]: 选择行- 支持切片和布尔索引
- 字符串处理:
.str[:4]: 切片前4个字符.astype(int): 类型转换- 链式操作提高效率
- 数据清洗:
pd.to_numeric(): 转换为数值errors='coerce': 无法转换的设为NaN- 便于后续处理缺失值
35.3 计算增长率
35.3.1 增长率计算方法
理论背景:增长率的各种计算方式
- 简单增长率: \[ g_t = \frac{X_t - X_{t-1}}{X_{t-1}} \]
- 适用于:任意相邻两期
- 优点:计算简单
- 缺点:受基数影响
- 复合年均增长率(CAGR): \[ \text{CAGR} = \left(\frac{X_n}{X_0}\right)^{\frac{1}{n}} - 1 \]
- 适用于:长期平均增长
- 优点:平滑短期波动
- 缺点:忽略中间路径
- 对数差分增长率: \[ g_t = \ln(X_t) - \ln(X_{t-1}) \]
- 适用于:连续复利假设
- 优点:对称性,可加性
- 缺点:近似值
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行
# =============================================================================
# 题目: 计算净利润增长率
# =============================================================================
# 本代码块演示如何使用pandas计算时间序列的增长率。增长率计算是财务分析
# 的核心技能,我们需要掌握不同的计算方法并理解它们的应用场景。
# ==================== 方法1:使用pct_change()计算增长率 ====================
# pct_change()计算百分比变化:(当前期 - 上一期) / 上一期
# 简单增长率公式: R_t = (X_t - X_{t-1}) / X_{t-1}
# periods参数默认为1,表示与前一期相比
growth_rate = profit.pct_change() # 计算百分比变化,返回增长率序列
# ==================== 输出增长率(小数形式) ====================
print('净利润增长率(小数形式):') # 打印标题
print(growth_rate) # 打印增长率序列,第一个值为NaN(因为没有上期数据)
# ==================== 转换为百分比形式 ====================
growth_rate_pct = growth_rate * 100 # 将小数转换为百分比形式
# ==================== 输出增长率(百分比形式) ====================
print('\n净利润增长率(百分比形式):') # 打印标题
for year, rate in growth_rate_pct.items(): # 遍历每一年的增长率
if not pd.isna(rate): # 跳过NaN值(第一年)
# 使用格式化字符串输出:+号表示正数,-号表示负数
# :+.2f表示带符号,保留2位小数
print(f'{year}年: {rate:+.2f}%') # 格式化输出增长率
# ==================== 方法2:手动计算验证 ====================
# 手动实现增长率计算,验证pct_change()的结果
growth_rate_manual = pd.Series(index=profit.index, dtype=float) # 创建空Series存储结果
for i in range(1, len(profit)): # 从第二个数据点开始(索引为1)
# 手动计算增长率: (本期 - 上期) / 上期
growth_rate_manual.iloc[i] = (profit.iloc[i] - profit.iloc[i-1]) / profit.iloc[i-1]
# ==================== 输出手动计算结果 ====================
print('\n验证-手动计算:') # 打印标题
for year, rate in growth_rate_manual.items(): # 遍历手动计算的结果
if not pd.isna(rate): # 跳过NaN值
print(f'{year}年: {rate*100:+.2f}%') # 格式化输出
# ==================== 验证两种方法一致性 ====================
# np.allclose()比较两个数组是否在容差范围内相等
# 这用于验证pct_change()和手动计算的结果是否一致
print(f'\n两种方法一致: {np.allclose(growth_rate.dropna(), growth_rate_manual.dropna())}') # 验证结果代码深度解析:
pct_change()函数:- 计算百分比变化
- 默认
periods=1 - 第一个值为NaN(无上期数据)
- 格式化输出:
{:+.2f}: 带符号,2位小数+表示正数-表示负数
- NaN处理:
- 第一个值为NaN
- 用
pd.isna()检查 - 用
dropna()删除
35.3.2 复合年均增长率(CAGR)
补充说明:长期增长率的度量
CAGR(Compound Annual Growth Rate)假设投资按恒定增长率复利增长,更符合长期投资视角。
\[ \text{CAGR} = \left(\frac{V_{\text{终值}}}{V_{\text{初值}}}\right)^{\frac{1}{n}} - 1 \]
其中: - \(V_{\text{终值}}\): 期末值 - \(V_{\text{初值}}\): 期初值 - \(n\): 年数
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行
# =============================================================================
# 题目: 计算复合年均增长率(CAGR)
# =============================================================================
# 本代码块演示如何计算复合年均增长率(CAGR)。CAGR是衡量长期投资表现
# 的标准指标,它假设投资按恒定增长率复利增长,消除了短期波动的影响。
# ==================== 删除NaN值 ====================
profit_valid = profit.dropna() # 删除缺失值,确保计算准确
# ==================== 计算CAGR ====================
if len(profit_valid) >= 2: # 确保至少有2个数据点
# 提取期初值和期末值
start_value = profit_valid.iloc[0] # 期初值(第一个数据点)
end_value = profit_valid.iloc[-1] # 期末值(最后一个数据点)
n_years = len(profit_valid) - 1 # 年份数=数据点数-1
# CAGR公式: (期末值 / 期初值)^(1/年份数) - 1
cagr = (end_value / start_value) ** (1 / n_years) - 1 # 计算复合年均增长率
# ==================== 输出CAGR计算结果 ====================
print('复合年均增长率(CAGR):') # 打印标题
print(f'期初值: {start_value:.2f}亿元') # 打印期初值,保留2位小数
print(f'期末值: {end_value:.2f}亿元') # 打印期末值,保留2位小数
print(f'年份数: {n_years}年') # 打印年份数
print(f'CAGR: {cagr*100:.2f}%') # 打印CAGR,转换为百分比
# ==================== 对比平均增长率 ====================
# 对比CAGR和简单平均增长率
avg_growth_rate = growth_rate.mean() # 计算简单平均增长率
print(f'\n简单平均增长率: {avg_growth_rate*100:.2f}%') # 打印简单平均
print(f'差异: {(cagr - avg_growth_rate)*100:.2f}个百分点') # 计算两者差异
# ==================== 解读CAGR ====================
print('\n解读:') # 打印标题
print('- CAGR假设每年按相同增长率复利增长') # CAGR的含义
print('- 简单平均忽略复利效应') # 简单平均的特点
print('- 通常CAGR < 简单平均(除非增长率恒定)') # 两者关系35.4 结果分析与可视化
35.4.1 增长率统计分析
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行
# =============================================================================
# 题目: 增长率统计分析
# =============================================================================
# 本代码块演示如何对增长率进行统计分析,包括均值、最大值、最小值、标准差
# 等。这些统计量帮助我们了解企业增长的稳定性和波动性。
# ==================== 统计分析 ====================
valid_years = growth_rate.dropna() # 删除NaN值,得到有效的增长率序列
print(f'有效年份: {len(valid_years)}') # 打印有效年份数量
print(f'平均增长率: {valid_years.mean()*100:.2f}%') # 打印平均增长率
print(f'最大增长率: {valid_years.max()*100:.2f}%') # 打印最大增长率
print(f'最小增长率: {valid_years.min()*100:.2f}%') # 打印最小增长率
print(f'增长率标准差: {valid_years.std()*100:.2f}%') # 打印增长率标准差(波动性)
# ==================== 增长率分布 ====================
print('\n增长率分布:') # 打印标题
# 统计正增长年份和负增长年份
positive_years = (valid_years > 0).sum() # 计算正增长年份数量
negative_years = (valid_years < 0).sum() # 计算负增长年份数量
print(f'正增长年份: {positive_years}年 ({positive_years/len(valid_years)*100:.1f}%)') # 打印正增长占比
print(f'负增长年份: {negative_years}年 ({negative_years/len(valid_years)*100:.1f}%)') # 打印负增长占比
# ==================== 高增长年份统计 ====================
# 高增长年份(>20%)
high_growth = (valid_years > 0.20).sum() # 统计增长率大于20%的年份数
print(f'高增长年份(>20%): {high_growth}年') # 打印高增长年份数
# ==================== 亏损年份统计 ====================
# 亏损年份(<0)
loss_years = (valid_years < 0).sum() # 统计负增长年份数
print(f'亏损年份: {loss_years}年') # 打印亏损年份数35.4.2 增长率可视化
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行
# =============================================================================
# 题目: 净利润与增长率双轴图
# =============================================================================
# 本代码块演示如何绘制双y轴图,同时展示营业利润和增长率。双y轴图适用于
# 两个变量量纲不同但需要对比分析的情况,例如绝对值(利润)和相对值(增长率)。
# ==================== 创建图形 ====================
fig, ax1 = plt.subplots(figsize=(14, 8)) # 创建图形,尺寸14×8英寸
# ==================== 左轴:营业利润 ====================
color1 = 'steelblue' # 定义左轴颜色
ax1.set_xlabel('年份', fontsize=12) # 设置x轴标签
ax1.set_ylabel('营业利润(亿元)', fontsize=12, color=color1) # 设置左y轴标签和颜色
# 绘制营业利润折线图
line1 = ax1.plot(profit.index, profit.values, color=color1, marker='o',
linewidth=2.5, label='营业利润')
ax1.tick_params(axis='y', labelcolor=color1) # 设置左y轴刻度标签颜色
ax1.grid(True, alpha=0.3, linestyle='--') # 显示网格,虚线样式
# ==================== 右轴:增长率 ====================
ax2 = ax1.twinx() # 创建共享x轴的第二个y轴
color2 = 'coral' # 定义右轴颜色
ax2.set_ylabel('增长率(%)', fontsize=12, color=color2) # 设置右y轴标签和颜色
# 绘制增长率折线图
line2 = ax2.plot(growth_rate_pct.index, growth_rate_pct.values, color=color2,
marker='s', linewidth=2.5, label='增长率')
ax2.tick_params(axis='y', labelcolor=color2) # 设置右y轴刻度标签颜色
ax2.axhline(y=0, color='gray', linestyle='--', linewidth=1, alpha=0.7) # 添加0参考线
# ==================== 添加阴影区域标记负增长 ====================
# fill_between()在两个y值之间填充颜色
ax2.fill_between(growth_rate_pct.index, 0, growth_rate_pct.values,
where=(growth_rate_pct.values < 0), # 条件:增长率小于0
color='red', alpha=0.2, label='负增长区间') # 红色半透明填充
# ==================== 标题和图例 ====================
plt.title('上市公司营业利润与增长率趋势', fontsize=16, pad=20) # 设置主标题
lines = line1 + line2 # 合并两条线的图例句柄
labels = [l.get_label() for l in lines] # 提取图例标签
ax1.legend(lines, labels, loc='upper left', fontsize=11) # 显示图例,位置在左上角
# ==================== 标注最高和最低点 ====================
max_year = growth_rate_pct.idxmax() # 找到最大增长率对应的年份
min_year = growth_rate_pct.idxmin() # 找到最小增长率对应的年份
max_value = growth_rate_pct[max_year] # 获取最大增长率值
min_value = growth_rate_pct[min_year] # 获取最小增长率值
# 标注最高点
ax2.annotate(f'最高: {max_value:.1f}%', # 注释文本
xy=(max_year, max_value), # 箭头指向的坐标
xytext=(max_year, max_value+5), # 文本位置
arrowprops=dict(facecolor='black', shrink=0.05, width=1.5, headwidth=8), # 箭头样式
fontsize=10, ha='center') # 字体大小和对齐方式
# 标注最低点
ax2.annotate(f'最低: {min_value:.1f}%', # 注释文本
xy=(min_year, min_value), # 箭头指向的坐标
xytext=(min_year, min_value-5), # 文本位置
arrowprops=dict(facecolor='black', shrink=0.05, width=1.5, headwidth=8), # 箭头样式
fontsize=10, ha='center') # 字体大小和对齐方式
fig.tight_layout() # 自动调整布局,避免元素重叠
plt.show() # 显示图形代码深度解析:
- 双y轴图(
twinx):ax1: 主y轴(利润)ax2: 次y轴(增长率)- 解决量纲不同的问题
- 填充区域(
fill_between):where: 条件判断- 标记负增长区域
- 视觉强调亏损年份
- 注释(
annotate):- 标注极值点
- 箭头指向
- 文字说明
35.4.3 增长趋势分解
理论背景:增长的趋势-周期分解
时间序列可以分解为: \[ Y_t = T_t + C_t + S_t + \varepsilon_t \]
其中: - \(T_t\): 趋势项(Trend): 长期方向 - \(C_t\): 循环项(Cycle): 多年波动 - \(S_t\): 季节项(Seasonal): 年内波动 - \(\varepsilon_t\): 随机项(Noise): 不可预测成分
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行
# =============================================================================
# 题目: 增长趋势分解
# =============================================================================
# 本代码块演示如何使用移动平均分解增长率的趋势和波动成分。移动平均是
# 时间序列分析的基础工具,可以平滑短期波动,揭示长期趋势。
# ==================== 计算移动平均(平滑短期波动) ====================
ma_window = 3 # 设置移动平均窗口为3年
# rolling()创建滚动窗口,center=True使窗口居中
growth_ma = growth_rate_pct.rolling(window=ma_window, center=True).mean() # 计算3年移动平均
# ==================== 可视化趋势分解 ====================
fig, axes = plt.subplots(2, 1, figsize=(14, 10)) # 创建2×1子图布局
# 子图1:原始增长率vs移动平均
axes[0].plot(growth_rate_pct.index, growth_rate_pct.values,
marker='o', linewidth=2, label='原始增长率', alpha=0.7) # 绘制原始增长率
axes[0].plot(growth_ma.index, growth_ma.values,
linewidth=3, label=f'{ma_window}年移动平均', color='red') # 绘制移动平均线
axes[0].axhline(y=0, color='gray', linestyle='--', linewidth=1) # 添加0参考线
axes[0].set_title('增长率趋势分解', fontsize=14) # 设置标题
axes[0].set_ylabel('增长率(%)', fontsize=12) # 设置y轴标签
axes[0].legend(fontsize=11) # 显示图例
axes[0].grid(True, alpha=0.3) # 显示网格
# 子图2:利润趋势
axes[1].plot(profit.index, profit.values, marker='s', linewidth=2.5, color='steelblue') # 绘制营业利润
axes[1].set_title('营业利润趋势', fontsize=14) # 设置标题
axes[1].set_xlabel('年份', fontsize=12) # 设置x轴标签
axes[1].set_ylabel('营业利润(亿元)', fontsize=12) # 设置y轴标签
axes[1].grid(True, alpha=0.3) # 显示网格
# ==================== 添加趋势线 ====================
# 使用二次多项式拟合利润趋势
z = np.polyfit(profit.index, profit.values, 2) # 二次多项式拟合
p = np.poly1d(z) # 创建多项式函数
axes[1].plot(profit.index, p(profit.index), '--', color='red', linewidth=2,
label='趋势线(二次)') # 绘制趋势线
axes[1].legend(fontsize=11) # 显示图例
plt.tight_layout() # 调整布局
plt.show() # 显示图形
# ==================== 增长阶段识别 ====================
print('\n增长阶段分析:') # 打印标题
if len(growth_ma.dropna()) > 0: # 确保有有效的移动平均数据
recent_ma = growth_ma.dropna().iloc[-1] # 获取最近的移动平均值
print(f'最近{ma_window}年平均增长率: {recent_ma:.2f}%') # 打印近期平均增长率
# ==================== 判断增长阶段 ====================
if recent_ma > 20: # 平均增长率大于20%
stage = '高速增长期' # 判断为高速增长期
elif recent_ma > 10: # 平均增长率大于10%
stage = '稳定增长期' # 判断为稳定增长期
elif recent_ma > 0: # 平均增长率大于0
stage = '缓慢增长期' # 判断为缓慢增长期
else: # 平均增长率小于等于0
stage = '衰退期' # 判断为衰退期
print(f'当前阶段: {stage}') # 打印当前增长阶段35.5 增长率预测
35.5.1 简单趋势预测
补充说明:外推预测的局限性
基于历史增长率预测未来需要注意:
- 均值回归:
- 极高增长率难以持续
- 负增长可能反转
- 长期趋于GDP增速
- 基数效应:
- 基数小,增长率高
- 基数大,增长率低
- 需要结合绝对值
- 行业周期:
- 成长期:高增长
- 成熟期:稳定增长
- 衰退期:负增长
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行
# =============================================================================
# 题目: 基于历史数据的增长率预测
# =============================================================================
# 本代码块演示如何基于历史增长率进行简单的外推预测。需要注意的是,
# 这种预测方法假设历史模式会延续,实际应用中需要结合行业分析和
# 宏观环境判断。
# ==================== 方法1:使用最近3年平均增长率预测 ====================
forecast_years = 3 # 预测未来3年
recent_growth = growth_rate_pct.dropna().tail(forecast_years).mean() # 计算最近3年平均增长率
# ==================== 方法2:使用整体CAGR预测 ====================
last_value = profit.dropna().iloc[-1] # 获取最后一年的利润值
forecast_values = [] # 创建空列表,存储预测值
print('未来' + str(forecast_years) + '年预测:') # 打印标题
print(f'\n方法1(最近{forecast_years}年平均):') # 打印方法说明
print(f' 预测增长率: {recent_growth:.2f}%') # 打印预测增长率
# ==================== 计算预测值 ====================
for i in range(1, forecast_years + 1): # 循环预测未来3年
# 使用复利公式: 预测值 = 期初值 × (1 + 增长率)^年数
forecast = last_value * (1 + recent_growth / 100) ** i # 计算第i年的预测值
forecast_values.append(forecast) # 将预测值添加到列表
print(f' 第{i}年: {forecast:.2f}亿元') # 打印第i年的预测值
# ==================== 可视化预测 ====================
fig, ax = plt.subplots(figsize=(12, 7)) # 创建图形
# 历史数据
ax.plot(profit.index, profit.values, marker='o', linewidth=2.5,
label='历史数据', color='steelblue') # 绘制历史数据折线图
# 预测数据
forecast_index = np.arange(profit.index[-1] + 1, profit.index[-1] + forecast_years + 1) # 生成预测年份索引
ax.plot(forecast_index, forecast_values, marker='s', linewidth=2.5,
linestyle='--', label='预测数据', color='coral') # 绘制预测数据折线图(虚线)
# 置信区间(假设±20%误差)
upper_bound = [v * 1.2 for v in forecast_values] # 计算上界(预测值×1.2)
lower_bound = [v * 0.8 for v in forecast_values] # 计算下界(预测值×0.8)
ax.fill_between(forecast_index, lower_bound, upper_bound,
color='coral', alpha=0.2, label='预测区间(±20%)') # 填充置信区间
ax.set_title('营业利润趋势外推预测', fontsize=14) # 设置标题
ax.set_xlabel('年份', fontsize=12) # 设置x轴标签
ax.set_ylabel('营业利润(亿元)', fontsize=12) # 设置y轴标签
ax.legend(fontsize=11) # 显示图例
ax.grid(True, alpha=0.3) # 显示网格
plt.tight_layout() # 调整布局
plt.show() # 显示图形
# ==================== 风险提示 ====================
print('\n警告:') # 打印标题
print('- 预测基于历史数据,未来可能不同') # 风险提示1
print('- 假设增长率恒定,实际会有波动') # 风险提示2
print('- 未考虑宏观环境和行业变化') # 风险提示3
print('- 仅供参考,不构成投资建议') # 免责声明35.6 投资应用案例
35.6.1 PEG比率分析
理论背景:PEG比率
PEG比率(Price/Earnings-to-Growth Ratio)由彼得·林奇提出,用于评估成长股的估值合理性:
\[ \text{PEG} = \frac{\text{PE}}{\text{增长率}} = \frac{P/E}{g} \]
解读标准: - PEG < 1: 被低估 - PEG = 1: 合理估值 - PEG > 1: 被高估
优势: - 考虑了增长因素 - 适合比较不同成长性的公司 - 避免”价值陷阱”
局限: - 增长率预测困难 - 对负增长不适用 - 忽略了增长质量
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行
# =============================================================================
# 题目: PEG比率计算与分析
# =============================================================================
# 本代码块演示如何计算PEG比率并进行估值判断。PEG比率是成长股估值的核心
# 指标,它将市盈率与增长率结合起来,更全面地评估股票的估值水平。
# ==================== 假设当前股价和每股收益(EPS) ====================
stock_price = 50 # 假设当前股价为50元
current_eps = 2 # 假设每股收益为2元
# ==================== 计算PE比率 ====================
# PE比率 = 股价 / 每股收益
pe_ratio = stock_price / current_eps # 计算市盈率
# ==================== 使用CAGR作为预期增长率 ====================
expected_growth = cagr * 100 # 将CAGR转换为百分比形式
# ==================== 计算PEG比率 ====================
# PEG = PE比率 / 增长率
# 注意:当增长率为负时,PEG比率无意义
peg_ratio = pe_ratio / expected_growth if expected_growth > 0 else np.nan # 计算PEG比率
# ==================== 输出PEG分析结果 ====================
print('PEG比率分析:') # 打印标题
print(f'股价: {stock_price}元') # 打印股价
print(f'每股收益(EPS): {current_eps}元') # 打印每股收益
print(f'PE比率: {pe_ratio:.2f}') # 打印市盈率
print(f'预期增长率(CAGR): {expected_growth:.2f}%') # 打印预期增长率
# 如果PEG不是NaN,打印PEG值;否则打印"无定义"
print(f'PEG比率: {peg_ratio:.2f}' if not np.isnan(peg_ratio) else 'PEG比率: 无定义(负增长)')
# ==================== 估值判断 ====================
if not np.isnan(peg_ratio): # 确保PEG比率有效
print('\n估值判断:') # 打印标题
if peg_ratio < 0.8: # PEG小于0.8
valuation = '被低估' # 判断为低估
advice = '建议买入' # 建议买入
elif peg_ratio < 1.2: # PEG在0.8到1.2之间
valuation = '合理估值' # 判断为合理估值
advice = '建议持有' # 建议持有
else: # PEG大于等于1.2
valuation = '被高估' # 判断为高估
advice = '建议谨慎' # 建议谨慎
print(f'估值水平: {valuation}') # 打印估值水平
print(f'投资建议: {advice}') # 打印投资建议
# ==================== 情景分析 ====================
print('\n情景分析(不同增长率下的PEG):') # 打印标题
# 定义不同的增长率情景
growth_scenarios = [5, 10, 15, 20, 25, expected_growth] # 增长率情景(%)列表
for g in growth_scenarios: # 遍历各情景
peg_scenario = pe_ratio / g # 计算该情景下的PEG比率
# 根据PEG值判断估值状态
status = '低估' if peg_scenario < 1 else '合理' if peg_scenario < 1.2 else '高估' # 判断估值状态
print(f'增长率={g:5.1f}%: PEG={peg_scenario:.2f} ({status})') # 打印情景分析结果35.6.2 增长质量评估
补充说明:如何评估增长质量
高质量增长的特征: 1. 可持续性: 来源于核心竞争力 2. 盈利性: 增长带来利润率提升 3. 现金流: 利润增长伴随现金流改善 4. 稳定性: 增长率波动较小 5. 内源性: 主要靠自身造血,而非并购
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行
# =============================================================================
# 题目: 增长质量综合评估
# =============================================================================
# 本代码块演示如何从多个维度评估企业增长质量。增长质量比增长率本身更重要,
# 高质量的增长可持续,低质量的增长难以维持。
# ==================== 收集增长相关指标 ====================
growth_metrics = {
'平均增长率': growth_rate.mean() * 100, # 计算平均增长率
'增长率标准差': growth_rate.std() * 100, # 计算增长率标准差(波动性)
'正增长概率': (growth_rate > 0).sum() / len(growth_rate.dropna()) * 100, # 计算正增长年份占比
'CAGR': cagr * 100, # 复合年均增长率
'最新增长率': growth_rate_pct.iloc[-1] # 最近的增长率
}
# ==================== 转换为DataFrame ====================
df_metrics = pd.DataFrame(list(growth_metrics.items()), # 将字典转换为列表
columns=['指标', '值(%)']) # 设置列名
# ==================== 输出增长质量指标 ====================
print('增长质量评估:') # 打印标题
print(df_metrics.to_string(index=False)) # 打印指标表,不显示索引
# ==================== 计算综合得分 ====================
# 1. 稳定性得分(标准差越小,得分越高)
# 标准差最大按50考虑,标准差越小得分越高
stability_score = 100 - min(growth_metrics['增长率标准差'], 50) / 50 * 100 # 计算稳定性得分
# 2. 持续性得分(正增长概率)
consistency_score = growth_metrics['正增长概率'] # 正增长概率即持续性得分
# 3. 动能得分(最新增长率)
# 最新增长率最大按30考虑,超过30按30算
momentum_score = max(min(growth_metrics['最新增长率'], 30) / 30 * 100, 0) # 计算动能得分
# ==================== 综合得分(加权平均) ====================
quality_score = (stability_score * 0.3 + # 稳定性权重30%
consistency_score * 0.4 + # 持续性权重40%
momentum_score * 0.3) # 动能权重30%
# ==================== 输出得分 ====================
print(f'\n增长质量得分:') # 打印标题
print(f'稳定性得分: {stability_score:.1f}/100') # 打印稳定性得分
print(f'持续性得分: {consistency_score:.1f}/100') # 打印持续性得分
print(f'动能得分: {momentum_score:.1f}/100') # 打印动能得分
print(f'综合得分: {quality_score:.1f}/100') # 打印综合得分
# ==================== 评级 ====================
if quality_score >= 80: # 综合得分>=80
grade = '优秀 (A)' # 评级为优秀
elif quality_score >= 60: # 综合得分>=60
grade = '良好 (B)' # 评级为良好
elif quality_score >= 40: # 综合得分>=40
grade = '一般 (C)' # 评级为一般
else: # 综合得分<40
grade = '较差 (D)' # 评级为较差
print(f'增长质量评级: {grade}') # 打印最终评级