货品4-西北,货品2-马来西亚,这两条线路存在较大问题,急需提升时效
货品2在华东地区还有较大的市场空间,适合加大投入;同时货品2在西北配送时效长,用户拒收率高,从成本角度考虑,应该减少投入
货品1、2、4质量存在问题,建议扩大抽检范围,增大质检力度
一、数据清洗
二、数据规整
比如:增加一项辅助列:月份
三、数据分析并可视化
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei' ##显示中文字符
data = pd.read_csv('./Data/wuliu_data1/data_wuliu.csv', encoding='gbk')#encoding='utf-8'获取失败
data.info()
--- ------ -------------- -----
0 订单号 1159 non-null object
1 订单行 1161 non-null int64
2 销售时间 1161 non-null object
3 交货时间 1161 non-null object
4 货品交货状况 1159 non-null object
5 货品 1161 non-null object
6 货品用户反馈 1161 non-null object
7 销售区域 1161 non-null object
8 数量 1157 non-null float64
9 销售金额 1161 non-null object
通过info()可以看出,包含10列数据,名字、数据量、格式等,可以得出:
#删除重复记录,遇到重复保留第一行,删除后代替源数据
data.drop_duplicates(keep='first',inplace=True)
#删除缺失值(有na的整行数据,axis=0,how='any'默认)
data.dropna(axis=0,how='any',inplace=True)
#删除‘订单行’这一列:第二次运行删除操作会报错
data.drop(columns=['订单行'],inplace=True,axis=1)
#更新索引:drop=True:把原来的索引index列删除,重置index,原来的索引因为删除了行数据变乱
data.reset_index(drop=True,inplace=True)
data
订单号 | 销售时间 | 交货时间 | 货品交货状况 | 货品 | 货品用户反馈 | 销售区域 | 数量 | 销售金额 | |
---|---|---|---|---|---|---|---|---|---|
0 | P096311 | 2016-7-30 | 2016-9-30 | 晚交货 | 货品3 | 质量合格 | 华北 | 2.0 | 1052,75元 |
1 | P096826 | 2016-8-30 | 2016-10-30 | 按时交货 | 货品3 | 质量合格 | 华北 | 10.0 | 11,50万元 |
2 | P097435 | 2016-7-30 | 2016-9-30 | 按时交货 | 货品1 | 返修 | 华南 | 2.0 | 6858,77元 |
3 | P097446 | 2016-11-26 | 2017-1-26 | 晚交货 | 货品3 | 质量合格 | 华北 | 15.0 | 129,58元 |
4 | P097446 | 2016-11-26 | 2017-1-26 | 晚交货 | 货品3 | 拒货 | 华北 | 15.0 | 32,39元 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1141 | P299901 | 2016-12-15 | 2017-3-15 | 按时交货 | 货品6 | 质量合格 | 马来西亚 | 2.0 | 200,41元 |
1142 | P302956 | 2016-12-22 | 2017-3-22 | 按时交货 | 货品2 | 拒货 | 华东 | 20.0 | 79,44元 |
1143 | P303801 | 2016-12-15 | 2017-3-15 | 按时交货 | 货品2 | 质量合格 | 华东 | 1.0 | 194,08元 |
1144 | P307276 | 2016-12-22 | 2017-3-22 | 按时交货 | 货品6 | 质量合格 | 马来西亚 | 1.0 | 32,18元 |
1145 | P314165 | 2016-12-20 | 2017-3-20 | 按时交货 | 货品2 | 质量合格 | 华东 | 1.0 | 1720,92元 |
1146 rows × 9 columns
#取出‘销售金额’列,对每个数据进行清洗,自定义map函数处理万元|元
#如果python已知函数不能满足我们的需求,就使用自定义函数:map、apply
#编写自定义过滤函数:1.删除逗号,2.转成float:如果是万元则删除万元再*10000;否则,删除元
def data_deal(number):
if number.find('万元') != -1:#找到带有万元的,取出数字,去掉逗号,转成float,*10000
#number[:number.find('万元')]去掉万元
#number[:,number.find('万元')].replace(',','')将逗号替换为空
number_new = float(number[:number.find('万元')].replace(',',''))*10000
pass
else: #找到带有元的,删除元,删除逗号,转成float
if number.find('元') != -1:
number_new = float(number.replace('元','').replace(',',''))
pass
return number_new
data['销售金额'] = data['销售金额'].map(data_deal)
data
订单号 | 销售时间 | 交货时间 | 货品交货状况 | 货品 | 货品用户反馈 | 销售区域 | 数量 | 销售金额 | |
---|---|---|---|---|---|---|---|---|---|
0 | P096311 | 2016-7-30 | 2016-9-30 | 晚交货 | 货品3 | 质量合格 | 华北 | 2.0 | 105275.0 |
1 | P096826 | 2016-8-30 | 2016-10-30 | 按时交货 | 货品3 | 质量合格 | 华北 | 10.0 | 11500000.0 |
2 | P097435 | 2016-7-30 | 2016-9-30 | 按时交货 | 货品1 | 返修 | 华南 | 2.0 | 685877.0 |
3 | P097446 | 2016-11-26 | 2017-1-26 | 晚交货 | 货品3 | 质量合格 | 华北 | 15.0 | 12958.0 |
4 | P097446 | 2016-11-26 | 2017-1-26 | 晚交货 | 货品3 | 拒货 | 华北 | 15.0 | 3239.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1141 | P299901 | 2016-12-15 | 2017-3-15 | 按时交货 | 货品6 | 质量合格 | 马来西亚 | 2.0 | 20041.0 |
1142 | P302956 | 2016-12-22 | 2017-3-22 | 按时交货 | 货品2 | 拒货 | 华东 | 20.0 | 7944.0 |
1143 | P303801 | 2016-12-15 | 2017-3-15 | 按时交货 | 货品2 | 质量合格 | 华东 | 1.0 | 19408.0 |
1144 | P307276 | 2016-12-22 | 2017-3-22 | 按时交货 | 货品6 | 质量合格 | 马来西亚 | 1.0 | 3218.0 |
1145 | P314165 | 2016-12-20 | 2017-3-20 | 按时交货 | 货品2 | 质量合格 | 华东 | 1.0 | 172092.0 |
1146 rows × 9 columns
data.describe()
数量 | 销售金额 | |
---|---|---|
count | 1146.000000 | 1.146000e+03 |
mean | 76.069372 | 1.223488e+05 |
std | 589.416486 | 1.114599e+06 |
min | 1.000000 | 0.000000e+00 |
25% | 1.000000 | 2.941500e+03 |
50% | 1.000000 | 9.476500e+03 |
75% | 4.000000 | 3.576775e+04 |
max | 11500.000000 | 3.270000e+07 |
#1.销售金额==0,采用删除方法,因为数据量很小
data = data[data['销售金额']!=0]
data.describe()
#2.销售金额和数量存在严重的右偏现象,在电商领域2/8法则:20%的人贡献了80%的效率,少数人贡献了大多数的订单
# 很正常,无需处理
数量 | 销售金额 | |
---|---|---|
count | 1145.000000 | 1.145000e+03 |
mean | 76.134934 | 1.224557e+05 |
std | 589.669861 | 1.115081e+06 |
min | 1.000000 | 5.100000e+01 |
25% | 1.000000 | 2.946000e+03 |
50% | 1.000000 | 9.486000e+03 |
75% | 4.000000 | 3.577300e+04 |
max | 11500.000000 | 3.270000e+07 |
增加一项辅助列:月份
在数据中,从销售时间里提取月份,两种方法:
data['销售时间'] = pd.to_datetime(data['销售时间'])
data['月份'] = data['销售时间'].apply(lambda x: x.month)
data
订单号 | 销售时间 | 交货时间 | 货品交货状况 | 货品 | 货品用户反馈 | 销售区域 | 数量 | 销售金额 | 月份 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | P096311 | 2016-07-30 | 2016-9-30 | 晚交货 | 货品3 | 质量合格 | 华北 | 2.0 | 105275.0 | 7 |
1 | P096826 | 2016-08-30 | 2016-10-30 | 按时交货 | 货品3 | 质量合格 | 华北 | 10.0 | 11500000.0 | 8 |
2 | P097435 | 2016-07-30 | 2016-9-30 | 按时交货 | 货品1 | 返修 | 华南 | 2.0 | 685877.0 | 7 |
3 | P097446 | 2016-11-26 | 2017-1-26 | 晚交货 | 货品3 | 质量合格 | 华北 | 15.0 | 12958.0 | 11 |
4 | P097446 | 2016-11-26 | 2017-1-26 | 晚交货 | 货品3 | 拒货 | 华北 | 15.0 | 3239.0 | 11 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1141 | P299901 | 2016-12-15 | 2017-3-15 | 按时交货 | 货品6 | 质量合格 | 马来西亚 | 2.0 | 20041.0 | 12 |
1142 | P302956 | 2016-12-22 | 2017-3-22 | 按时交货 | 货品2 | 拒货 | 华东 | 20.0 | 7944.0 | 12 |
1143 | P303801 | 2016-12-15 | 2017-3-15 | 按时交货 | 货品2 | 质量合格 | 华东 | 1.0 | 19408.0 | 12 |
1144 | P307276 | 2016-12-22 | 2017-3-22 | 按时交货 | 货品6 | 质量合格 | 马来西亚 | 1.0 | 3218.0 | 12 |
1145 | P314165 | 2016-12-20 | 2017-3-20 | 按时交货 | 货品2 | 质量合格 | 华东 | 1.0 | 172092.0 | 12 |
1145 rows × 10 columns
#有的‘货品交货状况’内容,开头含有空格,需要删除首位空格 **.strip()**
data['货品交货状况'] = data['货品交货状况'].str.strip()
data1 = data.groupby(['月份','货品交货状况']).size().unstack()#按月份和货币交货状况分类,.size()计算数量
#.unstack() 可以使输出表格更直观,方便后面计算
data1['按时交货率'] = data1['按时交货']/ (data1['按时交货']+data1['晚交货'])
data1
货品交货状况 | 按时交货 | 晚交货 | 按时交货率 |
---|---|---|---|
月份 | |||
7 | 189 | 13 | 0.935644 |
8 | 218 | 35 | 0.861660 |
9 | 122 | 9 | 0.931298 |
10 | 238 | 31 | 0.884758 |
11 | 101 | 25 | 0.801587 |
12 | 146 | 18 | 0.890244 |
data2 = data.groupby(['销售区域','货品交货状况']).size().unstack()
data2['按时交货率'] = data2['按时交货']/ (data2['按时交货']+data2['晚交货'])
print(data1.sort_values(by='按时交货率', ascending=False))
货品交货状况 按时交货 晚交货 按时交货率
月份
7 189 13 0.935644
9 122 9 0.931298
12 146 18 0.890244
10 238 31 0.884758
8 218 35 0.861660
11 101 25 0.801587
data3 = data.groupby(['货品', '货品交货状况']).size().unstack()
data3['按时交货率'] = data3['按时交货'] / (data3['按时交货']+data3['晚交货'])
print(data3.sort_values(by='按时交货率', ascending=False))
货品交货状况 按时交货 晚交货 按时交货率
货品
货品5 183 4 0.978610
货品6 309 7 0.977848
货品1 27 2 0.931034
货品3 212 26 0.890756
货品2 269 48 0.848580
货品4 14 44 0.241379
data4 = data.groupby(['货品','销售区域','货品交货状况']).size().unstack()
data4['按时交货率'] = data4['按时交货'] / (data4['按时交货']+data4['晚交货'])
print(data4.sort_values(by='按时交货率',ascending=False))
货品交货状况 按时交货 晚交货 按时交货率
货品 销售区域
货品5 泰国 183.0 4.0 0.978610
货品6 马来西亚 309.0 7.0 0.977848
货品1 华北 14.0 1.0 0.933333
华南 10.0 1.0 0.909091
货品3 华北 212.0 26.0 0.890756
货品2 华东 268.0 39.0 0.872964
货品4 西北 14.0 44.0 0.241379
货品2 马来西亚 1.0 9.0 0.100000
货品1 西北 3.0 NaN NaN
销售区域:最差在西北地区,货品有1和4,主要是货品4送货过晚导致的;
货品角度:最差的是货品2,主要送往华东和马来西亚,主要是马来西亚的送货较晚导致。
data1 = data.groupby(['月份','货品'])['数量'].sum().unstack()
data1
data1.plot(kind='line')
data2 = data.groupby(['货品', '销售区域'])['数量'].sum().unstack()
data2
销售区域 | 华东 | 华北 | 华南 | 泰国 | 西北 | 马来西亚 |
---|---|---|---|---|---|---|
货品 | ||||||
货品1 | NaN | 2827.0 | 579.0 | NaN | 11.0 | NaN |
货品2 | 53811.0 | NaN | NaN | NaN | NaN | 1510.0 |
货品3 | NaN | 9073.5 | NaN | NaN | NaN | NaN |
货品4 | NaN | NaN | NaN | NaN | 5229.0 | NaN |
货品5 | NaN | NaN | NaN | 5733.0 | NaN | NaN |
货品6 | NaN | NaN | NaN | NaN | NaN | 8401.0 |
data3 = data.groupby(['月份','销售区域','货品'])['数量'].sum().unstack()
data3['货品2'].unstack() #只能查看最后分组的指标
销售区域 | 华东 | 华北 | 华南 | 泰国 | 西北 | 马来西亚 |
---|---|---|---|---|---|---|
月份 | ||||||
7 | 489.0 | NaN | NaN | NaN | NaN | 2.0 |
8 | 1640.0 | NaN | NaN | NaN | NaN | 1503.0 |
9 | 3019.0 | NaN | NaN | NaN | NaN | 1.0 |
10 | 28420.0 | NaN | NaN | NaN | NaN | NaN |
11 | 2041.0 | NaN | NaN | NaN | NaN | 1.0 |
12 | 18202.0 | NaN | NaN | NaN | NaN | 3.0 |
注:字符串字段记得在统计之前删除首位空格,.str.strip()
data['货品用户反馈'] = data['货品用户反馈'].str.strip() #取出首位空格
data1 = data.groupby(['货品', '销售区域'])['货品用户反馈'].value_counts().unstack()
# 计算拒收率
data1['拒货率'] = data1['拒货'] / data1.sum(axis=1)#按行进行求和汇总
data1['返修率'] = data1['返修'] / data1.sum(axis=1)
data1['合格率'] = data1['质量合格'] / data1.sum(axis=1)
data1.sort_values(['合格率', '返修率', '拒货率'], ascending=False)#先按合格率排序,再按返修率,拒货率; 降序
货品用户反馈 | 拒货 | 质量合格 | 返修 | 拒货率 | 返修率 | 合格率 | |
---|---|---|---|---|---|---|---|
货品 | 销售区域 | ||||||
货品3 | 华北 | 31.0 | 188.0 | 19.0 | 0.130252 | 0.079788 | 0.789219 |
货品6 | 马来西亚 | 56.0 | 246.0 | 14.0 | 0.177215 | 0.044279 | 0.777936 |
货品5 | 泰国 | 14.0 | 144.0 | 29.0 | 0.074866 | 0.155018 | 0.769108 |
货品2 | 华东 | 72.0 | 184.0 | 51.0 | 0.234528 | 0.165997 | 0.598568 |
货品1 | 华南 | 5.0 | 4.0 | 2.0 | 0.454545 | 0.174603 | 0.343963 |
西北 | NaN | 1.0 | 2.0 | NaN | 0.666667 | 0.272727 | |
华北 | NaN | 3.0 | 12.0 | NaN | 0.800000 | 0.189873 | |
货品4 | 西北 | NaN | 9.0 | 49.0 | NaN | 0.844828 | 0.152945 |
货品2 | 马来西亚 | 6.0 | 1.0 | 3.0 | 0.600000 | 0.283019 | 0.091886 |
data1
货品用户反馈 | 拒货 | 质量合格 | 返修 | 拒货率 | 返修率 | 合格率 | |
---|---|---|---|---|---|---|---|
货品 | 销售区域 | ||||||
货品1 | 华北 | NaN | 3.0 | 12.0 | NaN | 0.800000 | 0.189873 |
华南 | 5.0 | 4.0 | 2.0 | 0.454545 | 0.174603 | 0.343963 | |
西北 | NaN | 1.0 | 2.0 | NaN | 0.666667 | 0.272727 | |
货品2 | 华东 | 72.0 | 184.0 | 51.0 | 0.234528 | 0.165997 | 0.598568 |
马来西亚 | 6.0 | 1.0 | 3.0 | 0.600000 | 0.283019 | 0.091886 | |
货品3 | 华北 | 31.0 | 188.0 | 19.0 | 0.130252 | 0.079788 | 0.789219 |
货品4 | 西北 | NaN | 9.0 | 49.0 | NaN | 0.844828 | 0.152945 |
货品5 | 泰国 | 14.0 | 144.0 | 29.0 | 0.074866 | 0.155018 | 0.769108 |
货品6 | 马来西亚 | 56.0 | 246.0 | 14.0 | 0.177215 | 0.044279 | 0.777936 |
结果分析:
货品3,6,5合格率均较高,返修率比较低,说明质量还可以
货品1,2,4合格率较低,返修率较高,质量存在一定问题,需要改善
货品2在马来西亚的拒货率较高,结合按时收货率来看,货品2在马来西亚的按时收货率也很低——可以猜测马来西亚人对货品的时效性要求较高,如果达不到,则往往考虑拒绝收货。
那么是否要减小对马来西亚的投入呢?增大对华东地区的投入?