记录第一次参加正式的数据挖掘竞赛,由科大讯飞xDatawhale举办的《电信客户流失预测挑战赛》
报名链接:2022 iFLYTEK A.I.开发者大赛-讯飞开放平台
一、赛题概要
赛题背景
随着市场饱和度的上升,电信运营商的竞争也越来越激烈,电信运营商亟待解决减少用户流失,延长用户生命周期的问题。对于客户流失率而言,每增加5%,利润就可能随之降低25%-85%。因此,如何减少电信用户流失的分析与预测至关重要。
鉴于此,运营商会经常设有客户服务部门,该部门的职能主要是做好客户流失分析,赢回高概率流失的客户,降低客户流失率。某电信机构的客户存在大量流失情况,导致该机构的用户量急速下降。面对如此头疼的问题,该机构将部分客户数据开放,诚邀大家帮助他们建立流失预测模型来预测可能流失的客户。
赛题任务
给定某电信机构实际业务中的相关客户信息,包含69个与客户相关的字段,其中“是否流失”字段表明客户会否会在观察日期后的两个月内流失。任务目标是通过训练集训练模型,来预测客户是否会流失,以此为依据开展工作,提高用户留存。
评价指标
AUC评价指标
AUC评价指标因为其不用手动设置阈值的特点常用于二分类的预测任务中。
简要分析
通过上述描述可以了解到,题目是二分类预测,拥有69个特征字段,目标字段为”是否流失“。
二、数据探索(EDA)
配置环境导入相关包
#导入库
import pandas as pd
import os
import gc
import lightgbm as lgb
import xgboost as xgb
from catboost import CatBoostRegressor
from hyperopt import hp, fmin, tpe
from sklearn.linear_model import SGDRegressor, LinearRegression, Ridge
from sklearn.preprocessing import MinMaxScaler
from gensim.models import Word2Vec
import math
import numpy as np
from numpy.random import RandomState
from tqdm import tqdm
from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score, log_loss
import matplotlib.pyplot as plt
import time
import warnings
warnings.filterwarnings('ignore')
数据读入
train_data = pd.read_csv("train.csv")
test_data = pd.read_csv("test.csv")
简要查看数据信息
#查看训练集和测试集前5行
train_data.head()
test_data.head()
#查看训练集和测试集的列
print('Train_data.columns:',train_data.columns)
print('Test_data.columns:',test_data.columns)
#查看训练集和测试集的形状
print('Train data shape:',train_data.shape)
print('Test data shape:',test_data.shape)
Train data shape: (150000, 69) Test data shape: (30000, 68)
#查看数据信息
train_data.info()
test_data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 150000 entries, 0 to 149999 Data columns (total 69 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 客户ID 150000 non-null int64 1 地理区域 150000 non-null int64 2 是否双频 150000 non-null int64 3 是否翻新机 150000 non-null int64 4 当前手机价格 150000 non-null int64 5 手机网络功能 150000 non-null int64 6 婚姻状况 150000 non-null int64 7 家庭成人人数 150000 non-null int64 8 信息库匹配 150000 non-null int64 9 预计收入 150000 non-null int64 10 信用卡指示器 150000 non-null int64 11 当前设备使用天数 150000 non-null int64 12 在职总月数 150000 non-null int64 13 家庭中唯一订阅者的数量 150000 non-null int64 14 家庭活跃用户数 150000 non-null int64 15 新手机用户 150000 non-null int64 16 信用等级代码 150000 non-null int64 17 平均月费用 150000 non-null int64 18 每月平均使用分钟数 150000 non-null int64 19 平均超额使用分钟数 150000 non-null int64 20 平均超额费用 150000 non-null int64 21 平均语音费用 150000 non-null int64 22 数据超载的平均费用 150000 non-null int64 23 平均漫游呼叫数 150000 non-null int64 24 当月使用分钟数与前三个月平均值的百分比变化 150000 non-null int64 25 当月费用与前三个月平均值的百分比变化 150000 non-null int64 26 平均掉线语音呼叫数 150000 non-null int64 27 平均丢弃数据呼叫数 150000 non-null int64 28 平均占线语音呼叫数 150000 non-null int64 29 平均占线数据调用次数 150000 non-null int64 30 平均未接语音呼叫数 150000 non-null int64 31 未应答数据呼叫的平均次数 150000 non-null int64 32 尝试拨打的平均语音呼叫次数 150000 non-null int64 33 尝试数据调用的平均数 150000 non-null int64 34 平均接听语音电话数 150000 non-null int64 35 平均完成的语音呼叫数 150000 non-null int64 36 完成数据调用的平均数 150000 non-null int64 37 平均客户服务电话次数 150000 non-null int64 38 使用客户服务电话的平均分钟数 150000 non-null int64 39 一分钟内的平均呼入电话数 150000 non-null int64 40 平均三通电话数 150000 non-null int64 41 已完成语音通话的平均使用分钟数 150000 non-null int64 42 平均呼入和呼出高峰语音呼叫数 150000 non-null int64 43 平均峰值数据调用次数 150000 non-null int64 44 使用高峰语音通话的平均不完整分钟数 150000 non-null int64 45 平均非高峰语音呼叫数 150000 non-null int64 46 非高峰数据呼叫的平均数量 150000 non-null int64 47 平均掉线或占线呼叫数 150000 non-null int64 48 平均尝试调用次数 150000 non-null int64 49 平均已完成呼叫数 150000 non-null int64 50 平均呼叫转移呼叫数 150000 non-null int64 51 平均呼叫等待呼叫数 150000 non-null int64 52 账户消费限额 150000 non-null int64 53 客户生命周期内的总通话次数 150000 non-null int64 54 客户生命周期内的总使用分钟数 150000 non-null int64 55 客户生命周期内的总费用 150000 non-null int64 56 计费调整后的总费用 150000 non-null int64 57 计费调整后的总分钟数 150000 non-null int64 58 计费调整后的呼叫总数 150000 non-null int64 59 客户生命周期内平均月费用 150000 non-null int64 60 客户生命周期内的平均每月使用分钟数 150000 non-null int64 61 客户整个生命周期内的平均每月通话次数 150000 non-null int64 62 过去三个月的平均每月使用分钟数 150000 non-null int64 63 过去三个月的平均每月通话次数 150000 non-null int64 64 过去三个月的平均月费用 150000 non-null int64 65 过去六个月的平均每月使用分钟数 150000 non-null int64 66 过去六个月的平均每月通话次数 150000 non-null int64 67 过去六个月的平均月费用 150000 non-null int64 68 是否流失 150000 non-null int64 dtypes: int64(69) memory usage: 79.0 MB
从输出的信息可以看到,本次数据都是int类型,暂时看没有缺失值,具体等待后面缺失值处理部分详细处理。
#describe 查看简要信息,看数据有无异常等情况
train_data.describe()
describe() 方法可以让我们快速的对数据整体有个概念,可以方便的从上面观察到一些异常值等。从上图可以看到,其中多项特征最小值为-1, 对于家庭成人人数等特征,猜测-1值为举办方对于缺失值的填充处理,后面可将-1作为异常值考虑。
相关性分析
查看对于’是否流失‘的相关系数:
是否流失 1.000000 当前设备使用天数 0.117242 手机网络功能 0.088076 家庭中唯一订阅者的数量 0.035298 婚姻状况 0.024911 平均语音费用 0.024728 平均超额费用 0.023879 信息库匹配 0.022176 在职总月数 0.021920 平均超额使用分钟数 0.019263 家庭活跃用户数 0.014626 信用卡指示器 0.013053 平均漫游呼叫数 0.011900 当月费用与前三个月平均值的百分比变化 0.006713 客户ID 0.001306 平均呼叫转移呼叫数 -0.003266 计费调整后的总费用 -0.003317 地理区域 -0.003459 客户生命周期内的总费用 -0.003480 平均占线数据调用次数 -0.005112 未应答数据呼叫的平均次数 -0.006067 数据超载的平均费用 -0.006451 新手机用户 -0.006805 平均丢弃数据呼叫数 -0.008222 客户生命周期内平均月费用 -0.010270 平均峰值数据调用次数 -0.011339 信用等级代码 -0.012046 非高峰数据呼叫的平均数量 -0.012354 平均占线语音呼叫数 -0.012965 完成数据调用的平均数 -0.013026 平均掉线语音呼叫数 -0.013157 过去六个月的平均月费用 -0.013646 过去三个月的平均月费用 -0.013932 尝试数据调用的平均数 -0.013940 平均月费用 -0.014820 客户生命周期内的总通话次数 -0.017114 计费调整后的呼叫总数 -0.017572 平均掉线或占线呼叫数 -0.017906 预计收入 -0.018576 客户生命周期内的总使用分钟数 -0.018654 计费调整后的总分钟数 -0.019213 是否双频 -0.019965 家庭成人人数 -0.024942 客户整个生命周期内的平均每月通话次数 -0.025390 平均三通电话数 -0.025761 客户生命周期内的平均每月使用分钟数 -0.026500 是否翻新机 -0.029043 平均呼叫等待呼叫数 -0.030874 一分钟内的平均呼入电话数 -0.033057 过去六个月的平均每月通话次数 -0.034927 平均未接语音呼叫数 -0.036626 平均客户服务电话次数 -0.037086 当月使用分钟数与前三个月平均值的百分比变化 -0.038794 使用客户服务电话的平均分钟数 -0.040060 过去六个月的平均每月使用分钟数 -0.040761 平均接听语音电话数 -0.041215 过去三个月的平均每月通话次数 -0.044770 平均非高峰语音呼叫数 -0.047101 尝试拨打的平均语音呼叫次数 -0.049644 平均尝试调用次数 -0.050090 平均呼入和呼出高峰语音呼叫数 -0.050286 使用高峰语音通话的平均不完整分钟数 -0.051437 过去三个月的平均每月使用分钟数 -0.051533 平均完成的语音呼叫数 -0.052980 平均已完成呼叫数 -0.053415 已完成语音通话的平均使用分钟数 -0.054818 每月平均使用分钟数 -0.060694 账户消费限额 -0.066694 当前手机价格 -0.101998 Name: 是否流失, dtype: float64
对于目标’是否丢失‘ 相关系数较高的有当前设备使用天数 (0.117242)、 手机网络功能(0.088076)、当前手机价格 ( -0.101998)等。后面可以围绕相关系数较强的特征做进一步的特征构造、特征增强等。
卡方检验
在做了皮尔森相关性分析后发现,每个特征对于目标特征的相关性都非常低,甚至都不能算得上是弱相关。在查阅了一些资料后,发现对于回归问题,也就是目标特征是连续值时,用皮尔森相关性来检验效果比较好。对于分类问题,目标特征是离散值时,可以考虑用卡方检验。
这里还需要注意一点是:
卡方检验输入的值不能为负值不然会报错 “Input X must be non-negative.”
也就是说在卡方检验前最好先进行区间缩放,是整个区间落在[0,1]内。
from sklearn.preprocessing import MinMaxScaler
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
copy_train = train.copy()
#先进行区间缩放
MinMax_train = MinMaxScaler().fit_transform(copy_train)
#选择K个最好的特征,返回选择特征后的数据
SelectKBest(chi2, k=30).fit_transform(MinMax_train,train['是否流失'])
三、特征工程
数据预处理
无量纲化
无量纲化主要包括标准化和区间缩放,标准化是将满足正态分布的特征进一步转换为标准正态分布。区间缩放是将特征值缩放到某个区间内,常见的有[0,1]。
标准化需要计算特征的均值和标准差,在sklearn中可以直接调用。
from sklearn.preprocessing import StandardScaler
#返回值为标准化后的数据
StandardScaler().fit_transform()
区间缩放则常用最值进行缩放,也可以直接调用。
from sklearn.preprocessing import MinMaxScaler
#区间缩放,返回值为缩放到[0, 1]区间的数据
MinMaxScaler().fit_transform()
二值化
对于某些特征,我们只要定性考虑时,可以对其设定一个阈值,对大于阈值的分为一类值(赋值为1),小于阈值的分为另一类(赋值为0)。则可以减少冗余特征信息。
from sklearn.preprocessing import Binarizer
#二值化,阈值设置为10,返回值为二值化后的数据
Binarizer(threshold=10).fit_transform()
OneHot编码
有些特征的值之间并没有关系,例如当我们有[猫,狗,鸡]这样的输入我们不能直接令其编码为[1,2,3],这样会人为引入了大小关系。OneHot编码为[[1,0,0],[0,1,0],[0,0,1]]则避免了这一情况。
from sklearn.preprocessing import OneHotEncoder
#独热编码
OneHotEncoder().fit_transform()
特征选择
当对数据进行预处理过后,还需要进行特征选择,选择出对于模型来说比较重要,有意义的特征,这样模型在学习的时候才能学到比较关键的信息,准确性才能高。
特征选择可以分为以下三种方法:
- Filter 过滤法
- Wrapper 包装法
- Embedded 嵌入法
Filter 过滤法
过滤法的基本想法就是对每个特征值计算其相对于目标特征的信息值,得到多个结果。然后将多个服从某种计算方法的结果按照从大到小排序,输出前 k 个特征。显然,这样复杂度大大降低。那么关键的问题就是使用什么样的方法来度量,目标是选取目标特征关联最密切的一些特征。
- Pearson相关系数
- 卡方验证
- 互信息和最大信息系数
- 方差选择法
Pearson相关系数:皮尔森相关系数衡量的是变量之间的线性相关性,结果的取值区间为[-1,1] , -1 表示完全的负相关), +1 表示完全的正相关, 0 表示没有线性相关性。
卡方验证:卡方检验是检验类别型变量的相关性的常用方法
互信息和最大信息系数:互信息也是评价类别型变量的相关性的常用方法
方差选择法:方差选择法,先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。
Wrapper 包装法
Wrapper的核心思想是递归消除。递归消除特征法使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练。过程如图。
Embedded 嵌入法
和Wrapper 一样,嵌入法也是一种特征选择和算法训练同时进行的特征选择方法,其过程为先使 用使用带惩罚项的基模型进行训练,得到各个特征的权值系数,根据权值系数从大到小选择特征。嵌入法以惩罚项为核心进行特征选择,除了筛选出特征外,同时也进行了降维。
“经验来说,过滤法更快速,但更粗糙。包装法和嵌入法更精确,比较适合具体到算法去调整,但计算量比较大,运行时间长。当数据量很大的时候,优先使用方差过滤和互信息法调整,再上其他特征选择方法”。
Baseline
运行Baseline,分别跑了lgb、xgb以及catboost,分数如图。
根据结果可以看到,lgb的分数达到0.839这是没有对特征做太多处理,直接喂给模型的结果。
反向上分
后续按照前面的特征选择等方法做了尝试,做了特征选择如:Filter做特征选择、Wrapper做特征选择、hyperopt调参等等,结果没有提升反而下降了。甚至后面一度只有0.5,怀疑是做特征时有错误,导致学的都是错的。看来想要提分还是要先从特征入手,如何构建好的特征给模型可能就是对于这次比赛需要着重思考的地方吧。
每天都在反向上分,后续还会继续尝试做好特征并更新进度的。
参考文章
《精通特征工程》 爱丽丝·郑 阿曼达·卡萨丽
《机器学习算法竞赛实战》 王贺
《阿里云天池大赛赛题解析----机器学习篇》 天池平台
自动机器学习超参数调整(贝叶斯优化) - FlyingWarrior - 博客园 (cnblogs.com)
一种超参数优化技术-Hyperopt - 人工智能遇见磐创 - 博客园 (cnblogs.com)
ds-ai-tech-notes/8.md at master · apachecn/ds-ai-tech-notes · GitHub
ds-ai-tech-notes/7.md at master · apachecn/ds-ai-tech-notes · GitHub