乐趣区

关于python:共享单车数据集探索及可视化

剖析背景

剖析目标

  • 剖析摩拜单车订单的相干数据对骑行时长的影响状况,以此作为业务经营优化的参考和根据(因为原数据集中无订单金额的数据,又因摩拜单车是以骑行时长作为计费规范的,骑行时长是影响订单金额大小的最重要因素,故本剖析针对骑行时长开展)。
  • 次要集中在剖析骑行工夫(包含工作日 / 双休日、顶峰时段 / 非顶峰时段两个维度)、骑行地位、用户价值这些变量对骑行时长的影响上。

数据集概要

  • 原数据集来自 Udacity 提供的摩拜单车上海城区 2016 年 8 月随机抽样百万条用户应用数据,共有 102361 条订单记录,蕴含终点、目的地、租赁工夫、还车工夫、用户 ID、车辆 ID、交易编号和路线轨迹信息。
  • 通过荡涤整顿和信息提取后,新数据集减少了 22 个新变量,次要用于剖析的变量为:ttl_min(骑行时长(min))、distance(骑行始末点的直线间隔(km))、daytype(工作日 / 双休日)、hourtype(顶峰时段 / 非顶峰时段)、ring_stage(内环内 / 中环内 / 外环内 / 外环外)、rate(高价值用户 / 中等价值用户 / 低价值用户)这六个变量。
  • 新数据集在应用过程中亦去除了大量骑行速度、间隔、时长的异样记录,最终的订单记录数量为 102338 条。

剖析论断

用户行为总结

在数据摸索过程中,发现骑行工夫(包含工作日 / 双休日、顶峰时段 / 非顶峰时段)、骑行区域和用户价值这四个变量均会对骑行时长产生影响。当顺次限定四个变量条件后,能够发现:

  • 在骑行地理位置或用户价值条件雷同的状况下,骑行工夫对于均匀骑行时长的法则显著,顶峰时段和双休日的均匀骑行时长高于非顶峰时段和工作日;
  • 总体上,用户价值越高、骑行时长越长,骑行区域越远离市中心、骑行时长越长,但前者对于骑行时长的影响远小于后者。

在关注类型变量对于骑行时长的影响之外,又有以下发现:

  • 比拟不同骑行地理位置和用户价值类型下,工作日和顶峰时段的数据点散布特色高度相似,阐明工作日和顶峰时段的用车行为特色类似;
  • 高价值用户更多地散布在内环范畴内。

优化倡议总结

针对上述用户行为数据分析论断,提出以下优化倡议:

  • 鉴于骑行工夫(工作日 / 双休日、顶峰时段 / 非顶峰时段)高度影响骑行时长的特色,能够不同的骑行工夫为划分规范,针对性地推出骑行套餐、营销流动,以晋升订单频次和订单金额(如不同时段的骑行徽章处分、限时收费骑、遇见顶峰车等形式)
  • 鉴于远离市区用户单次生产高(骑行时长长)、生产频次低(高价值用户少)的行为特色,可按骑行地理位置推出相应骑行套餐,以晋升该类地区用户的生产频次、进步他们对于应用摩拜单车的依赖度
  • 鉴于工作日和顶峰时段的用户行为特色类似,因而在设计经营流动计划时,可合并思考

其余阐明

  • 因原始数据集中的信息量过少,可供剖析的内容无限,扩充数据集信息和范畴后,可用于剖析的内容包含但不限于:
  • 依据用户在 APP 内的点击数据来剖析要害门路转化率,以此判断某一地区的单车供需是否均衡,以供单车投放量和调度效率的优化
  • 以月度、季度为单位的单车应用状况的周期性法则,以此作为营销方案设计和优化的参考和根据

骑行券、骑行套餐、充值返现等优惠活动对用户骑行行为的影响,以此作为用户精细化经营或营销方案设计的参考和根据
剖析过程

剖析过程

次要关注四个类型变量对于骑行时长的影响。首先介绍骑行时长、骑行间隔的数据分布状况。而后通过绘制小提琴图,察看到两者随类型变量的变动而高度类似的数据特色,进而断定只需关注骑行时长这一要害指标和四个类型变量之间的关系即可。最初通过点图绘制在管制不同条件的类型变量的状况下,其余变量对于骑行时长的影响。

# 导入所有须要用到的库,并将图表设置为间接显示
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb

%matplotlib inline

# 革除输入中的正告
import warnings
warnings.simplefilter("ignore")

# 导入荡涤整顿后的数据集
df_e = pd.read_csv('mobike_master.csv')

# 将对应列转换成类别变量
order_dict = {'ring_stage': ['inside inner ring', 'inside middle ring', 'inside outer ring', 'outside outer ring'],
              'rate': ['high-value user', 'middle-value user', 'low-value user'],
              'daytype': ['weekdays', 'weekends'],
              'hourtype': ['rush hours', 'non-rush hours']}
for var in order_dict:
    order = pd.api.types.CategoricalDtype(ordered = True, categories = order_dict[var])
    df_e[var] = df_e[var].astype(order)

# 数据清理,去除大量在骑行速度、骑行时长和骑行间隔上显著异样的数据
df_e['speed'] = df_e['distance'] / (df_e['ttl_min'] / 60)
df_e = df_e[-(((df_e['speed'] < 12) | (df_e['speed'] > 20)) & ((df_e['ttl_min'] > 720) | (df_e['distance'] > 50)))]

骑行时长散布

骑行时长的数据范畴十分大,最小值为 1 分钟,最大值为 666 分钟,且出现长尾散布,绝大多数骑行时长较短,应用 log 转换 x 轴绘图能够发现,骑行时长出现右偏态散布,峰值呈现在 7 -10 分钟之间。

bins = 10 ** np.arange(0, np.log10(df_e.ttl_min.max()) + 0.15, 0.15)
plt.hist(data = df_e, x = 'ttl_min', bins = bins);
plt.xscale('log')
xticks = (1, 2, 5, 10, 20, 50, 100, 200, 500)
plt.xticks(xticks, xticks);
plt.xlabel('Riding Duration (min)');
plt.title('Distribution of Riding Duration');

骑行间隔散布

数据集中的骑行间隔用的是骑行始末点之间的直线间隔作为估算的,该数据的范畴同样十分大,最小值为 0.146km,最大值为 32.497km,且同样出现长尾散布,绝大多数骑行间隔较短,极少数骑行间隔较长,应用 log 转换 x 轴绘图能够发现,骑行间隔出现右偏态散布,峰值呈现在 0.7-1.3 公里之间。

bins = 10 ** np.arange(np.log10(df_e.distance.min()), np.log10(df_e.distance.max()) + 0.08, 0.08)
plt.hist(data = df_e, x = 'distance', bins = bins);
plt.xscale('log')
xticks = (0.1, 0.2, 0.5, 1, 2, 5, 10, 20)
plt.xticks(xticks, xticks);
plt.xlabel('Riding Distance (km)');
plt.title('Distribution of Riding Distance');

骑行时长和骑行间隔与其余变量的关系

  • 在骑行工夫方面,发现双休日和顶峰时段的骑行时长和骑行间隔的中位数相较工作日和非顶峰时段都要更高(除双休日的骑行间隔稍微低于工作日);
  • 在骑行区域方面,一旦用户骑行区域在内环之外,骑行时长和骑行间隔的中位数均随着离市中心越远而变得越高,可能是因为越凑近市区,用户出发点和目的地之间的间隔越来越大;
  • 在用户价值方面,骑行时长和骑行间隔的中位数均随着用户价值变低而变低。

通过比拟,发现骑行时长和骑行间隔这两个数值变量的数据分布特色和分类状况下的变动特色简直齐全一样,后续能够不再对骑行间隔做剖析,起因如下:一方面骑行时长是原始数据中的实在数据(骑行间隔是通过骑行始末点估算的直线间隔),另一方面摩拜单车是依据骑行时长作为付费根据的,故此,在数据特色高度类似的状况下,抉择数据品质和价值更高的骑行时长作为后续剖析指标。

# 因为骑行时长和骑行间隔的数据均出现十分长的长尾,所以先对两个数据进行 log 转化,以便更清晰地察看数据特色
df_e['log_ttl_min'] = np.log10(df_e['ttl_min'])
df_e['log_distance'] = np.log10(df_e['distance'])
cat_vars = ['daytype', 'hourtype', 'ring_stage', 'rate']
fig, ax = plt.subplots(ncols = 4, nrows = 2, figsize = [20,10])
color = sb.color_palette()[0]
for i in range(len(cat_vars)):
    var = cat_vars[i]
    # 画第一行的图
    sb.violinplot(data = df_e, x = var, y = 'log_ttl_min', ax = ax[0, i], color = color);
    ttl_min_ticks = [1, 2, 5, 10, 20, 50, 100, 200, 500]
    ax[0, i].set_yticks(np.log10(ttl_min_ticks));
    ax[0, i].set_yticklabels(ttl_min_ticks);
    ax[0, i].set_ylabel('Riding Duration (min)');
    if i == 2:
        xlabels = ax[0, i].get_xticklabels()
        ax[0, i].set_xticklabels(xlabels, rotation = 10);
    # 画第二行的图
    sb.violinplot(data = df_e, x = var, y = 'log_distance', ax = ax[1, i], color = color);
    distance_ticks = [0.1, 0.2, 0.5, 1, 2, 5, 10, 20]
    ax[1, i].set_yticks(np.log10(distance_ticks));
    ax[1, i].set_yticklabels(distance_ticks);
    ax[1, i].set_ylabel('Riding Distance (km)');
    if i == 2:
        xlabels = ax[1, i].get_xticklabels()
        ax[1, i].set_xticklabels(xlabels, rotation = 10);
plt.suptitle('riding duration and distance by other features', fontsize = 'xx-large');

在给定骑行工夫的条件下,骑行时长随骑行区域和用户价值的变化规律

  • 总体上,除了内环以内的数据外,其余区域的均匀骑行时长均随着骑行终点离市中心越远而变得越高
  • 除在外环以外的双休日和非顶峰时段外,高价值用户的均匀骑行时长均是最高的
  • 总体上,顶峰时段和双休日的均匀骑行时长要高于非顶峰时段和工作日
  • 从第一列的高低两张图中大抵能够看出,工作日和顶峰时段中,均匀骑行时长随着用户价值变量和骑行区域变量的扭转而产生的变动特色是十分类似的,这可能是因为工作日和顶峰时段的用户中,上班族占了大多数,而这些上班族领有类似的用车行为特色
# 自定义函数,绘制控制变量条件下的 pointplot 图
def ppltgrid(row_dict):
    for var in row_dict:
        firstplot = list(row_dict.keys())[0]    # 设置第一个绘图的编号,以便后续获取第一个绘图 y 轴的操作
        a0,b0,c0 = var.split(',')
        a,b,c = int(a0), int(b0), int(c0)
        plt.subplot(a,b,c)
        flagid, flag, hue, x = row_dict[var]['flagid'], row_dict[var]['flag'], row_dict[var]['hue'], row_dict[var]['x']
        ax = sb.pointplot(data = df_e[df_e[flagid] == flag], x = x, y = 'log_ttl_min', hue = hue,
                          palette = 'Blues_r', linestyles = '', dodge = 0.1);
        ax.set_title("{}'s riding duration across {} and {}".format(flag, x, hue), fontsize ='small');
        ylocs = np.arange(1, 1.25, 0.025)
        ylabels = np.round(np.power(10, ylocs), 2)
        ax.set_yticks(ylocs);
        ax.set_yticklabels(ylabels);
        ax.set_yticklabels([],minor = True);    # 不显示默认的次要刻度
        if c % b == 1:    # 为每行的第一个图设置 y 轴标签,其余图则不显示,以防遮蔽图表内容
            ax.set_ylabel('Mean Riding Duration (min)');
        else:
            ax.set_ylabel('');
        if x == 'ring_stage' or x == 'rate':    # ring_stage 和 rate 的类别名称过长,将字体变小
            xlabels = ax.get_xticklabels()
            ax.set_xticklabels(xlabels, fontsize = 'small');
        if var == firstplot:
            ylim = ax.get_ylim()    # 获取第一个绘图的 y 轴
        else:
            plt.ylim(ylim);    # 使第二个开始的所有绘图放弃和第一个绘图统一的 y 轴范畴
plt.figure(figsize = [15, 10])
row_dict = {'2,2,1': {'flagid': 'daytype', 'flag': 'weekdays', 'hue': 'rate', 'x': 'ring_stage'},
            '2,2,2': {'flagid': 'daytype', 'flag': 'weekends', 'hue': 'rate', 'x': 'ring_stage'},
            '2,2,3': {'flagid': 'hourtype', 'flag': 'rush hours', 'hue': 'rate', 'x': 'ring_stage'},
            '2,2,4': {'flagid': 'hourtype', 'flag': 'non-rush hours', 'hue': 'rate', 'x': 'ring_stage'}}
ppltgrid(row_dict)

在给定骑行区域和用户价值的条件下,骑行时长随骑行工夫的变化规律

  • 别离限定骑行地理位置变量和用户价值变量,察看骑行工夫对均匀骑行时长的影响,能够发现数据点散布的绝对地位高度类似,阐明骑行工夫对于均匀骑行时长的法则显著,即在骑行地理位置或用户价值条件雷同的状况下,顶峰时段和双休日的均匀骑行时长高于非顶峰时段和工作日。
  • 比拟第一行和第二行的数据点散布特色,能够发现在用户价值变量视角下的数据点,随着用户价值由高到低,纵向变动幅度远低于第一行骑行地位视角下的纵向变动幅度,阐明用户价值对均匀骑行时长的作用较小,远小于骑行地位对其的影响。
plt.figure(figsize = [20,10])
row_dict = {'2,4,1': {'flagid':'ring_stage', 'flag': 'inside inner ring', 'hue': 'daytype', 'x': 'hourtype'},
            '2,4,2': {'flagid':'ring_stage', 'flag': 'inside middle ring', 'hue': 'daytype', 'x': 'hourtype'},
            '2,4,3': {'flagid':'ring_stage', 'flag': 'inside outer ring', 'hue': 'daytype', 'x': 'hourtype'},
            '2,4,4': {'flagid':'ring_stage', 'flag': 'outside outer ring', 'hue': 'daytype', 'x': 'hourtype'},
            '2,4,5': {'flagid':'rate', 'flag': 'high-value user', 'hue': 'daytype', 'x': 'hourtype'},
            '2,4,6': {'flagid':'rate', 'flag': 'middle-value user', 'hue': 'daytype', 'x': 'hourtype'},
            '2,4,7': {'flagid':'rate', 'flag': 'low-value user', 'hue': 'daytype', 'x': 'hourtype'}}
ppltgrid(row_dict)

代码已提交至 Github
更多内容请关注我的集体博客

参考资料

  • 查问上海天文中心点——国际饭店的经纬度坐标(高德开放平台):https://lbs.amap.com/console/…
  • 上海内环中环外环大抵范畴:https://zhidao.baidu.com/ques…
  • 摩拜单车 2016 年 8 月免费规范:http://www.33lc.com/article/7…
退出移动版