本文记录了整个项目需求分析与实现的过程,主要任务是使用SQL完成数据提取过程,接着利用Python进行数据分析,并连接到PowerBI实现可视化,发现问题-分析问题-解决问题。
(一)、业务背景介绍
Adventure Works Cycles是基于微软AdventureWorks示例数据库的虚拟公司,是一家大型跨国制造公司。该公司向北美,欧洲和亚洲商业市场生产和销售金属和复合材料自行车。2020年7月业务部门需要向上级汇报2019年1月至今的自行车销售情况,为精细化运营提供数据支持,精准定位目标客户群体。
(二)、需求分析与实现
分析流程
(三)详情分析
数据说明:
三张表:
*1、 订单明细表 (ods_sales_orders)
- 2、时间地区产品聚合表或产品销售信息事实表(dw_customer_order)
*3、 每日新增用户表(ods_customer)
目录
- 一、自行车整体销售表现
- 二、2020年6月自行车地域销售表现
- 三、2020年6月自行车产品销售表现
- 四、用户行为分析
- 五、总结
一、自行车整体销售表现
1.1 从数据库读取源数据: dw_customer_order
engine = create_engine('mysql+pymysql://用户名:密码@ip地址/数据库名称')
sql='select * from dw_customer_order'
df = pd.read_sql_query(sql,engine)
#strftime日期转字符串,strptime字符串转日期
gather_customer_order['create_year_month1']=gather_customer_order['create_date'].apply(lambda x:x.strftime('%Y-%m'))
筛选出数据表中的自行车数据
gather_customer_order = gather_customer_order[gather_customer_order['cplb_zw']=='自行车']
gather_customer_order.reset_index(inplace=True)
gather_customer_order.info()
1.2自行车整体销量表现
#按照年月分组,对月销售数量和月销售金额进行求和,并按照日期降序进行排序,方便计算环比
"""
环比有环比增长速度和环比发展速度两种计算方法。
环比增长速度=(本期数-上期数)/上期数*100%,反映本期比上期增长了多少。
环比发展速度=本期数/上期数*100%,环比发展速度是报告期水平与前一水平之比,反映现象在前后两期的发展变化情况。
"""
overall_sales_performance =gather_customer_order.groupby('create_year_month1').agg({'order_num':'sum','sum_amount':'sum'}).sort_index(ascending=True).reset_index()
销售数量环比
overall_sales_performance['order_num_diff']=overall_sales_performance['order_num'].pct_change().fillna(0)
销售金额环比
#销售金额环比
overall_sales_performance['sum_amount_diff']=overall_sales_performance['sum_amount'].pct_change().fillna(0)
存到sql数据库
engine1 = sqlalchemy.create_engine('mysql+pymysql://用户名:密码@ip地址/数据库名称')
"""
if_exists:表如果存在怎么处理
append:追加
replace:删除原表,建立新表再添加
fail:什么都不干
index=False:不插入索引index
"""
overall_sales_performance.to_sql('pt_overall_sale_performance_1_zhaoyqiu',engine1,index=False,if_exists='replace')
由图可知,在2019年1月至2020年7月期间,2020年6月自行车销售量最多,为28651辆;较5月份增长五倍。
由图可知,在2019年1月至2020年7月期间,2020年6月自行车销售金额最多,为52百万元;同时该月销售额环比增速也是最快的,较5月份增长高达5倍。
另外可以发现,自行车销售量和销售金额趋势保持一致。
从上述图示中可以明显看到2020年4月到6月,用户销量和销售额明显骤增,而6月之后又随之骤减。可以再深入挖掘具体是什么原因造成该现象的出现?是常态还是突发情况?如果是突发情况?该如何维持该现象以促业绩的增长?
二、2020年6月自行车地域销售表现
2.1 源数据 dw_customer_order,清洗筛选5、6月数据
gather_customer_order['create_year_month1'].unique()
gather_customer_order_5_6=gather_customer_order[(gather_customer_order['create_year_month1']=='2020-05')|(gather_customer_order['create_year_month1']=='2020-06')]
2.2 2020年5-6月自行车区域销售表现
2.2.1 按照'chinese_territory','create_year_month',区域、月份分组,订单量求和、销售金额求和,赋予变量gather_customer_order_5_6_group,记得重置索引
gather_customer_order_5_6_group=gather_customer_order_5_6.groupby(['chinese_territory','create_year_month1']).agg({'order_num':'sum','sum_amount':'sum'}).reset_index()
2.2.2 求不同区域5月、6月的环比
# 提取包含的所有区域并存储在列表中,为计算环比做准备
#1、获得去重区域的列表region_list
region_list=list(gather_customer_order_5_6_group['chinese_territory'].unique())
region_list
#pct_change()当前元素与先前元素的相差百分比
order_x=pd.Series([])
amount_x=pd.Series([])
for i in region_list:
a=gather_customer_order_5_6_group.loc[gather_customer_order_5_6_group['chinese_territory']==i]['order_num'].pct_change().fillna(0)
b=gather_customer_order_5_6_group.loc[gather_customer_order_5_6_group['chinese_territory']==i].sum_amount.pct_change().fillna(0)
order_x=order_x.append(a)
amount_x=amount_x.append(b)
gather_customer_order_5_6_group['order_diff']=order_x
gather_customer_order_5_6_group['amount_diff']=amount_x
"""
生成order_x和amount_x两个空Series,分别用于储存销售量环比和销售金额环比。通过for循环,对各个区域进行遍历。同时,对各个区域
通过pct_change()函数计算环比。因为这里没有9月数据,所以10月环比为NaN,因此通过fillna(0)来填充。之后将销售量环比和销售金额
环比分别存入order_x和amount_x两个Series。最后在原表格后面新增两列,将之前的两个Series接在原表最右侧
"""
#5月6月各个区域自行车销售数量、销售金额环比
gather_customer_order_5_6_group.head()
2.2.3、将最终的gather_customer_order_5_6_group的DataFrame存入Mysql的pt_bicy_november_territory_2当中。
engine1=sqlalchemy.create_engine('mysql+pymysql://用户名:密码@ip地址/数据库名称')
gather_customer_order_5_6_group.to_sql('pt_bicy_november_territory_2_zhaoyqiu',engine1,index=False,if_exists='append')
通过上图,可以发现:
- 8个区域中,只有华中和华南两个地区的6月环比增速低于5月。
- 在8个区域中,和5月份相比增速最快的是台港澳地区,达7倍多。
- 其中,2020年6月华东地区在8个区域中销量最大,达7602辆。
可以得出初步结论:6月销量骤增的原因有二:
一是因为3/4的地区销量均在增加;
二是因为6月华东地区的销量明显大于5月华东地区的销量,且华东地区的销量贡献了整体销量的大部分。
2.3 2020年5、6月华东地区自行车销售量top10城市环比
2.3.1、筛选华东地区6月自行车交易数据 赋予变量为gather_customer_order_6
gather_customer_order_6=gather_customer_order[(gather_customer_order['create_year_month1']=='2020-06')&\
(gather_customer_order['chinese_territory']=='华东')].reset_index()
gather_customer_order_6.head()
2.3.2、将gather_customer_order_6按照chinese_city城市分组,求和销售数量order_num,最终查看华东地区6月自行车销售数量前十城市,赋予变量gather_customer_order_city_head
gather_customer_order_city_head=gather_customer_order_6.groupby('chinese_city').agg({'order_num':'sum'}).sort_values('order_num',ascending=False).head(10)
gather_customer_order_city_head.reset_index(inplace=True)
gather_customer_order_city_head.head()
2.3.3、根据6月gather_customer_order_city_head的前十城市,查看5月6月华东地区自行车销售数据gather_customer_order_5_6,赋予变量gather_customer_order_5_6_head
#得到5,6月华东地区数据
gather_customer_order_5_6_top1_area=gather_customer_order_5_6[gather_customer_order_5_6['chinese_territory']=='华东']
gather_customer_order_5_6_top1_area['chinese_territory'].unique()
#筛选销售前十城市,5月6月自行车销售数据
gather_customer_order_5_6_head = gather_customer_order_5_6_top1_area[gather_customer_order_5_6_top1_area.chinese_city.isin(list(gather_customer_order_city_head.chinese_city))]
gather_customer_order_5_6_head.head()
2.3.4、根据gather_customer_order_5_6_head,按城市按月分组计算前十城市,自行车销售数量销售金额,赋予变量gather_customer_order_city_5_6
gather_customer_order_city_5_6=gather_customer_order_5_6_head.groupby(['chinese_city','create_year_month1']).agg({'order_num':'sum','sum_amount':'sum'}).reset_index()
2.3.5、根据gather_customer_order_city_5_6,计算前10的销售金额及销售量环比,最终形成结果gather_customer_order_city_5_6
#销售量
gather_customer_order_city_5_6_order_head=gather_customer_order_city_5_6.sort_values('order_num',ascending=False).reset_index().head(10)
#销售金额
gather_customer_order_city_5_6_amount_head=gather_customer_order_city_5_6.sort_values('sum_amount',ascending=False).reset_index().head(10)
#计算前十城市环比
city_top_list = list(gather_customer_order_city_head.chinese_city)
city_top_list
order_top_x = pd.Series([])
amount_top_x = pd.Series([])
for i in city_top_list:
a=gather_customer_order_city_5_6[gather_customer_order_city_5_6.chinese_city==i]['order_num'].pct_change().fillna(0)
b=gather_customer_order_city_5_6[gather_customer_order_city_5_6.chinese_city==i]['sum_amount'].pct_change().fillna(0)
order_top_x=order_top_x.append(a)
amount_top_x =amount_top_x.append(b)
#order_diff销售数量环比,amount_diff销售金额环比
gather_customer_order_city_5_6['order_diff']=order_top_x
gather_customer_order_city_5_6['amount_diff']=amount_top_x
gather_customer_order_city_5_6.head(5)
2.3.6、将最终的gather_customer_order_city_10_11的DataFrame存入Mysql的pt_bicy_november_october_city_3当中。
engine1=sqlalchemy.create_engine('mysql+pymysql://用户名:密码@ip地址/数据库名称')
gather_customer_order_city_10_11.to_sql('pt_bicy_november_october_city_3_zhaoqiu',engine1,index=False,if_exists='replace')
由图可知:
- 上海市、杭州市和南京市是华东地区6月份自行车销售市场的主力军,占比48.86%,因此后期可以采取措施保持现有市场活力。
- 徐州市环比增速最快,达7倍多,表名该城市有较大发展潜力,可以重点关注。
三、2020年6月自行车产品销售表现
3.1、数据源 dw_customer_order
3.2 整体细分市场销量表现
3.2.1、gather_customer_order表利用groupby聚合月份,求每个月自行车的销售数量,赋值给变量gather_customer_order_group_month
gather_customer_order_group_month=gather_customer_order.groupby('create_year_month1').agg({'order_num':'sum'}).reset_index()
3.2.2、利用pd.merge模块合并自行车销售信息表(gather_customer_order)+自行车每月累计销售数量表(gather_customer_order_group_month)赋值变量给order_num_proportion
order_num_proportion=pd.merge(gather_customer_order,gather_customer_order_group_month,on='create_year_month1')
3.2.3、计算自行车销量/自行车每月销量占比,计算结果形成新的列'order_proportion'
#自行车销量/自行车每月销量占比
order_num_proportion['order_proportion'] = order_num_proportion.apply(lambda x:x.order_num_x/x.order_num_y, axis=1)
-
公路自行车一直占比最多,且每月占比均超过50%,是各类自行车中最畅销的产品,其次销量往下的依次是山地自行车和旅游自行车。
和5月份相比,旅游自行车销售量环比增速最快,达5.9%,公路自行车的销量环比增速尾随其后。
由以上两点可知,6月份公司销售额的增长的原因有二,
一是因为公路自行车的大幅销量,二是因为公路自行车的增速较大,给个公司带来了巨大的收益。因此,公司可以考虑继续加大对公路自行车的投入力度以及关注提升旅游自行车销量的方法。
3.3、公路/山地/旅游自行车细分市场表现
3.3.1、查看cpzl_zw有哪些产品子类
gather_customer_order['cpzl_zw'].unique()
公路自行车细分市场销量表现
gather_customer_order_road = gather_customer_order[gather_customer_order['cpzl_zw'] == '公路自行车']
gather_customer_order_road_month=gather_customer_order_road.groupby(['create_year_month1','product_name']).agg({'order_num':'sum'}).reset_index()
gather_customer_order_road_month=pd.merge(gather_customer_order_road_month,gather_customer_order_road_month_sum,on='create_year_month1')
gather_customer_order_road_month.head()
- 2020年6月公路自行车,销量排前三的产品依次为:
Road-750 Black,Road-150 Red,Road-550-W Yellow。该排名和全年整体数据样本中的产品销量排名一致。
山地自行车细分市场销量表现
#筛选
gather_customer_order_mountain=gather_customer_order[gather_customer_order['cpzl_zw']=='山地自行车']
#山地自行车不同型号产品销售数量
gather_customer_order_mountain_month=gather_customer_order_mountain.groupby(['create_year_month1','product_name']).agg({'order_num':'sum'}).reset_index()
# gather_customer_order_mountain_month=gather_customer_order_mountain.groupby(['create_year_month1','product_name']).order_num.sum()
#每个月山地自行车累计销售数量
gather_customer_order_mountain_month_sum = gather_customer_order_mountain_month.groupby('create_year_month1').agg({'order_num':'sum'}).reset_index()
#合并gather_customer_order_mountain_month和每月累计销量,用于计算不同型号产品的占比
gather_customer_order_mountain_month=pd.merge(gather_customer_order_mountain_month,gather_customer_order_mountain_month_sum,on='create_year_month1')
gather_customer_order_mountain_month.head()
-
全年整体数据样本中的产品销量排名前三的为:
Mountain-200 Black,Mountain-200 Silver,Mountain-400-W Silver。
- 2020年6月山地自行车,销量排前三的产品依次为:
Mountain-200 Silver,Mountain-200 Black,Mountain-400-W Silver。
这说明整体表现优良的产品在细分月份上表现也依旧优秀。
旅游自行车细分市场销量表现
gather_customer_order_tour=gather_customer_order[gather_customer_order['cpzl_zw']=='旅游自行车']
gather_customer_order_tour_month=gather_customer_order_tour.groupby(['create_year_month1','product_name']).agg({'order_num':'sum'}).reset_index()
gather_customer_order_tour_month_sum=gather_customer_order_tour_month.groupby('create_year_month1').agg({'order_num':'sum'}).reset_index()
gather_customer_order_tour_month=pd.merge(gather_customer_order_tour_month,gather_customer_order_tour_month_sum,on='create_year_month1')
gather_customer_order_tour_month.head()
将山地自行车、旅游自行车、公路自行车每月销量信息合并
gather_customer_order_month=pd.concat([gather_customer_order_road_month,gather_customer_order_mountain_month,gather_customer_order_tour_month])
gather_customer_order_month
2020年6月旅游自行车,销量排前三的产品依次为:
Touring-1000 Blue,Touring-1000 Yellow,Touring-2000 Blue。该排名和全年整体数据样本中的产品销量排名一致。
3.3.5、新增一列'order_num_proportio',为销售量占每月自行车总销售量比率
#各类自行车,销售量占每月自行车总销售量比率,记得最后加axis=1
gather_customer_order_month['order_num_proportio'] = gather_customer_order_month.apply(lambda x:x.order_num_x/x.order_num_y,axis=1)
gather_customer_order_month.rename(columns={'order_num_x':'order_month_product','order_num_y':'sum_order_month'})
计算2020年6月自行车环比
#计算6月环比,需要先筛选5、6月的数据
gather_customer_order_month.create_year_month1.unique()
#利用isin
gather_customer_order_month_5_6=gather_customer_order_month[gather_customer_order_month['create_year_month1'].isin(['2020-05','2020-06'])]
gather_customer_order_month_5_6.head()
#排序。将5月6月自行车销售信息排序。注意计算环比前一定要记得排序
gather_customer_order_month_5_6 = gather_customer_order_month_5_6.sort_values(by = ['product_name','create_year_month1'])
gather_customer_order_month_5_6.head()
product_name=list(gather_customer_order_month['product_name'].unique())
product_name1 = list(gather_customer_order_month_10_11.product_name.drop_duplicates())
len(product_name1)
#### 3.3.8、计算自行车销售数量环比,最终得到gather_customer_order_month_5_6
series=pd.Series([])
for i in product_name1:
m=gather_customer_order_month_5_6[gather_customer_order_month_5_6.product_name==i]['order_num_x'].pct_change().fillna(0)
series=series.append(m)
gather_customer_order_month_5_6.head()
gather_customer_order_month_5_6['diff']=series
#筛选出6月自行车数据
gather_customer_order_month_6=gather_customer_order_month_5_6[gather_customer_order_month_5_6['create_year_month1']=='2020-06']
四、用户行为分析
这里我们需要使用订单明细表:ods_sales_orders,ods_customer用户表,依旧注意分析2019年11月的数据
pymysql.install_as_MySQLdb()
from sqlalchemy import create_engine
#读取数据库客户信息表
engine2 = create_engine('mysql+pymysql://用户名:密码@ip地址/数据库名称')
df_CUSTOMER = pd.read_sql_query("select customer_key,birth_date,gender,marital_status from ods_customer where create_date < '2019-12-1'",con =engine2)
df_sales_orders_11 = pd.read_sql_query("select * from ods_sales_orders where create_date>='2019-11-1' and create_date<'2019-12-1'",con = engine2)
销售订单表中仅客户编号,无客户年龄性别等信息,需要将销售订单表和客户信息表合并
#pd.merge
sales_customer_order_11=pd.merge(df_sales_orders_11,df_CUSTOMER,on='customer_key',how='left')
sales_customer_order_11.head()
4.1.1 根据sales_customer_order_11['birth_date'],获取客人的年份作为新的一列,要求以字符串类型存储
# 利用split()和切片,取得客户出生年份并在表格后面新增一列储存
customer_birth_year = sales_customer_order_11['birth_date'].str.split('-').apply(lambda x: x[0] if type(x)==list else x)
customer_birth_year.name='birth_year'
sales_customer_order_11 = pd.concat([sales_customer_order_11,customer_birth_year],axis = 1)
sales_customer_order_11.head(3)
4.1、用户年龄分析
4.1.2 sales_customer_order_11['birth_year']字段修改为int类型
sales_customer_order_11['birth_year']=sales_customer_order_11['birth_year'].fillna(method='ffill').astype('int32')
sales_customer_order_11['birth_year']
计算用户年龄
sales_customer_order_11['customer_age'] = 2020 - sales_customer_order_11['birth_year']
sales_customer_order_11['customer_age']
4.1.3 利用customer_age字段,进行年龄分层,划分层次为"30-34","35-39","40-44","45-49","50-54","55-59","60-64",最终形成age_level字段
sales_customer_order_11['age_level']=pd.cut(sales_customer_order_11['customer_age'],bins=[i for i in range(30,66,5)],labels=['30-34','35-39','40-44','45-49','50-54','55-59','60-64'])
sales_customer_order_11.head()
筛选销售订单为自行车的订单信息
df_customer_order_bycle = sales_customer_order_11[sales_customer_order_11['cplb_zw'] == '自行车']
#df_customer_order_bycle = sales_customer_order_11.loc[sales_customer_order_11['cplb_zw'] == '自行车']
4.1.4 计算年龄比例,最终形成df_customer_order_bycle['age_level_rate']
#这个年龄比例指的是什么??
df_customer_order_bycle['age_level_rate'] = 1/df_customer_order_bycle.shape[0]
df_customer_order_bycle.head()
将年龄分为3个层次
#right=False表示分组左边闭合
df_customer_order_bycle['age_level2']=pd.cut(df_customer_order_bycle.customer_age,bins=[0,35,45,63],right=False,labels=['<35','35-45','>=45'])
df_customer_order_bycle.head(3)
求每个年龄段人数
age_level2_count = df_customer_order_bycle.groupby(by = 'age_level2').sales_order_key.count().reset_index()
age_level2_count
4.2、用户性别
gender_count = df_customer_order_bycle.groupby(by = 'gender').cplb_zw.count().reset_index()
df_customer_order_bycle = pd.merge(df_customer_order_bycle,age_level2_count,on = 'age_level2').rename(columns = {'sales_order_key_y':'age_level2_count'})
df_customer_order_bycle['age_level2_rate'] = 1/df_customer_order_bycle['age_level2_count']
df_customer_order_bycle = pd.merge(df_customer_order_bycle,gender_count,on = 'gender').rename(columns = {'cplb_zw_y':'gender_count'})
df_customer_order_bycle['gender_rate'] = 1/df_customer_order_bycle['gender_count']
df_customer_order_bycle.head()
五、总结
整体
- 2020年4月到6月,用户销量和销售额明显骤增,而6月之后又随之骤减。可以再深入挖掘具体是什么原因造成该现象的出现?是常态还是突发情况?如果是突发情况?该如何维持该现象以促业绩的增长?
区域 - 8个区域中,只有华中和华南两个地区的6月环比增速低于5月。
- 在8个区域中,和5月份相比增速最快的是台港澳地区,达7倍多。
- 其中,2020年6月华东地区在8个区域中销量最大,达7602辆。
可以得出初步结论:6月销量骤增的原因有二:
一是因为3/4的地区销量均在增加;
二是因为6月华东地区的销量明显大于5月华东地区的销量,且华东地区的销量贡献了整体销量的大部分。
城市 - 上海市、杭州市和南京市是华东地区6月份自行车销售市场的主力军,占比48.86%,因此后期可以采取措施保持现有市场活力。
- 徐州市环比增速最快,达7倍多,表名该城市有较大发展潜力,可以重点关注。
产品类别 - 公路自行车一直占比最多,且每月占比均超过50%,是各类自行车中最畅销的产品,其次销量往下的依次是山地自行车和旅游自行车。
- 和5月份相比,旅游自行车销售量环比增速最快,达5.9%,公路自行车的销量环比增速尾随其后。
由以上两点可以推断,6月份公司销售额的增长的原因有二,
一是因为公路自行车的大幅销量,二是因为公路自行车的增速较大,给个公司带来了巨大的收益。因此,公司可以考虑继续加大对公路自行车的投入力度以及关注提升旅游自行车销量的方法。