首先导入分析所需的模块
import pandas as pd
import seaborn as sns
import matplotlib.pylab as plt
import numpy as np
# 绘图显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
用pandas
读取破产公司文件,并预览数据
com_all = pd.read_csv('./data/com.csv')
com_all.head(3)
字段比较多,我们用info
来看一下
com_all.info()
共有6272行,也就是6272家公司。共有16列,前10列基本都是非空的,所以下面我们主要对前10列进行分析。
接来下,我们先对数据做个大致了解,先来看看数据涉及哪些年份,以及每年的破产公司数量
# 从日期字符串提取年份子串
com_all['death_year'] = com_all['death_data'].apply(lambda x: x[:4])
# 按年份分组计数,画每年破产公司数量的折线图
com_all[['com_name', 'death_year']].groupby('death_year').count().plot(xticks=range(20), rot=30, figsize=(10, 6))
明显能看到从14年破产公司开始增多,15年陡增,17年达到峰值,所以说17年开始不少自媒体经常说大环境不好也是有原因的。记得我15年刚毕业找工作的时候就听说大环境已经不太好了,然而我17年跳槽的时候环境变得更差了。这真是好事没赶上,坏事没落下。
对整体数据有了大致了解以后,我们按照单维度拆解,分别来对破产公司进行分析。上面提到14年破产公司开始增加,那么我们可以认为14年之前破产的公司属于自然破产,而非所谓的“大环境”导致。所以下面我们只对14年之后的破产公司进行分析。
com_part = com_all[com_all['death_year'] >= '2014']
下面以公司所在地为例,查看不同省份破产公司分布
# 城市
com_city_gb = com_part[['com_name', 'com_addr']].groupby('com_addr').count().sort_values(by='com_name', ascending=False)
com_city_gb[com_city_gb['com_name'] > 10].plot(kind='bar', rot=20, title='省份', figsize=(10, 6))
可以看到北京、广东、上海等经济发达的地区,破产产的公司更多。这里需要注意一个概念叫幸存者偏差,举个例子,你如果从这个数据得出北京、上海等地创业更容易破产的结论,那就是有偏差的。因为你只是从幸存下来的破产数据去下结论,而没有考虑总体数据,因此得到的结论是有偏差的或者说是不对的。举个例子,图上可以看到北京破产的公司有2000家,浙江破产的公司大概400家,而实际上北京同期成立的创业公司可能有3000家,创业死亡率为 67%,而浙江同期成立的创业公司可能有800家,创业死亡率为 50%,明显在北京创业有更高的存活率。
然后我们在分行业维度来看看破产公司分布
# 行业
com_cat_gb = com_part[['com_name', 'cat']].groupby('cat').count().sort_values(by='com_name', ascending=False)
com_cat_gb.plot(kind='bar', rot=20, title='行业', figsize=(10, 6))
可以看到电子商务、企业服务、本地生活、金融等行业破产公司数量较多,这里同样存在幸存者偏差的问题,行业死亡率是否高,还需要结合行业整体数据来判断。
同样的方式,我们在分别看看融资阶段和破产原因两个维度的情况
从破产融资阶段看,破产的公司大部分都没有融资记录或者没有获得融资。如果能拿到所有公司注册和破产的数据,再结合融资阶段画一个不同融资阶段的漏斗图会非常直观看到各个融资阶段的存活率。
从破产原因看,破产的原因主要在于商业模式匮乏、行业竞争以及市场伪需求。
到这里,单维度的数据就分析完了。但单维度分析有个缺点是粒度太粗了,它只能反映整体的情况。如果需要更进一步的细化分析,还需要进行维度交叉。
上面对破产原因
单维度进行分析,我们知道了大部分公司是因为什么原因导致的破产,但这反映不出不同行业的破产原因。下面我就选行业
和破产原因
这俩个维度进行更细化的分析。首先的想法是将行业
作为x轴,破产原因
作为y轴做个散点图,图上的点越大,说明对应的行业的破产原因就越突出
# 选top行业和破产原因
death_reasons = com_death_reason_gb[:15].index.values
cats = com_cat_gb[:10].index.values
com_part2 = com_part[com_part['death_reason'].isin(death_reasons) & com_part['cat'].isin(cats)]
com_part2.plot(kind='scatter', x='cat', y='death_reason', figsize=(10, 6))
行业和破产原因太多了,我们只选top的进行分析。从图上点的大小大概能看出来不同行业的破产原因是不同的,但也不是太直观,并且不能定量地看。
如何更直观地看不同行业下不同破产原因的区别呢,我想到一种方法,计算不同行业、不同破产原因的TGI
指标,然后画一个热力图。
TGI
反应的是目标群体在总体里的强势或弱势指数。举例:在所有破产公司中,行业竞争
原因导致破产的比例是14%,而电商
行业里,行业竞争
原因导致破产的比例为20%,那么电商
行业在行业竞争
这个破产原因的TGI=20% / 15% = 1.42。大于1代表在总体里处于强势,数值越高就越强势。
沿着这个思路,准备所需要的数据
# 行业+破产原因维度的破产公司数量
reason_cat_df = com_part2.groupby(['cat', 'death_reason']).count()[['com_name']]
# 行业维度的破产公司数量
cat_df = com_part2.groupby(['cat']).count()[['com_name']]
# 不同破产原因的占比
reason_df = (com_part2.groupby(['death_reason']).count()[['com_name']] / cat_df.sum())
将DataFarme
索引变为列,方便关联
reason_cat_df.reset_index(inplace=True)
cat_df.reset_index(inplace=True)
reason_df.reset_index(inplace=True)
reason_df.rename(columns={'com_name': 'all_reason_r'}, inplace=True)
按照不同维度,将数据关联在一起,并计算TGI
# 关联数据
tmp_df = pd.merge(reason_cat_df, cat_df, on='cat',how='left')
df = pd.merge(tmp_df, reason_df, on = 'death_reason', how='left')
# 计算每个行业破产原因占比
df['cat_reason_r'] = df['com_name_x'] / df['com_name_y']
# 计算每个行业破产原因的TGI
df['cat_reason_tgi'] = df['cat_reason_r'] / df['all_reason_r']
df
这样,TGI
就计算完成了。为了画热力图,我们还需要对数据进行重塑,通过透视图
把行业
变成索引,破产原因
变成列
df_tgi = df.pivot_table(index='death_reason', columns='cat', values='cat_reason_tgi')
df_tgi = df_tgi.fillna(0)
df_tgi
画热力图
plt.figure(figsize=(15, 8))
sns.heatmap(df_tgi, annot=True, fmt='.2g')
可以放大来看,颜色越浅代表越强势。比如:金融
行业在政策监管
和法律法规风险
的TGI
为7.5,说明这两个原因是导致金融公司破产很强势的原因。
通过TGI
+热力图的方式我们可以很直观并且定量的看到不同行业下破产原因的区别。我的分析就到这里了,有兴趣的朋友再对其他维度进行交叉分析。数据地址和源码已经打包,公众号回复关键字破产公司即可。
欢迎公众号 「渡码」 输出别地儿看不到的干货。