【财报分析】将 Pandas 分析成果输出到 Word 文档

2022-02-23  本文已影响0人  山药鱼儿

连载的前两篇文章,小鱼使用 Pandas 分析了某上市的三大财务报表:

其中,我们输出了大量的表格以及柱形图、折线图。代码、表格、柱形图混在一起未免显得有点儿混乱,尤其我们想要将分析结果共享给其他没有编程背景的同伴,那么代码的出现可能使得同伴非常困惑。

本节,我们就来学习一下如何将我们之前的输出结果保存到 Word 文档中,更好地呈现分析成果。

定义常量

列表 images 中的字符串将作为柱形图(折线图)的标题以及在保存图片文件时进行命名。

images = [
    ['总资产','总资产增长率'],
    '资产负债率',
    '准货币资金与有息负债',
    ['应付预收与应收预付','应收预付明细'],
    '应收账款和合同资产占总资产的比率',
    '固定资产工程占总资产的比率',
    '投资类资产占总资产的比率',
    '存货和应收账款情况',
    '商誉占总资产的比率',
    ['营业收入','营业收入增长率'],
    ['毛利率','毛利率波动幅度'],
    ['期间费用率','期间费用率占毛利率的比例'],
    '销售费用率',
    ['主营利润率','主营利润占营业利润的比率'],
    '',
    ['净资产收益率ROE','归属于母公司所有者的净利润增长率'],
    '购建支付的现金与经营活动产生的现金流量净额的比率',
    '分配股利、利润或偿付利息支付的现金与经营活动产生的现金流量净额的比率',
    '三大活动的现金流量净额情况'
]

定义 Word 文档中显示的标题:

titles = [
    '看总资产,判断公司实力及扩张能力',
    '看资产负债率,了解公司的偿债风险',
    '看有息负债和准货币资金,排除偿债风险',
    '看“应付预收”减“应收预付”的差额,了解公司的竞争优势',
    '看应收账款、合同资产,了解公司的产品竞争力',
    '看固定资产,了解公司维持竞争力的成本',
    '看投资类资产,判断公司的专注程度',
    '看存货,了解公司未来业绩爆雷的风险',
    '看商誉,了解公司未来爆雷的风险',
    '看营业收入,了解公司的行业地位及成长性',
    '看毛利率,了解公司的产品竞争力及风险',
    '看期间费用率,了解公司的成本管控能力',
    '看销售费用率,了解公司产品的销售难易度',
    '看主营利润,了解公司主业的盈利能力及利润质量',
    '看净利润,了解公司的经营成果及含金量,净利润主要看净利润含金量',
    '看归母净利润,了解公司的整体盈利能力及持续性',
    '看购买固定资产、无形资产和其他长期资产支付的现金,了解公司的增长潜力',
    '看分配股利、利润或偿付利息支付的现金,了解公司的现金分红情况',
    '附:三大活动产生的现金流量净额'
]

一共有 19 个标题,前 18 个为三大财务报表的十八步财报排雷,最后一个对应经营活动、投资活动、筹资活动产生的现金流量净额情况。

定义函数

我们需要在 Word 文档中依次写入每个分析步骤的标题、表格以及绘图结果。定义函数 save_title save_table save_image

import docx

def save_table(table):
    rows, cols = table.shape[0]+1, table.shape[1]
    t = doc.add_table(rows, cols) 

    # add the header rows. 
    for col in range(cols-1): 
        # 表格部分只取最近5年的数据,从索引1开始取
        t.cell(0, col+1).text = str(table.columns[col+1])

    # add the index cols.
    for row in range(rows-1):
        t.cell(row+1, 0).text = str(table.index[row])

    # add the rest of the dataframe 
    for row in range(rows-1): 
        for col in range(cols-1): 
            t.cell(row+1,col+1).text = str(table.values[row, col+1]) 
            
    doc.add_paragraph()
    doc.save(DOC)
    
def save_title(title):
    doc.add_paragraph(title)
    doc.add_paragraph()
    doc.save(DOC)
    
def save_image(image_path):
    if isinstance(image_path, list):
        for img in image_path:
            doc.add_picture(f'{img}.png')
    elif image_path:
        doc.add_picture(f'{image_path}.png')
    doc.save(DOC)

值得注意的是,对于一些分析项,需要保存的图片可能不止一张,比如资产项的分析中,就有总资产和总资产增长率两张图片。

函数调用

首先,将所有的表格搜集到一个列表中:

tables = [t1_show, t2_show, t3_show, t4_show, t5_show, t6_show, 
          t7_show, t8_show, t9_show, t10_show, t11_show, t12_show,
          t13_show, t14_show, t15_show, t16_show, t17_show, t18_show]

t1_show 为例,展示表格结构:

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

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

在绘图函数中增加 plt.savefig(title+'.png') 语句,将绘制结果先保存成本地 png 图片。

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')

这样,当在 NoteBook 中展示绘制结果时,也会同时生成相应的本地文件:

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

总资产增长率:

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

调用函数,生成 Word 文档:

from itertools import zip_longest

DOC = 'xxx公司2020财报排雷.docx'
doc = docx.Document(DOC) 

for title, table, image in zip_longest(titles, tables, images):
    save_title(title)
    if table is not None:
        save_table(table)
    save_image(image)

使用 zip_longest 是因为 titlesimagestables 多一项内容。最后一项分析三大活动产生的现金流量净额时,小鱼没有输出表格,因为折线图的展示已经非常直观了。

至此,Word 分析文档就为我们生成好了,下面是小鱼输出的第 1 页内容。

默认输出的文档非常简单,可以根据需要的风格,自行美化 docx 文档,并添加分析结论。

上一篇 下一篇

猜你喜欢

热点阅读