数据探索分析就写了6000+的实战文,写完怕不得几万字?
大家好,我是小一
今天的这篇文章比较肝,是一篇比较贴合实际工作的数分实战案例
全文 6000 多字,可能阅读会花一些时间,但是 绝对物超所值。特别是对于没有项目可以练手的同学来说,建议跟着实操一遍,收获很大!
下面是正文:
这个项目官方给出的背景是这样的:
解读一下,大致意思是:现在有一批已经更换5G套餐的用户数据,数据维度有很多,包括:基础信息、消费行为、超套信息、宽带信息、其他信息,共 46 个用户特征。
目的是 通过这批用户数据去分析什么样的用户更倾向于更换5G套餐,从而进行潜客营销
如果是第一次做分析类项目的同学,可能拿到这个数据的第一印象是:靠,咋这么多特征列?
其实数据一共就 14w 条,5 个用户维度一共 46 个特征,比较正常的数据,实际真正应用的话这个数据量甚至还有点点少,训练出来的模型需要多轮测试才能部署。
ok,背景也说完了,下面开始正文
探索性数据分析部分需要绘图,涉及代码比较多,就不一一放了
想要源数据练手的同学可以直接拉到文末。
整体分析
在分析之前需要明确,当前的工作是探索性数据分析(EDA)。探索性数据分析属于数据清洗之前的部分,主要是探索数据,只看数据不操作数据
先来看看数据:
整体数据就这样,一共 14w 条数据,46 个特征
1. 缺失分析
缺失分析应该算是最早应该做的,如果有缺失值,后面的探索 不要忘了考虑缺失 情况
一个 46 个特征,肯定会有缺失值,代码也很简单:
"""查看数据整体缺失情况"""
df_data.isnull().sum()
图很长,放一部分吧:
这个图看的不是很明了,换种方式,我们可以计算每个特征的缺失程度,然后排序一下
代码如下:
"""查看特征的缺失程度"""
missing_series = df_data.isnull().sum()/df_data.shape[0]
missing_df = pd.DataFrame(missing_series).reset_index()
missing_df = missing_df.rename(columns={'index': 'col', 0: 'missing_pct'})
missing_df = missing_df.sort_values('missing_pct', ascending=False).reset_index(drop=True)
效果是这样的:
1.2 缺失分析-看图分析
用户标识维度无数据缺失
用户基础信息维度中星级缺失 6849 条数据、细分市场缺失 691 条数据 消费行为信息维度、超套信息维度中所有特征均分别缺失 89、392 条数据 宽带信息维度中宽带贷款和宽带是否激活特征缺失 101060 条数据,缺失较严重 签约信息维度、套餐信息维度中所有特征均分别缺失 774、6617 条数据 流量饱和度信息维度中所有特征均缺失 9000+ 条数据,需要进一步分析 其他信息特征中,5G流量特征缺失 132559 条数据,缺失非常严重
另外,缺失分析不光是特征分析,还需要 对样本进行缺失分析
如果一个样本在多个特征上都缺失,那默认该样本可用价值比较少,可以直接丢弃
代码如下:
"""查看样本的缺失程度"""
missing_series = df_data.isnull().sum(axis=1)
list_missing_num = sorted(list(missing_series.values))
绘图如下:
1.3 缺失分析-总结
首先,数据呈现阶段性缺失,可以初步判定同一维度中的多个特征缺失实为同一样本的缺失。
其次,部分样本的特征缺失较多,可以考虑删除此部分样本
2. 类别分析
常见的数据类型一般分为两种:类别型特征和数值型特征
像样本数据中的 细分市场 就属于类别特征,属性包括:校园用户、集团用户等等,对应的 5G流量 就属于数值特征,有具体的数值大小。
pandas 中对于类别和数值特征的区分很简单:
# 查看特征的数值特征有哪些,类别特征有哪些
numerical_fea = list(df_data.select_dtypes(exclude=['object']).columns)
category_fea = list(filter(lambda x: x not in numerical_fea, list(df_data.columns)))
但是,上述代码存在根本上的问题
pandas 在读取数据的时候会自动声明数据类别,导致有部分脱敏后的类别数据会被其认为是数值数据
例如,终端类型、是否异网宽带用户特征,因为数据需要脱敏处理,所以你看到的数据值为:1、2... ,实质上它们都是类别特征,像终端类型的原始数据可能是:华为、小米、苹果这些
这里推荐一种比较取巧的方法:同值过滤法
解释一下:如果一个被 pandas 认定的数值特征中出现不同值的个数超过 10,那么这个特征就是数值特征,否则就是类别特征
上面的 10 你也可以人为调整
代码如下:
"""划分数值型变量中的连续变量和分类变量"""
def get_numerical_serial_fea(data, feas):
numerical_serial_fea = []
numerical_noserial_fea = []
for fea in feas:
temp = data[fea].nunique()
# 如果同值个数小于10,则认为是类别型数据
if temp <= 10:
numerical_noserial_fea.append(fea)
else:
numerical_serial_fea.append(fea)
return numerical_serial_fea,numerical_noserial_fea
在今天的项目中,这个方法效果很明显:
原本认定的 4 个类别特征,增加到 19 个
3. 同值化分析
同值化就是一个特征中某个属性的占比很高,那么用这个特征去分类极有可能得不出好效果
同值化在类别特征中比较容易出现,代码如下:
"""查看特征中特征的单方差(同值化)性质"""
threshold_const = 0.95
const_list = [x for x in df_data.columns if x!='label']
const_col = []
const_val = []
for col in const_list:
# value_counts 的最多的一个样本类别的样本数
max_samples_count = df_data[col].value_counts().iloc[0]
# 总体非空样本数
sum_samples_count = df_data[df_data[col].notnull()].shape[0]
# 计算特征中类别最多的样本占比
const_val.append(max_samples_count/sum_samples_count)
# 过滤同值化特征
if max_samples_count/sum_samples_count >= threshold_const:
const_col.append(col)
print('常变量/同值化比例大于{}的特征个数为{}'.format(threshold_const, len(const_col)))
效果如下:
可以发现,同值化比例大于 95% 的有 5 个特征,甚至有一个特征全为同一个值,需要特别注意
单特征深度分析
单特征分析主要是针对类别型特征和数值型特征挨个进行分析
但是用户信息中缺失情况比较一致,处于同一维度的特征也可以同时做对比分析
1. 类别特征分析-整体
先来看整体类别特征的分布情况:
1. 类别特征分析-看图说话
从上图可以得出很多有用的信息,其中:
性别中,男性5G用户开通率略微高于女性 市场中,集团用户更倾向于开通5G 星级中,四星级用户更愿意使用5G 本网宽带用户比异网宽带用户更倾向于使用5G,而且宽带带宽为100的用户占比更高、200次之 宽带、终端捆绑的用户更愿意使用5G 家庭用户比非家庭用户更愿意使用5G 终端类型为1的用户最多,为2的5G用户率最高
另外:
宽带是否激活特征只有唯一值和缺失值 当月是否保号保号用户特征同值化较高
还有:星级、宽带带宽特征个别特征占比较低,可以考虑分箱处理;上述倾向于使用5G的用户特征(例如:细分市场)中类别存在空值,缺失的是否重要?同值化特征是否可以删除?
别急着下结论,都需要进一步分析
1.1 星级特征-分析
上面说过,星级特征需要特别考虑缺失值是否重要
小技巧:将缺失值单独分为一列
代码如下:
"""进一步对上述类别特征进行分析"""
df_data_2 = df_data.copy()
# 星级特征
df_data_2.loc[df_data_2['星级'].isnull(), '星级'] = '空'
"""星级特征对应的5G用户"""
plt.figure(figsize=(13, 5))
# 设置标题
plt.title('不同星级特征对应的5G用户')
sns.countplot(x='星级', hue='label', data=df_data_2)
plt.show()
效果如下:
另外,也可以看看星级用户对应的5G用户具体占比情况
"""星级对应的5G用户占比"""
df_bucket = df_data_2.groupby('星级')
user_5G_trend = pd.DataFrame()
user_5G_trend['total'] = df_bucket['label'].count()
user_5G_trend['5G'] = df_bucket['label'].sum()
user_5G_trend['5G_rate'] = user_5G_trend['5G']/user_5G_trend['total']
user_5G_trend = user_5G_trend.reset_index()
user_5G_trend
绘图如下:
1.1 星级特征-结论
星级 0、1、2、3、4 对应的5G用户占比逐渐增高,星级 5、6、7 用户数较少,但是整体5G用户占比还是高于平均值
操作建议:可以进行分箱,空值对应的5G用户可单独分为一类,或者根据5G用户占比率进行分箱合并
具体的,后期可根据模型的具体预测效果进行选择
1.2 细分市场特征-分析
和星级特征一样,先考虑缺失值,然后在分析
代码类似上一步,直接看图
1.2 细分市场特征-结论
校园用户占比最少,5G开通率最低;集团用户5G用户占比最高
操作建议:空值对应的5G用户 占比极低,分箱会影响其他箱的5G用户占比,所以不建议进行箱体合并,可尝试直接单独当做一箱
具体的,后期可根据模型的具体预测效果进行选择
1.3 宽带带宽&是否激活特征-分析
同样的思路,先考虑缺失值,然后在分析
不同的是,宽带带宽 特征与另一个特征 宽带是否激活 需要综合考虑
1.3 宽带带宽&是否激活特征-结论
宽带带宽特征:
带宽在60以下的特征因为样本数据太少,可以进行合箱 带宽在100以上的因为总体5G用户占比较高,可以进行合箱
操作建议:最终的宽带带宽特征可以分为3箱:<=60、>100、空
宽带是否激活特征:
因为属性只有1,表示宽带已经激活,所以这里大胆预测缺失的数据就是表示宽带没有激活,对应的可以用0表示
1.4 其他类别特征-分析
剩余 6 个特征中 4 个为签约维度特征,2 个为其他维度特征,可以一并进行分析
1.4 其他类别特征-总结
前 4 个签约维度特征中存在缺失数据,任选两个特征分析发现缺失数据的5G用户占比较低
提供如下操作建议:
合并到概率相近的箱中,例如上述特征中的0属性 用众数填充 用同类别用户该特征的众数填充 直接删除样本
后 2 个特征虽然同值化较严重,但是样本少的5G用户占比较高,或许在模型训练中会拿到一个不错的贡献分
暂时不做处理,后面特征工程中尝试通过 lgb 进行特征筛选后在确定
2. 数值特征分析-整体
离散特征中有两个例外的特征需要单独分析:年龄和在网时长
年龄字段虽然是数值型,但是将其进行分箱后模型的性能会大大提升,分析如下:
2.1 年龄特征-分析
计算每个年龄5G用户占比情况,观察是否可以分箱,以及分箱策略
代码如下:
"""
年龄特征分析
计算不同年龄的5G用户分布情况
"""
df_bucket = df_data_2.groupby('年龄')
user_5G_trend = pd.DataFrame()
user_5G_trend['total'] = df_bucket['label'].count()
user_5G_trend['5G'] = df_bucket['label'].sum()
user_5G_trend['5G_rate'] = user_5G_trend['5G']/user_5G_trend['total']
user_5G_trend = user_5G_trend.reset_index()
绘图如下:
2.1 年龄特征-总结
从图中可以发现:
25-50岁 之间5G用户整体占比较高,基本在 20% 上方波动 13-25岁 的5G用户占比随着年龄呈上升趋势 50岁 以上的5G用户占比随着年龄呈下降趋势
基于这个特性,可以将年龄特征进行分箱,大致如下:
13-20、20-25、25-45、45-50、>50
上面分组不绝对,例如对于第1、2组也可以合为一组,3、4组合为一组
具体的分组效果需要根据模型的得分去判断
2.2 在网时长特征-分析
思路同年龄特征,直接统计各自的5G用户占比情况
绘图如下:
2.2 在网时长特征-总结
从图中可以发现:
在网时长为 1 的样本占比最多,但同时5G用户占比率也最低
当在网时长在 2-10 之间时,5G用户占比在 25%-30% 中间波动
当在网时长 >10 时,5G用户占比率高于 30%,并呈现加速上升趋势
其实,分析到这,不难猜出,对应的数字应该代表用户在网年份
具体的操作建议:还是分箱操作 ① 0-1 ② 2-10 ③ >10
具体的分组效果还是需要根据模型的得分去判断,这里不绝对
2.3 数值特征-分析
数值特征的分析比较简单,最常见的是对极大极小值进行过滤,或者设定一个最大值赋给超过该值的所有值
其次是对数据进行无量纲化,使得不同的特征能够保持在一个量纲上,模型训练起来也快一些
直接绘图看特征分布:
操作建议:去极值、标准化,常见的操作手法
总结一下
以上就是在数据探索阶段需要做的事情,常见的探索手法还会对多个特征特征进行联立分析
例如:不同星级的男性和女性5G用户占比是什么样的?不同细分市场不同年龄段的5G用户占比又是什么样的?
很多时候,特征之间的互相融合就是源自于多维度的探索分析
总结一下今天的内容,方便在特征工程部分进行相应的处理
首先很明显能看出:
性别中,男性5G用户开通率略微高于女性 市场中,集团用户更倾向于开通5G 星级中,四星级用户更愿意使用5G 本网宽带用户更倾向于使用5G,而且宽带带宽为100的用户意愿更强 宽带、终端捆绑的用户更愿意使用5G 家庭用户比非家庭用户更愿意使用5G 终端类型为为2的5G用户率最高
更细致一点的:
星级 0、1、2、3、4 对应的5G用户占比逐渐增高,星级 5、6、7 用户数最少,但是5G用户占比率相近
校园用户占比最少,5G开通率最低;集团用户5G开通率最高
带宽在 60 以下的样本数据太少,带宽在100以上的5G用户占比较高
宽带是否激活中属性只有1,表示宽带已经激活
签约维度特征中签约信息为空的5G用户占比较低
是否抵消保号用户和当月是否换机这两个特征虽然同值化较严重,但是样本少的属性5G用户占比较高
实战类文章,强烈建议大家都动动手操作一下,主要是这个数据源自于实际场景,量也不大,比那什么泰坦尼克、豆瓣电影这些数据集都有操作价值。
相关数据集我已经打包好了, 想实操的同学可以在留言区查看源码和数据集获取方式
往期文章
2021-03-30
一键爬取基金历年季度报数据,轻松搞定!附源码
2021-02-20
数据分析最重要的 3 种特征编码,你真的能分清楚?
2021-02-02
我是小一,坚持向暮光所走的人,终将成为耀眼的存在!
期待你的 三连!我们下节见