【财报分析】使用 Pandas 分析资产负债表

由于最近一直在为大家更新机器学习算法的帖子,未避免我们对 Pandas 一些用法的生疏,小鱼精心准备了两篇 Pandas 系列的文章,将分别使用 Pandas 来分析上市公司的资产负债表、利润表和现金流量表。

本篇是 Pandas 分析财报系列文章的第一篇,通过本篇文章的学习,相信不仅可以加深大家对 Pandas 的熟练程度,还会收获财报金融方面的一些技巧~

首先,下载上市公司的资产负债表。同花顺 http://stockpage.10jqka.com.cn/ 个股搜索个股名称,找到【财务分析】,点击【财务指标】:

找到【财务指标】部分,依次点击【资产负债表】、【按年度】、【导出数据】。

同样的方式,可以把下方的利润表和现金流量表也下载下来,供后续分析使用。下面是小鱼下载好的三大报表:

读取资产负债表

注:下载好之后,用 Excel 打开浏览一下再用 Pandas 读,否则可能会遇到读取失败。

首先,导入工具包,并进行 pandas 和 matplotlib 的一些基本设置,定义常量 DEBT 表示资产负债表:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

pd.set_option('display.float_format', lambda x: '%.4f' % x)
pd.set_option('mode.chained_assignment', None)

# 解决绘图中显示中文的问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

DEBT = '600xxx_debt_year.xls'
BENEFIT = '600xxx_benefit_year.xls'
CASH = '600xxx_cash_year.xls'

将重复用到的代码,定义成辅助函数:

def format_thousandth(arr):
    """将 arr 或 Series 中的数字使用千分位表示"""
    return arr.apply(lambda x:format(x, ',.0f'))
    
def format_percentage(arr):
    """将 arr 或 Series 中的数字使用百分之表示,小数点后保留 2 位"""
    return arr.apply(lambda x:format(x, '.2%'))

def plot_show(t, title='', ylabel='单位:亿', kind='line', y_format='hundred million'):
    """绘图"""
    t.plot(kind=kind)
    
    y_max = t.max()
    y_min = t.min()
    while type(y_max) == pd.Series:
        y_max = y_max.max()
        y_min = y_min.min()
    
    if y_min > 0:
        y_min = 0
    
    num_yticks = np.linspace(y_min, y_max, 8)
    if y_format == 'hundred million':
        plt.yticks(num_yticks, map(lambda x:round(x/100000000,2), num_yticks))
    else:
        plt.yticks(num_yticks, map(lambda x:format(x,'.2%'), num_yticks))
        
    if kind == 'line':
        plt.xticks(t.index, t.index)
    
    plt.ylabel(ylabel)
    plt.title(title)
    plt.savefig(title+'.png')

读取资产债表

debt_df = pd.read_excel(DEBT, sheet_name='Worksheet', header=1, index_col=0)
debt_df.dropna(inplace=True)
debt_df.replace({'--': 0}, inplace=True)
debt_df = debt_df.T[:6][::-1]
debt_df.columns.name = '年份'
debt_df.apply(format_thousandth)
debt_df.T

小鱼只读取了最近 6 年的资产负债表数据:

分析资产负债表

1、分析总资产,了解公司实力及扩张能力

总资产规模代表了一家公司掌控的资源规模,也就是这家公司的实力。一般情况下,总资产规模在行业中的排名可以反映出一家公司在行业中的地位。总资产排名第一的公司一般就是这个行业中的老大。

截止 2022 年 2 月 18 日,A 股 4140 家上市公司中,总资产规模大于 500 亿有 354 家,总资产规模大于 100 亿有 1188 家,总资产规模大于 50 亿有 1937 家。

选取总资产,并计算总资产的增长率:

t1 = pd.DataFrame(index=debt_df.index, columns=['资产合计(元)', '总资产增长率'])
t1['资产合计(元)'] = debt_df['资产合计(元)']
t1['总资产增长率'] = debt_df['资产合计(元)'].pct_change()

pd.merge(
    t1.loc[:,['资产合计(元)']].apply(format_thousandth),
    t1.loc[:,['总资产增长率']].apply(format_percentage),
    left_index=True,
    right_index=True
).T

总资产规模及增长率:

以柱形图展示总资产规模:

plot_show(t1['资产合计(元)'], title='资产合计', kind='bar')

该公司的总资产近 6 年一直处于增长之中,2020 年总资产规模达到了 2000 多亿。通过折线图进一步观察总资产增长率:

plot_show(t1['总资产增长率'],title='总资产增长率', ylabel='', y_format='p')

总资产增长率:大于 10% 则公司处于扩张之中,成长性较好;小于 0% 公司很可能处于收缩或衰退之中。

2、看资产负债率,了解公司的偿债风险

通过资产规模和增长率的分析,我们发现一家公司资产实力雄厚,并且总资产的增长率在 10% 以上,公司处于快速扩张之中。但是,总资产在增加,可能是负债在增加,也可能是所有者权益在增加。

注:总资产 = 总负债(和别人借的) + 所有者权益(股东的钱),负债和所有者权益解释了钱从哪里来,总资产解释了钱都流向了哪儿。

接下来,我们分析资产负债率,来排除偿债风险。

t2 = debt_df[['负债合计(元)','资产合计(元)']]
t2['资产负债率'] = debt_df['负债合计(元)'] / debt_df['资产合计(元)']

pd.merge(
    t2[['负债合计(元)','资产合计(元)']].apply(format_thousandth),
    t2[['资产负债率']].apply(format_percentage),
    left_index=True,
    right_index=True
).T

近 6 年的资产负债率:

以柱形图展示资产负债率:

plot_show(t2['资产负债率'], title='资产负债率', ylabel='', kind='bar', y_format='p')

资产负债率:非金融、行地产等行业,资产负债率大于 70%,发生债务危机的可能性较大;小于 40%,基本没有偿债风险;40%~60% 之间偿债风险较小,但在特殊情况下依然可能发生偿债危机。

3、看有息负债和准货币资金,排除偿债风险

某公司的资产负债率很高,并且在逐年增加,并不一定代表偿债风险在增加。如果负债中大多数都是经营性负债(无息),反而说明该公司在上下游的话语权很强。

下面,我们看看兜里的钱够不够还有息负债。计算近 6 年的准货币资金和有息负债:

t3 = pd.DataFrame(index=debt_df.index, columns=[
    '货币资金(元)', '交易性金融资产(元)', '其他流动资产里的理财产品', '其他流动资产里的结构性存款', '准货币资金', '短期借款(元)', 
    '一年内到期的非流动负债(元)', '长期借款(元)', '应付债券(元)', '长期应付款', '有息负债总额', 
    '总货币资金与有息负债之差'])

t3[['货币资金(元)', '交易性金融资产(元)','短期借款(元)', '一年内到期的非流动负债(元)', '长期借款(元)', '应付债券(元)']] = \
debt_df[['货币资金(元)', '交易性金融资产(元)','短期借款(元)', '一年内到期的非流动负债(元)', '长期借款(元)', '应付债券(元)']]

# 下方数据需要在年报中确认
t3['其他流动资产里的理财产品'] = [0,0,0,0,0,0]
t3['其他流动资产里的结构性存款'] = [0,0,0,0,0,0]
t3['长期应付款'] = [0,0,0,0,0,0]

t3['准货币资金']=t3[['货币资金(元)','交易性金融资产(元)','其他流动资产里的理财产品','其他流动资产里的结构性存款']].sum(axis=1)
t3['有息负债总额']=t3[['短期借款(元)','一年内到期的非流动负债(元)','长期借款(元)','应付债券(元)','长期应付款']].sum(axis=1)
t3['总货币资金与有息负债之差'] = t3['准货币资金'] - t3['有息负债总额']
t3.apply(format_thousandth).T

其他流动资产里的理财产品:在其他流动资产的注释中查找理财产品,如果没有理财产品,此项的金额为 0。

其他流动资产里的结构性存款:在其他流动资产的注释中查找结构性存款,如果没有结构性存款,此项的金额为 0。

长期应付款:结合长期应付款的注释,判断是有息负债还是无息负债。

某公司连续 6 年的准货币资金和有息负债情况:

以柱形图展示有息负债和准货币资金:

plot_show(t3[['准货币资金','有息负债总额']], title='准货币资金与有息负债', kind='bar')

准货币资金与有息负债之差:大于0,无偿债风险;小于0,有偿债风险。

异常情况:准货币资金和短期借款或长期借款的金额都很大,很可能企业实际没有钱,后期风险很大。

4、看“应付预收”减“应收预付”的差额,了解公司的竞争优势

应付预收属于公司的经营性负债,是无偿占用别人的资金。金额越大,代表公司的竞争力越强,行业地位越高。应收预付属于公司的资产,即资金被别人占用了。金额越小,代表公司的竞争力越强,行业地位越高。

计算公式:(应付账款+应付票据+预收款项+合同负债)-(应收账款+应收票据+预付款项+合同资产+应收款项融资)。有的公司导不出来应收款项融资这行数据,需要手动填入。

t4 = pd.DataFrame(index=debt_df.index, columns=[
    '其中:应付票据(元)', '应付账款(元)', '预收款项(元)', '合同负债(元)', 
    '应付与预收合计', '其中:应收票据(元)', '合同资产', '应收款项融资', '应收账款(元)', 
    '预付款项(元)', '应收与预付合计', '应付预收减应收预付的差额'])
t4[['其中:应付票据(元)', '应付账款(元)', '预收款项(元)', '合同负债(元)','其中:应收票据(元)',
    '应收账款(元)', '预付款项(元)']] = \
debt_df[['其中:应付票据(元)', '应付账款(元)', '预收款项(元)', '合同负债(元)','其中:应收票据(元)',
    '应收账款(元)', '预付款项(元)']]

t4['合同资产'] = [0,0,0,0,0,0]
t4['应收款项融资'] = [0,0,0,4066653238,3350585849,3085315740]

t4['应付与预收合计'] = t4[['其中:应付票据(元)','应付账款(元)','预收款项(元)','合同负债(元)']].sum(axis=1)
t4['应收与预付合计'] = t4[['其中:应收票据(元)', '合同资产', '应收款项融资', '应收账款(元)', '预付款项(元)',]].sum(axis=1)
t4['应付预收减应收预付的差额'] = t4['应付与预收合计'] - t4['应收与预付合计']
t4.apply(format_thousandth).T

某公司近 6 年应付预收与应收预付的情况:

应付预收 - 应收预付的差额:大于0,公司的竞争力较强,具有两头吃的能力;小于0,被其他公司无偿占用资金,公司竞争力相对较弱。

通过柱形图对比应付预收与应收预付的大小:

plot_show(t4[['应付与预收合计','应收与预付合计']], title='应付预收与应收预付', kind='bar')

进一步分析应收预付的详情:

plot_show(t4[['其中:应收票据(元)','应收款项融资','应收账款(元)','预付款项(元)']], title='应收预付明细', kind='bar')

5、看应收账款、合同资产,了解公司的产品竞争力

通过应付预收与应收预付的差额,我们知道了公司的竞争力强不强,下面分析应收账款占总资产的比例,了解公司产品的竞争力如何。

t5 = pd.DataFrame(index=debt_df.index, columns=[
    '合同资产', '应收账款(元)', '应收账款加合同资产', '资产合计(元)', '(应收账款+合同资产)占总资产的比率'
])
t5[['应收账款(元)','资产合计(元)']] = debt_df[['应收账款(元)','资产合计(元)']]

t5['合同资产'] = [0,0,0,0,0,0]
t5['应收账款加合同资产'] = t5['合同资产'] + t5['应收账款(元)']
t5['(应收账款+合同资产)占总资产的比率'] = t5['应收账款加合同资产'] / t5['资产合计(元)']

pd.merge(
    t5[[ '合同资产', '应收账款(元)', '应收账款加合同资产', '资产合计(元)']].apply(format_thousandth),
    t5[['(应收账款+合同资产)占总资产的比率']].apply(format_percentage),
    left_index=True,
    right_index=True
).T

近 6 年的应收账款占总资产的比率:

以柱状图进行展示:

plot_show(t5['(应收账款+合同资产)占总资产的比率'], title='应收账款和合同资产占总资产的比率', ylabel='', kind='bar', y_format='p')

一般,我们会把(应收账款+合同资产)占资产总计的比率大于 15% 的公司淘汰掉。在特别情况下,对于行业第一名并且同时具有 3 个或以上核心竞争力的公司可以放宽到 20%,大于 20% 的一律淘汰掉。

(应收账款+合同资产)占总资产的比率:小于 1%,最好的公司,公司产品很畅销;小于 3%,优秀的公司,公司产品畅销;比率大于 10%,公司的产品比较难销售;比率大于 20%,公司的产品很难销售。

6、看固定资产,了解公司维持竞争力的成本

经过前面的分析,我们了解了公司的实力地位、成长性、债务风险、公司和产品竞争力情况,下面我们来看看公司维持竞争力的成本,也就是(固定资产+在建工程+工程物资)占总资产的比例:

  • 比率大于 40%,重资产型公司,维持竞争力的成本比较高,风险相对较大。
  • 比率小于 40%,轻资产型公司,保持持续的竞争力成本相对要低一些。
t6 = pd.DataFrame(index=debt_df.index, columns=[
    '固定资产合计(元)', '在建工程合计(元)', '工程物资(元)', '固定资产+在建工程+工程物资', 
    '资产合计(元)', '固定资产工程占总资产的比率'])

t6[['固定资产合计(元)', '在建工程合计(元)', '资产合计(元)']] = \
debt_df[['固定资产合计(元)', '在建工程合计(元)', '资产合计(元)']]

t6['工程物资(元)'] = [0,0,0,0,0,0]

t6['固定资产+在建工程+工程物资'] = t6[['固定资产合计(元)', '在建工程合计(元)', '工程物资(元)']].sum(axis=1)
t6['固定资产工程占总资产的比率'] = t6['固定资产+在建工程+工程物资'] / t6['资产合计(元)']

t6_show = pd.merge(t6[['固定资产合计(元)', '在建工程合计(元)', '工程物资(元)', 
             '固定资产+在建工程+工程物资', '资产合计(元)']].apply(format_thousandth),
         t6[['固定资产工程占总资产的比率']].apply(format_percentage),
         right_index=True,left_index=True).T
t6_show

公司固定资产占总资产的比例:

注:在建工程正常情况下后期会转为固定资产,此行数据取数包括了工程物资。 工程物资正常情况下后期转为在建工程。

以柱形图进行可视化展示:

plot_show(t6['固定资产工程占总资产的比率'], title='固定资产工程占总资产的比率', ylabel='', kind='bar', y_format='p')

一般选择(固定资产+在建工程)与总资产比率小于 20% 的轻资产型公司。对于行业第一名并且同时具有 3 个或以上核心竞争力的公司可以放宽到 50%,大于 50% 的一律淘汰掉。

7、看投资类资产,判断公司的专注程度

君子务本,本立而道生。对于一家公司也一样,只有专注于主业,才能卓越。看投资类资产占总资产的比例可以帮助我们了解一家公司的主业专注度。

投资类资产计算公式:投资类资产合计 = 其他权益工具投资 + 债权投资 + 其他债权投资 + 其他非流动金融资产 + 可供出售金融资产 + 持有至到期投资 + 长期股权投资 + 投资性房地产 + 以公允价值计量且其变动计入当期损益的金融资产。

t7 = pd.DataFrame(index=debt_df.index, columns=[
    '以公允价值计量且其变动计入当期损益的金融资产', '债权投资', '可供出售金融资产(元)', 
    '其他权益工具投资(元)', '持有至到期投资', '其他非流动金融资产(元)', 
    '长期股权投资(元)','投资性房地产(元)', '投资类资产合计', 
    '资产合计(元)', '投资类资产占总资产的比率'])

t7[['可供出售金融资产(元)','其他权益工具投资(元)','其他非流动金融资产(元)', 
    '长期股权投资(元)', '投资性房地产(元)', '资产合计(元)']] = \
debt_df[['可供出售金融资产(元)','其他权益工具投资(元)','其他非流动金融资产(元)', 
         '长期股权投资(元)', '投资性房地产(元)', '资产合计(元)']]


t7['以公允价值计量且其变动计入当期损益的金融资产'] = np.zeros(6)
t7['债权投资'] = np.zeros(6)
t7['持有至到期投资'] = np.zeros(6)

t7['投资类资产合计'] = t7.T[:8].sum()
t7['投资类资产占总资产的比率'] = t7['投资类资产合计'] / t7['资产合计(元)']

pd.concat([t7.T[:10].apply(format_thousandth),t7.T[10:].apply(format_percentage)])

近 6 年的投资类资产情况:

以柱形图可视化展示:

plot_show(t7['投资类资产占总资产的比率'], title='投资类资产占总资产的比率', ylabel='', kind='bar', y_format='p')

投资类资产占总资产的比值小于 10%,专注于主业,属于优秀的公司;比值大于 10%,不够专注于主业。一家非常专注于主业的公司,在未来持续保持竞争优势的概率较大。

8、看存货,了解公司未来业绩爆雷的风险

注:暴雷的风险主要是两个方面:经营和投资,其中经营看存货,投资看商誉。

对于应收账款占总资产的比率大于 5% 并且存货占总资产的比率大于 15% 的公司存在未来爆雷风险。应收账款占比比较大,说明货比较难卖,必须靠延长账期来把货卖出去,同时大量存货积压,这时候存货暴雷的风险往往比较大。

t8 = pd.DataFrame(index=debt_df.index, columns=['存货(元)', '资产合计(元)', '存货占总资产的比率'])
t8[['存货(元)', '资产合计(元)']] = debt_df[['存货(元)', '资产合计(元)']]

t8['存货占总资产的比率'] = debt_df['存货(元)'] / debt_df[ '资产合计(元)']

pd.concat([t8.T[:2].apply(format_thousandth), t8.T[2:].apply(format_percentage)])

近 6 年某公司存货占总资产的比例:

柱形图可视化展示存货、应收账款情况:

tmp_df = pd.merge(t8['存货占总资产的比率'], t5['(应收账款+合同资产)占总资产的比率'],right_index=True,left_index=True)
plot_show(tmp_df, title='存货和应收账款情况', kind='bar', ylabel='', y_format='p')

注:应付预收-应收预付 > 0 且应收账款/资产总计 < 1%,存货基本没有爆雷的风险;应收账款/资产总计 > 5% 且存货/资产总计 > 15%,爆雷的风险比较大。

9、看商誉,了解公司未来业绩爆雷的风险

注:溢价收购其他公司,多花的那部分钱就是商誉。商誉越大,当冤大头的可能就越大。

t9 = pd.DataFrame(index=debt_df.index, columns=['商誉(元)', '资产合计(元)', '商誉占总资产的比率'])
t9[['商誉(元)', '资产合计(元)']] = debt_df[['商誉(元)', '资产合计(元)']]
t9['商誉占总资产的比率'] = debt_df['商誉(元)'] / debt_df[ '资产合计(元)']

pd.concat([t9.T[:2].apply(format_thousandth), t9.T[2:].apply(format_percentage)])

某公司近 10 年的商誉情况:

使用柱形图可视化展示商誉:

plot_show(t9['商誉占总资产的比率'], title='商誉占总资产的比率', kind='bar', ylabel='', y_format='p')

大于 10%,商誉有爆雷的风险;小于 10%,商誉没有爆雷的风险,具体可以根据收购的资产质量权衡。

总结

以上就是基于 Pandas 分析的资产负债表了,通过资产负债表我们可以了解到一家公司的实力和成长性(资产规模和资产增长率)、债务风险(资产负债率、准货币资金与有息负债的差额)、公司竞争力(应付预收减应收预付)、产品竞争力(应收账款占总资产的比例)、维持竞争力的成本(固定资产占总资产的比例)、是否专注于主业(投资类资产占总资产的比例)以及暴雷的风险(存货和商誉)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341

推荐阅读更多精彩内容