Uber打车用户留存情况预测
1. 项目概况
1.1 项目背景与定义
为了辨别打车用户特征对于留存情况的影响以进一步提高用户留存率,Uber公开了50,000名于2014年1月注册Uber账户的用户部分信息,希望基于该信息得到具有相对可靠性及参考意义的预测模型。
为解决该二分类问题,本项目将实际运用Python相关库(Pandas, Numpy,Matplotlib, Scikit-learn等)进行分类模型的筛选、细化与评估,在得到可靠模型的同时,输出客户各特征对于Uber留存率的重要度。
1.2 项目流程
- 数据前处理与特征工程
- 数据探索分析
- 数值型特征缺失值处理
- 数值型特征异常点检测
- 留存用户标签定义
- 数据可视化与特征关联性分析
- 类别型特征指示变量转换
- 日期型特征离散
- 分类模型筛选
- 定义模型评分依据
- 尝试不同分类模型并筛选表现较好模型
- 模型交叉验证与调优
- 利用GridSearchCV调优得到max_depth, max_features, n_estimators参数较优值
- 模型验证与评估
- 结论
2. 数据前处理与特征工程
2.1 数据集概述
city
: 用户注册所在城市
phone
: 用户使用的手机系统
signup_date
: 账户注册日期,格式为‘YYYY-MM-DD’
last_trip_date
: 用户最近一次打车日期,格式为‘YYYY-MM-DD’
avg_dist
: 用户注册后前30天内平均打车距离(英里)
avg_rating_by_driver
: 司机对该用户打分的平均值
avg_rating_of_driver
: 该用户对所有司机打分的平均值
surge_pct
: 用户紧急叫车次数占总乘车次数的百分比
avg_surge
: 用户紧急叫车的平均加价倍率
trips_in_first_30_days
: 用户注册后前30天内的总乘车次数
uber_black_user
: 是否为UberBlack级别车用户
weekday_pct
: 用户工作日打车占比
2.2 数据探索分析
import pandas as pd
import numpy as np
import json
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
with open('train.json', 'r') as f:
data = json.load(f)
df = pd.DataFrame(data)
df.head()
|
avg_dist |
avg_rating_by_driver |
avg_rating_of_driver |
avg_surge |
city |
last_trip_date |
phone |
signup_date |
surge_pct |
trips_in_first_30_days |
uber_black_user |
weekday_pct |
0 |
3.67 |
5.0 |
4.7 |
1.10 |
King’s Landing |
2014-06-17 |
iPhone |
2014-01-25 |
15.4 |
4 |
True |
46.2 |
1 |
8.26 |
5.0 |
5.0 |
1.00 |
Astapor |
2014-05-05 |
Android |
2014-01-29 |
0.0 |
0 |
False |
50.0 |
2 |
0.77 |
5.0 |
4.3 |
1.00 |
Astapor |
2014-01-07 |
iPhone |
2014-01-06 |
0.0 |
3 |
False |
100.0 |
3 |
2.36 |
4.9 |
4.6 |
1.14 |
King’s Landing |
2014-06-29 |
iPhone |
2014-01-10 |
20.0 |
9 |
True |
80.0 |
4 |
3.13 |
4.9 |
4.4 |
1.19 |
Winterfell |
2014-03-15 |
Android |
2014-01-27 |
11.8 |
14 |
False |
82.4 |
df.describe()
|
avg_dist |
avg_rating_by_driver |
avg_rating_of_driver |
avg_surge |
surge_pct |
trips_in_first_30_days |
weekday_pct |
count |
50000.000000 |
49799.000000 |
41878.000000 |
50000.000000 |
50000.000000 |
50000.000000 |
50000.000000 |
mean |
5.796827 |
4.778158 |
4.601559 |
1.074764 |
8.849536 |
2.278200 |
60.926084 |
std |
5.707357 |
0.446652 |
0.617338 |
0.222336 |
19.958811 |
3.792684 |
37.081503 |
min |
0.000000 |
1.000000 |
1.000000 |
1.000000 |
0.000000 |
0.000000 |
0.000000 |
25% |
2.420000 |
4.700000 |
4.300000 |
1.000000 |
0.000000 |
0.000000 |
33.300000 |
50% |
3.880000 |
5.000000 |
4.900000 |
1.000000 |
0.000000 |
1.000000 |
66.700000 |
75% |
6.940000 |
5.000000 |
5.000000 |
1.050000 |
8.600000 |
3.000000 |
100.000000 |
max |
160.960000 |
5.000000 |
5.000000 |
8.000000 |
100.000000 |
125.000000 |
100.000000 |
df1 = df.copy()
2.3 数值型特征缺失值处理
df1.isnull().sum()
avg_dist 0
avg_rating_by_driver 201
avg_rating_of_driver 8122
avg_surge 0
city 0
last_trip_date 0
phone 396
signup_date 0
surge_pct 0
trips_in_first_30_days 0
uber_black_user 0
weekday_pct 0
dtype: int64
avg_rating_by_driver, avg_rating_of_driver和phone三个字段存在缺失值,处理方法:
* avg_rating_by_driver、avg_rating_of_driver字段:用各自统计的中位数填充
* phone字段:直接删除对应的行
df1['avg_rating_by_driver'].fillna(df1['avg_rating_by_driver'].median(), inplace=True)
df1['avg_rating_of_driver'].fillna(df1['avg_rating_of_driver'].median(), inplace=True)
df1 = df1.drop(index=df[df.phone.isnull()].index).reset_index(drop=True)
df1.isnull().sum()
avg_dist 0
avg_rating_by_driver 0
avg_rating_of_driver 0
avg_surge 0
city 0
last_trip_date 0
phone 0
signup_date 0
surge_pct 0
trips_in_first_30_days 0
uber_black_user 0
weekday_pct 0
dtype: int64
2.4 数值型特征异常点检测
fig, ax = plt.subplots(figsize=(10,6))
sns.boxplot(data=df1[['avg_rating_by_driver', 'avg_rating_of_driver', 'avg_surge']])

fig, ax = plt.subplots(figsize=(10,6))
sns.boxplot(