网易数据分析师 - 【项目07】 城市餐饮店铺选址分析 &【项目08】 电商打折套路解析

版权声明:欢迎转载~ 转载请注明来源及作者,谢谢! https://blog.csdn.net/qq_42442369/article/details/86737815

【项目07】 城市餐饮店铺选址分析

'''
【项目07】  城市餐饮店铺选址分析

1、从三个维度“口味”、“人均消费”、“性价比”对不同菜系进行比较,并筛选出可开店铺的餐饮类型
要求:
① 计算出三个维度的指标得分
② 评价方法:
   口味 → 得分越高越好
   性价比 → 得分越高越好
   人均消费 → 价格适中即可
③ 制作散点图,x轴为“人均消费”,y轴为“性价比得分”,点的大小为“口味得分”
   绘制柱状图,分别显示“口味得分”、“性价比得分”
   * 建议用bokeh做图
提示:
① 数据清洗,清除空值、为0的数据
② 口味指标计算方法 → 口味评分字段,按照餐饮类别分组算均值,再做标准化处理
③ 人均消费指标计算方法 → 人均消费字段,按照餐饮类别分组算均值,再做标准化处理
④ 性价比指标计算方法 → 性价比 = (口味 + 环境 + 服务)/人均消费,按照餐饮类别分组算均值,再做标准化处理
⑤ 数据计算之前,检查一下数据分布,去除异常值(以外限为标准)
   * 这里排除了高端奢侈餐饮的数据干扰
⑥ 注意,这里先分别计算三个指标,再合并数据(merge)作图,目的是指标之间的噪音数据不相互影响

2、选择一个餐饮类型,在qgis中做将上海划分成格网空间,结合python辅助做空间指标评价,得到餐饮选址位置
* 课程这里以“素菜馆为例”
课程数据
① net_population.shp → 投影坐标系,上海1km²格网内的人口密度数据
② road.shp → 投影坐标西,上海道路数据
要求:
① 通过空间分析,分别计算每个格网内的几个指标:人口密度指标、道路密度指标、餐饮热度指标、同类竞品指标
② 评价方法:
   人口密度指标 → 得分越高越好
   道路密度指标 → 得分越高越好
   餐饮热度指标 → 得分越高越好
   同类竞品指标 → 得分越低越好
   综合指标 = 人口密度指标*0.4 + 餐饮热度指标*0.3 + 道路密度指标*0.2 +同类竞品指标*0.1
③ 最后得到较好选址的网格位置的中心坐标,以及所属区域
   * 可以用bokeh制作散点图
提示:
① 道路密度指标计算方法 → 网格内道路长度
② 餐饮热度指标计算方法 → 网格内餐饮poi计数
③ 同类竞品指标计算方法 → 网格内素菜馆poi计数
④ 餐饮poi数据记得投影
⑤ 可以以“net_population.shp”为网格基础数据,做空间统计
⑥ 在qgis做空间统计之后,网格数据导出点数据,投影成wgs84地理坐标系,导出excel数据,在python做指标标准化等
⑦ 在bokeh中做散点图时,注意添加一个size字段,通过最终评分来赋值
⑧ 在bokeh中做散点图时,可以给TOP10的点用颜色区分


'''
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
% matplotlib inline

import warnings
warnings.filterwarnings('ignore') 
# 不发出警告

from bokeh.io import output_notebook
output_notebook()
# 导入notebook绘图模块

from bokeh.plotting import figure,show
from bokeh.models import ColumnDataSource
# 导入图表绘制、图标展示模块
# 导入ColumnDataSource模块

'''
1、从三个维度“口味”、“人均消费”、“性价比”对不同菜系进行比较,并筛选出可开店铺的餐饮类型
要求:
① 计算出三个维度的指标得分
② 评价方法:
   口味 → 得分越高越好
   性价比 → 得分越高越好
   人均消费 → 价格适中即可
③ 制作散点图,x轴为“人均消费”,y轴为“性价比得分”,点的大小为“口味得分”
   绘制柱状图,分别显示“口味得分”、“性价比得分”
   * 建议用bokeh做图
提示:
① 数据清洗,清除空值、为0的数据
② 口味指标计算方法 → 口味评分字段,按照餐饮类别分组算均值,再做标准化处理
③ 人均消费指标计算方法 → 人均消费字段,按照餐饮类别分组算均值,再做标准化处理
④ 性价比指标计算方法 → 性价比 = (口味 + 环境 + 服务)/人均消费,按照餐饮类别分组算均值,再做标准化处理
⑤ 数据计算之前,检查一下数据分布,去除异常值(以外限为标准)
   * 这里排除了高端奢侈餐饮的数据干扰
⑥ 注意,这里先分别计算三个指标,再合并数据(merge)作图,目的是指标之间的噪音数据不相互影响

'''
# 查看数据

import os
os.chdir('C:\\Users\\Hjx\\Desktop\\')
# 创建工作路径

df1 = pd.read_excel('上海餐饮数据.xlsx',sheetname=0,header=0)
df1_length = len(df1)
df1_columns = df1.columns.tolist()
print('数据量为%i条' % len(df1))
print(df1.head())

# 口味、客单价、性价比指标计算

data1 = df1[['类别','口味','环境','服务','人均消费']]
data1.dropna(inplace = True)
data1 = data1[(data1['口味']>0)&(data1['人均消费']>0)]
# 筛选数据,清除空值、为0的数据

data1['性价比'] = (data1['口味'] + data1['环境'] + data1['服务']) / data1['人均消费']
# 计算性价比指数

fig,axes = plt.subplots(1,3,figsize = (10,4))
data1.boxplot(column=['口味'],ax = axes[0])
data1.boxplot(column=['人均消费'],ax = axes[1])
data1.boxplot(column=['性价比'],ax = axes[2])
# 查看异常值

def f1(data,col):
    q1 = data[col].quantile(q = 0.25)
    q3 = data[col].quantile(q = 0.75) 
    iqr = q3-q1
    t1 = q1 - 3 * iqr
    t2 = q3 + 3 * iqr
    return data[(data[col] > t1)&(data[col]<t2)][['类别',col]]
# 创建函数 → 删除异常值

data_kw = f1(data1,'口味')
data_rj = f1(data1,'人均消费')
data_xjb = f1(data1,'性价比')
# 数据异常值处理

def f2(data,col):
    col_name = col + '_norm'
    data_gp = data.groupby('类别').mean()
    data_gp[col_name] = (data_gp[col] - data_gp[col].min())/(data_gp[col].max()-data_gp[col].min())
    data_gp.sort_values(by = col_name, inplace = True, ascending=False)
    return data_gp
# 创建函数 → 标准化指标并排序

data_kw_score = f2(data_kw,'口味')
data_rj_score = f2(data_rj,'人均消费')
data_xjb_score = f2(data_xjb,'性价比')
# 指标标准化得分

data_final_q1 = pd.merge(data_kw_score,data_rj_score,left_index=True,right_index=True)    # 合并口味、人均消费指标得分
data_final_q1 = pd.merge(data_final_q1,data_xjb_score,left_index=True,right_index=True)       # 合并性价比指标得分
# 合并数据

data_final_q1.head()

# 制作散点图、柱状图
# x轴为“人均消费”,y轴为“性价比得分”,点的大小为“口味得分”

from bokeh.models import HoverTool
from bokeh.palettes import brewer
from bokeh.models.annotations import BoxAnnotation
from bokeh.layouts import gridplot
# 导入模块

data_final_q1['size'] = data_final_q1['口味_norm'] * 40  # 添加size字段
data_final_q1.index.name = 'type'
data_final_q1.columns = ['kw','kw_norm','price','price_norm','xjb','xjb_norm','size']
# 将中文改为英文
# 添加颜色参数

source = ColumnDataSource(data_final_q1)
# 创建ColumnDataSource数据

hover = HoverTool(tooltips=[("餐饮类型", "@type"),
                            ("人均消费", "@price"),
                            ("性价比得分", "@xjb_norm"),
                            ("口味得分", "@kw_norm")
                           ])  # 设置标签显示内容
result = figure(plot_width=800, plot_height=250,
                title="餐饮类型得分情况" ,
                x_axis_label = '人均消费', y_axis_label = '性价比得分', 
                tools=[hover,'box_select,reset,xwheel_zoom,pan,crosshair']) 
# 构建绘图空间
result.circle(x = 'price',y = 'xjb_norm',source = source,
         line_color = 'black',line_dash = [6,4],fill_alpha = 0.6,
        size = 'size')
price_mid = BoxAnnotation(left=40,right=80, fill_alpha=0.1, fill_color='navy')   
result.add_layout(price_mid)
# 设置人均消费中间价位区间
result.title.text_font_style = "bold"
result.ygrid.grid_line_dash = [6, 4]
result.xgrid.grid_line_dash = [6, 4]
# 散点图

# 绘制柱状图
data_type = data_final_q1.index.tolist()# 提取横坐标

kw = figure(plot_width=800, plot_height=250, title='口味得分',x_range=data_type,
           tools=[hover,'box_select,reset,xwheel_zoom,pan,crosshair'])
kw.vbar(x='type', top='kw_norm', source=source,width=0.9, alpha = 0.8,color = 'red')   
kw.ygrid.grid_line_dash = [6, 4]
kw.xgrid.grid_line_dash = [6, 4]
# 柱状图1

price = figure(plot_width=800, plot_height=250, title='人均消费得分',x_range=kw.x_range,
              tools=[hover,'box_select,reset,xwheel_zoom,pan,crosshair'])
price.vbar(x='type', top='price_norm', source=source,width=0.9, alpha = 0.8,color = 'green') 
price.ygrid.grid_line_dash = [6, 4]
price.xgrid.grid_line_dash = [6, 4]
# 柱状图2
    
p = gridplot([[result],[kw], [price]])
# 组合图表
show(p)

'''
2、选择一个餐饮类型,在qgis中做将上海划分成格网空间,结合python辅助做空间指标评价,得到餐饮选址位置
* 课程这里以“素菜馆为例”
课程数据
① net_population.shp → 投影坐标系,上海1km²格网内的人口密度数据
② road.shp → 投影坐标西,上海道路数据
要求:
① 通过空间分析,分别计算每个格网内的几个指标:人口密度指标、道路密度指标、餐饮热度指标、同类竞品指标
② 评价方法:
   人口密度指标 → 得分越高越好
   道路密度指标 → 得分越高越好
   餐饮热度指标 → 得分越高越好
   同类竞品指标 → 得分越低越好
   综合指标 = 人口密度指标*0.4 + 餐饮热度指标*0.3 + 道路密度指标*0.2 +同类竞品指标*0.1
③ 最后得到较好选址的网格位置的中心坐标,以及所属区域
   * 可以用bokeh制作散点图
提示:
① 道路密度指标计算方法 → 网格内道路长度
② 餐饮热度指标计算方法 → 网格内餐饮poi计数
③ 同类竞品指标计算方法 → 网格内素菜馆poi计数
④ 餐饮poi数据记得投影
⑤ 可以以“net_population.shp”为网格基础数据,做空间统计
⑥ 在qgis做空间统计之后,网格数据导出点数据,投影成wgs84地理坐标系,导出excel数据,在python做指标标准化等
⑦ 在bokeh中做散点图时,注意添加一个size字段,通过最终评分来赋值
⑧ 在bokeh中做散点图时,可以给TOP10的点用颜色区分

'''

# 加载数据

df2 = pd.read_excel('空间统计.xlsx',sheetname=0,header=0)
data2 = df2.fillna(0)
data2.head()

# 指标统计

data2['rkmd_norm'] = (data2['人口密度']-data2['人口密度'].min())/(data2['人口密度'].max()-data2['人口密度'].min()) # 人口密度指标标准化
data2['cyrd_norm'] = (data2['餐饮计数']-data2['餐饮计数'].min())/(data2['餐饮计数'].max()-data2['餐饮计数'].min()) # 餐饮热度指标标准化
data2['tljp_norm'] = (data2['素菜餐饮计数'].max()-data2['素菜餐饮计数'])/(data2['素菜餐饮计数'].max()-data2['素菜餐饮计数'].min()) # 同类竞品指标标准化
data2['dlmi_norm'] = (data2['道路长度']-data2['道路长度'].min())/(data2['道路长度'].max()-data2['道路长度'].min()) # 道路密度指标标准化
# 指标标准化

data2['final_score'] = data2['rkmd_norm']*0.4 + data2['cyrd_norm']*0.3 + data2['tljp_norm']*0.1 + data2['dlmi_norm']*0.2
data_final_q2 = data2.sort_values(by = 'final_score',ascending=False).reset_index()
data_final_q2[:10]
# 计算综合评分并查看TOP10的网格ID

# 制作空间散点图

data_final_q2['size'] = data_final_q2['final_score'] * 20
data_final_q2['color'] = 'green'
data_final_q2['color'].iloc[:10] = 'red'
# 添加size字段

source = ColumnDataSource(data_final_q2)
# 创建ColumnDataSource数据

hover = HoverTool(tooltips=[("经度", "@lng"),
                            ("纬度", "@lat"),
                            ("最终得分", "@final_score"),
                           ])  # 设置标签显示内容
p = figure(plot_width=800, plot_height=800,
                title="空间散点图" , 
                tools=[hover,'box_select,reset,wheel_zoom,pan,crosshair']) 
# 构建绘图空间

p.square(x = 'lng',y = 'lat',source = source,
         line_color = 'black',fill_alpha = 0.5,
        size = 'size',color = 'color')
p.ygrid.grid_line_dash = [6, 4]
p.xgrid.grid_line_dash = [6, 4]
# 散点图
show(p)

【项目08】 电商打折套路解析

'''
【项目08】  电商打折套路解析

作业要求
1、从现有数据中,分析出“各个品牌都有多少商品参加了双十一活动?”
要求:
① 计算得到:商品总数、品牌总数
② 双十一当天在售的商品占比情况(思考:是不是只有双十一当天在售的商品是“参与双十一活动的商品?”)
③ 未参与双十一当天活动的商品,在双十一之后的去向如何?
④ 真正参与双十一活动的品牌有哪些?其各个品牌参与双十一活动的商品数量分布是怎样的?
   * 用bokeh绘制柱状图表示
提示:
① 数据的“id”字段为商品的实际唯一标识,“title”字段则为商品在网页上显示的名称
   * 仔细看数据可以发现,同一个id的title不一定一样(双十一前后)
② 数据的“店名”字段为品牌的唯一标识
③ 按照商品销售节奏分类,我们可以将商品分为7类
   A. 11.11前后及当天都在售 → 一直在售
   B. 11.11之后停止销售 → 双十一后停止销售
   C. 11.11开始销售并当天不停止 → 双十一当天上架并持续在售
   D. 11.11开始销售且当天停止 → 仅双十一当天有售
   E. 11.5 - 11.10 → 双十一前停止销售
   F. 仅11.11当天停止销售 → 仅双十一当天停止销售
   G. 11.12开始销售 → 双十一后上架
④ 未参与双十一当天活动的商品,可能有四种情况:
   con1 → 暂时下架(F)
   con2 → 重新上架(E中部分数据,数据中同一个id可能有不同title,“换个马甲重新上架”),字符串查找特定字符 dataframe.str.contains('预售')
   con3 → 预售(E中部分数据,预售商品的title中包含“预售”二字)
   con4 → 彻底下架(E中部分数据),可忽略
⑤ 真正参加活动的商品 = 双十一当天在售的商品 + 预售商品 (可以尝试结果去重)
   通过上述几个指标计算,研究出哪些是真正参与双十一活动的品牌,且其商品数量是多少
   
2、哪些商品真的在打折呢?
要求:
① 针对每个商品,评估其打折的情况
② 针对在打折的商品,其折扣率是多少
   * 用bokeh绘制折线图:x轴为折扣率,y轴为商品数量
③ 按照品牌分析,不同品牌的打折力度
   * 用bokeh绘制浮动散点图,y坐标为品牌类型,x坐标为折扣力度
提示:
① 打折情况评估方法:
   真打折:商品的价格在10天内有波动、双11价格为10天内最低价、不存在涨价现象
   不打折:商品价格无变化
② 针对每个商品做price字段的value值统计,查看价格是否有波动,可以先用pd.cut将date分为不同周期:'双十一前','双十一当天','双十一后',得到period字段
   data[['id','price','date']].groupby(['id','price']).min()
   针对统计出来的结果,如果按照id和price分组仍只有一个唯一值,则说明价格未变,没打折;否则为打折
③ 折扣率 = 双十一当天价格 / 双十一之前价格
④ 作图过程中,清除掉折扣率大于95%的数据

3、商家营销套路挖掘?
要求:
① 解析出不同品牌的参与打折商品比例及折扣力度,并做散点图,总结打折套路
   * 用bokeh绘制散点图,x轴为参与打折商品比例,y轴为折扣力度,点的大小代表该品牌参加双11活动的商品总数
提示:
① 折扣力度为该品牌所有打折商品的折扣均值,这里去掉品牌中不打折的数据
② 绘制散点图后,可以将x、y轴绘制均值辅助线,将绘图空间分为四个象限,基于该象限来总结套路

'''
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
% matplotlib inline

import warnings
warnings.filterwarnings('ignore') 
# 不发出警告

from bokeh.io import output_notebook
output_notebook()
# 导入notebook绘图模块

from bokeh.plotting import figure,show
from bokeh.models import ColumnDataSource
# 导入图表绘制、图标展示模块
# 导入ColumnDataSource模块

'''
1、从现有数据中,分析出“各个品牌都有多少商品参加了双十一活动?”
要求:
① 计算得到:商品总数、品牌总数
② 双十一当天在售的商品占比情况(思考:是不是只有双十一当天在售的商品是“参与双十一活动的商品?”)
③ 未参与双十一当天活动的商品,在双十一之后的去向如何?
④ 真正参与双十一活动的品牌有哪些?其各个品牌参与双十一活动的商品数量分布是怎样的?
   * 用bokeh绘制柱状图表示
提示:
① 数据的“id”字段为商品的实际唯一标识,“title”字段则为商品在网页上显示的名称
   * 仔细看数据可以发现,同一个id的title不一定一样(双十一前后)
② 数据的“店名”字段为品牌的唯一标识
③ 按照商品销售节奏分类,我们可以将商品分为7类
   A. 11.11前后及当天都在售 → 一直在售
   B. 11.11之后停止销售 → 双十一后停止销售
   C. 11.11开始销售并当天不停止 → 双十一当天上架并持续在售
   D. 11.11开始销售且当天停止 → 仅双十一当天有售
   E. 11.5 - 11.10 → 双十一前停止销售
   F. 仅11.11当天停止销售 → 仅双十一当天停止销售
   G. 11.12开始销售 → 双十一后上架
④ 未参与双十一当天活动的商品,可能有四种情况:
   con1 → 暂时下架(F)
   con2 → 重新上架(E中部分数据,数据中同一个id可能有不同title,“换个马甲重新上架”),字符串查找特定字符 dataframe.str.contains('预售')
   con3 → 预售(E中部分数据,预售商品的title中包含“预售”二字)
   con4 → 彻底下架(E中部分数据),可忽略
⑤ 真正参加活动的商品 = 双十一当天在售的商品 + 预售商品 (可以尝试结果去重)
   通过上述几个指标计算,研究出哪些是真正参与双十一活动的品牌,且其商品数量是多少

'''

# 查看数据, 计算商品总数、品牌总数

import os
os.chdir('C:\\Users\\Hjx\\Desktop\\')
# 创建工作路径

df = pd.read_excel('双十一淘宝美妆数据.xlsx',sheetname=0,header=0,index_col=0)
df_length = len(df)
df_columns = df.columns.tolist()
df.fillna(0,inplace = True)   # 填充缺失值
df['date'] = df.index.day     # 提取销售日期
print('数据量为%i条' % len(df))
print('数据时间周期为:\n', df.index.unique())
df.head()

# 双十一当天在售的商品占比情况
# 按照商品销售节奏分类,我们可以将商品分为7类
#   A. 11.11前后及当天都在售 → 一直在售
#   B. 11.11之后停止销售 → 双十一后停止销售
#   C. 11.11开始销售并当天不停止 → 双十一当天上架并持续在售
#   D. 11.11开始销售且当天停止 → 仅双十一当天有售
#   E. 11.5 - 11.10 → 双十一前停止销售
#   F. 仅11.11当天停止销售 → 仅双十一当天停止销售
#   G. 11.12开始销售 → 双十一后上架

data1 = df[['id','title','店名','date']]
#print(data1.head())
# 筛选数据

d1 = data1[['id','date']].groupby(by = 'id').agg(['min','max'])['date']  
# 统计不同商品的销售开始日期、截止日期

id_11 = data1[data1['date']==11]['id'].unique()
d2 = pd.DataFrame({'id':id_11,'双十一当天是否售卖':True})
# 筛选双十一当天售卖的商品id

id_date = pd.merge(d1,d2,left_index=True,right_on='id',how = 'left')
id_date['双十一当天是否售卖'][id_date['双十一当天是否售卖']!=True] = False
#print(id_date.head())
# 合并数据

m = len(data1['id'].unique())
m_11 = len(id_11)
m_11_pre = m_11/m
print('商品总数为%i个\n-------' % m)
print('双十一当天参与活动的商品总数为%i个,占比为%.2f%%\n-------' % (m_11,m_11_pre*100))
print('品牌总数为%i个\n' % len(data1['店名'].unique()),data1['店名'].unique())
# 统计

id_date['type'] = '待分类'
id_date['type'][(id_date['min'] <11)&(id_date['max']>11)] = 'A'      #  A类:11.11前后及当天都在售 → 一直在售
id_date['type'][(id_date['min'] <11)&(id_date['max']==11)] = 'B'     #  B类:11.11之后停止销售 → 双十一后停止销售
id_date['type'][(id_date['min'] ==11)&(id_date['max']>11)] = 'C'     #  C类:11.11开始销售并当天不停止 → 双十一当天上架并持续在售
id_date['type'][(id_date['min'] ==11)&(id_date['max']==11)] = 'D'    #  D类:11.11开始销售且当天停止 → 仅双十一当天有售
id_date['type'][id_date['双十一当天是否售卖']== False] = 'F'         #  F类:仅11.11当天停止销售 → 仅双十一当天停止销售
id_date['type'][id_date['max']<11] = 'E'                             #  E类:11.5 - 11.10 → 双十一前停止销售
id_date['type'][id_date['min'] >11] = 'G'                            #  G类:11.11之后开始销售 → 双十一后上架
# 商品销售节奏分类

result1 = id_date['type'].value_counts()
result1 = result1.loc[['A','C','B','D','E','F','G']]  # 调整顺序
# 计算不同类别的商品数量

from bokeh.palettes import brewer
colori = brewer['YlGn'][7]
# 设置调色盘

plt.axis('equal')  # 保证长宽相等
plt.pie(result1,labels = result1.index, autopct='%.2f%%',pctdistance=0.8,labeldistance =1.1,
        startangle=90, radius=1.5,counterclock=False, colors = colori)
# 绘制饼图

result1

# 未参与双十一当天活动的商品,在双十一之后的去向如何?
#   con1 → 暂时下架(F)
#   con2 → 重新上架(E中部分数据,数据中同一个id可能有不同title,“换个马甲重新上架”)
#   con3 → 预售(E中部分数据,预售商品的title中包含“预售”二字),字符串查找特定字符 dataframe.str.contains('预售')
#   con4 → 彻底下架(E中部分数据),可忽略

id_not11 = id_date[id_date['双十一当天是否售卖']==False]  # 筛选出双十一当天没参加活动的产品id
print('双十一当天没参加活动的商品总数为%i个,占比为%.2f%%\n-------' % (len(id_not11),len(id_not11)/m*100))
print('双十一当天没参加活动的商品销售节奏类别为:\n',id_not11['type'].value_counts().index.tolist())
print('------')
# 找到未参与双十一当天活动的商品id

df_not11 = id_not11[['id','type']]
data_not11 = pd.merge(df_not11,df,on = 'id', how = 'left')
# 筛选出未参与双十一当天活动商品id对应的原始数据

id_con1 = id_date['id'][id_date['type'] == 'F'].values
# 筛选出con1的商品id
# con1 → 暂时下架(F)

data_con2 = data_not11[['id','title','date']].groupby(by = ['id','title']).count()   # 按照id和title分组(找到id和title一对多的情况)
title_count = data_con2.reset_index()['id'].value_counts()   # 计算id出现的次数,如果出现次数大于1,则说明该商品是更改了title的
id_con2 = title_count[title_count>1].index
# 筛选出con2的商品id
# con2 → 重新上架(E中部分数据,数据中同一个id可能有不同title,“换个马甲重新上架”)

data_con3 = data_not11[data_not11['title'].str.contains('预售')]   # 筛选出title中含有“预售”二字的数据
id_con3 = data_con3['id'].value_counts().index     
# 筛选出con3的商品id
# con3 → 预售(E中部分数据,预售商品的title中包含“预售”二字)

print("未参与双十一当天活动的商品中:\n暂时下架商品的数量为%i个,重新上架商品的数据量为%i个,预售商品的数据量为%i个" 
      % (len(id_con1), len(id_con2), len(id_con3)))

# 真正参与双十一活动的品牌有哪些?其各个品牌参与双十一活动的商品数量分布是怎样的?
# 真正参加活动的商品 = 双十一当天在售的商品 + 预售商品 (相加后再去重,去掉预售且当天在售的商品)

data_11sale = id_11
#print('双十一当天在售的商品的数量为%i个\n' % len(data_11sale),data_11sale)
#print('--------')
# 得到“双十一当天在售的商品”id及数量

id_11sale_final = np.hstack((data_11sale,id_con3))
result2_id = pd.DataFrame({'id':id_11sale_final})
print('商品总数为%i个' % m)
print('真正参加活动的商品商品总数为%i个,占比为%.2f%%\n-------' % (len(result2_id),len(result2_id)/m*100))
#result2['id'].duplicated() 
# 得到真正参与双十一活动的商品id

x1 =  pd.DataFrame({'id':id_11})
x1_df = pd.merge(x1,df,on = 'id', how = 'left')    # 筛选出真正参与活动中 当天在售的商品id对应源数据 
brand_11sale = x1_df.groupby('店名')['id'].count()
# 得到不同品牌的当天参与活动商品的数量

x2 =  pd.DataFrame({'id':id_con3})
x2_df = pd.merge(x2,df,on = 'id', how = 'left')    # 筛选出真正参与活动中 当天在售的商品id对应源数据 
brand_ys = x2_df.groupby('店名')['id'].count()
# 得到不同品牌的预售商品的数量

result2_data = pd.DataFrame({'当天参与活动商品数量':brand_11sale,
                            '预售商品数量':brand_ys})
result2_data['参与双十一活动商品总数'] = result2_data['当天参与活动商品数量'] + result2_data['预售商品数量']
result2_data.sort_values(by = '参与双十一活动商品总数',inplace = True,ascending = False)
result2_data

# 制作堆叠图查看各个品牌参与双十一活动的商品数量分布

from bokeh.models import HoverTool
from bokeh.core.properties import value
# 导入相关模块

lst_brand = result2_data.index.tolist()
lst_type = result2_data.columns.tolist()[:2]
colors = ["#718dbf" ,"#e84d60"]
# 设置好参数

result2_data.index.name = 'brand'
result2_data.columns = ['sale_on_11','presell','sum']
# 修改数据index和columns名字为英文

source = ColumnDataSource(data=result2_data)
# 创建数据

hover = HoverTool(tooltips=[("品牌", "@brand"),
                            ("双十一当天参与活动的商品数量", "@sale_on_11"),
                            ("预售商品数量", "@presell"),
                            ("参与双十一活动商品总数", "@sum")
                           ])  # 设置标签显示内容

p = figure(x_range=lst_brand, plot_width=900, plot_height=350, title="各个品牌参与双十一活动的商品数量分布",
          tools=[hover,'reset,xwheel_zoom,pan,crosshair'])
# 构建绘图空间

p.vbar_stack(lst_type,          # 设置堆叠值,这里source中包含了不同年份的值,years变量用于识别不同堆叠层
             x='brand',     # 设置x坐标
             source=source,
             width=0.9, color=colors, alpha = 0.8,legend=[value(x) for x in lst_type],
             muted_color='black', muted_alpha=0.2
             )
# 绘制堆叠图

p.xgrid.grid_line_color = None
p.axis.minor_tick_line_color = None
p.outline_line_color = None
p.legend.location = "top_right"
p.legend.orientation = "horizontal"
p.legend.click_policy="mute"
# 设置其他参数

show(p)

'''
2、哪些商品真的在打折呢?
要求:
① 针对每个商品,评估其打折的情况
② 针对在打折的商品,其折扣率是多少
   * 用bokeh绘制折线图:x轴为折扣率,y轴为商品数量
③ 按照品牌分析,不同品牌的打折力度
   * 用bokeh绘制浮动散点图,y坐标为品牌类型,x坐标为折扣力度
提示:
① 打折情况评估方法:
   真打折:商品的价格在10天内有波动、双11价格为10天内最低价、不存在涨价现象
   不打折:商品价格无变化
② 针对每个商品做price字段的value值统计,查看价格是否有波动,可以先用pd.cut将date分为不同周期:'双十一前','双十一当天','双十一后',得到period字段
   data[['id','price','date']].groupby(['id','price']).min()
   针对统计出来的结果,如果按照id和price分组仍只有一个唯一值,则说明价格未变,没打折;否则为打折
③ 折扣率 = 双十一当天价格 / 双十一之前价格
④ 作图过程中,清除掉折扣率大于95%的数据

'''

# 针对每个商品,评估其打折的情况
#   真打折:商品的价格在10天内有波动、双11价格为10天内最低价、不存在涨价现象
#   不打折:商品价格无变化

data2 = df[['id','title','店名','date','price']]
data2['period'] = pd.cut(data2['date'],[4,10,11,14],labels = ['双十一前','双十一当天','双十一后'])
#print(data2.head())
# 筛选数据

price = data2[['id','price','period']].groupby(['id','price']).min()
price.reset_index(inplace = True)
# 针对每个商品做price字段的value值统计,查看价格是否有波动

id_count = price['id'].value_counts()
id_type1 = id_count[id_count == 1].index
id_type2 = id_count[id_count != 1].index
# 筛选出“不打折”和“真打折”的商品id

n1 = len(id_type1)
n2 = len(id_type2)
print('真打折的商品数量约占比%.2f%%,不打折的商品数量约占比%.2f%%' % (n2/len(id_count)*100, n1/len(id_count)*100))

# 针对在打折的商品,其折扣率是多少

result3_data1 = data2[['id','price','period','店名']].groupby(['id','period']).min()
result3_data1.reset_index(inplace = True)
# 筛选数据

result3_before11 = result3_data1[result3_data1['period'] == '双十一前']
result3_at11 = result3_data1[result3_data1['period'] == '双十一当天']
result3_data2 = pd.merge(result3_at11,result3_before11,on = 'id')
# 筛选出商品双十一当天及双十一之前的价格

result3_data2['zkl'] = result3_data2['price_x'] / result3_data2['price_y']
# 计算折扣率


result3_data1

# 用bokeh绘制折线图:x轴为折扣率,y轴为商品数量占比

bokeh_data = result3_data2[['id','zkl']].dropna()
bokeh_data['zkl_range'] = pd.cut(bokeh_data['zkl'],bins = np.linspace(0,1,21))
bokeh_data2 = bokeh_data.groupby('zkl_range').count().iloc[:-1] # 这里去掉折扣率在0.95-1之间的数据,该区间内数据zkl大部分为1,不打折
bokeh_data2['zkl_pre'] = bokeh_data2['zkl']/bokeh_data2['zkl'].sum()
# 将数据按照折扣率拆分为不同区间,并统计不同1扣率的商品数量

source = ColumnDataSource(data=bokeh_data2)
# 创建数据

lst_brand = bokeh_data2.index.tolist()

hover = HoverTool(tooltips=[("折扣率", "@zkl")])  # 设置标签显示内容

p = figure(x_range=lst_brand, plot_width=900, plot_height=350, title="商品折扣率统计",
          tools=[hover,'reset,xwheel_zoom,pan,crosshair'])
# 构建绘图空间

p.line(x='zkl_range',y='zkl_pre',source = source,     # 设置x,y值, source → 数据源
       line_width=2, line_alpha = 0.8, line_color = 'black',line_dash = [10,4])   # 线型基本设置
# 绘制折线图
p.circle(x='zkl_range',y='zkl_pre',source = source, size = 8,color = 'red',alpha = 0.8)

p.xgrid.grid_line_color = None
p.axis.minor_tick_line_color = None
p.outline_line_color = None
# 设置其他参数

show(p)

a3 = bokeh_data2.reset_index()
a3['zkl_range'].astype(np.str)

# 按照品牌分析,不同品牌的打折力度
# 用bokeh绘制浮动散点图,y坐标为品牌类型,x坐标为折扣力度

from bokeh.transform import jitter

brands = result3_data2['店名_y'].dropna().unique().tolist()
# 得到y坐标

bokeh_data = result3_data2[['id','zkl','店名_y']].dropna()
bokeh_data = bokeh_data[bokeh_data['zkl'] < 0.95]
source = ColumnDataSource(data = bokeh_data)
# 创建数据

hover = HoverTool(tooltips=[("折扣率", "@zkl")])  # 设置标签显示内容

p = figure(plot_width=800, plot_height=600,y_range=brands,title="不同品牌折扣率情况",
          tools=[hover,'reset,ywheel_zoom,pan,crosshair'])

p.circle(x='zkl', 
         y=jitter('店名_y', width=0.6, range=p.y_range),
         source=source, alpha=0.3)
# jitter参数 → 'day':第一参数,这里指y的值,width:间隔宽度比例,range:分类范围对象,这里和y轴的分类一致

p.ygrid.grid_line_color = None
# 设置其他参数

show(p)

'''
3、商家营销套路挖掘?
要求:
① 解析出不同品牌的参与打折商品比例及折扣力度,并做散点图,总结打折套路
   * 用bokeh绘制散点图,x轴为参与打折商品比例,y轴为折扣力度,点的大小代表该品牌参加双11活动的商品总数
提示:
① 折扣力度为该品牌所有打折商品的折扣均值,这里去掉品牌中不打折的数据
② 绘制散点图后,可以将x、y轴绘制均值辅助线,将绘图空间分为四个象限,基于该象限来总结套路

'''

# 解析出不同品牌的参与打折商品比例及折扣力度,并做散点图,总结打折套路

data_zk = result3_data2[result3_data2['zkl']<0.95]  # 删除未打折数据
result4_zkld = data_zk.groupby('店名_y')['zkl'].mean()
# 筛选出不同品牌的折扣率

n_dz = data_zk['店名_y'].value_counts()
n_zs = result3_data2['店名_y'].value_counts()
result4_dzspbl = pd.DataFrame({'打折商品数':n_dz,'商品总数':n_zs})
result4_dzspbl['参与打折商品比例'] = result4_dzspbl['打折商品数'] / result4_dzspbl['商品总数']
result4_dzspbl.dropna(inplace = True)
#print(result4_dzspbl.head())
# 计算出不同品牌参与打折商品比例

result4_sum = result2_data.copy()
# 筛选出品牌参加双11活动的商品总数

result4_data = pd.merge(pd.DataFrame(result4_zkld),result4_dzspbl,left_index = True, right_index = True, how = 'inner')
result4_data = pd.merge(result4_data,result4_sum,left_index = True, right_index = True, how = 'inner')
# 合并数据

result3_data2

# 用bokeh绘制散点图,x轴为参与打折商品比例,y轴为折扣力度,点的大小代表该品牌参加双11活动的商品总数

from bokeh.models.annotations import Span            # 导入Span模块
from bokeh.models.annotations import Label           # 导入Label模块
from bokeh.models.annotations import BoxAnnotation   # 导入BoxAnnotation模块


bokeh_data = result4_data[['zkl','sum','参与打折商品比例']]
bokeh_data.columns = ['zkl','amount','pre']
bokeh_data['size'] = bokeh_data['amount'] * 0.03
source = ColumnDataSource(bokeh_data)
# 创建ColumnDataSource数据

x_mean = bokeh_data['pre'].mean()
y_mean = bokeh_data['zkl'].mean()

hover = HoverTool(tooltips=[("品牌", "@index"),
                            ("折扣率", "@zkl"),
                            ("商品总数", "@amount"),
                            ("参与打折商品比例", "@pre"),
                           ])  # 设置标签显示内容
p = figure(plot_width=600, plot_height=600,
                title="各个品牌打折套路解析" , 
                tools=[hover,'box_select,reset,wheel_zoom,pan,crosshair']) 
# 构建绘图空间

p.circle_x(x = 'pre',y = 'zkl',source = source,size = 'size',
           fill_color = 'red',line_color = 'black',fill_alpha = 0.6,line_dash = [8,3])
p.ygrid.grid_line_dash = [6, 4]
p.xgrid.grid_line_dash = [6, 4]
# 散点图

x = Span(location=x_mean, dimension='height', line_color='green',line_alpha = 0.7, line_width=1.5, line_dash = [6,4])
y = Span(location=y_mean, dimension='width', line_color='green',line_alpha = 0.7, line_width=1.5, line_dash = [6,4])
p.add_layout(x)
p.add_layout(y)
# 绘制辅助线

bg1 = BoxAnnotation(bottom=y_mean, right=x_mean,fill_alpha=0.1, fill_color='olive')
label1 = Label(x=0.1, y=0.55,text="少量大打折",text_font_size="10pt" )
p.add_layout(bg1)
p.add_layout(label1)
# 绘制第一象限

bg2 = BoxAnnotation(bottom=y_mean, left=x_mean,fill_alpha=0.1, fill_color='firebrick')
label2 = Label(x=0.7, y=0.55,text="大量大打折",text_font_size="10pt" )
p.add_layout(bg2)
p.add_layout(label2)
# 绘制第二象限

bg3 = BoxAnnotation(top=y_mean, right=x_mean,fill_alpha=0.1, fill_color='firebrick')
label3 = Label(x=0.1, y=0.80,text="少量少打折",text_font_size="10pt" )
p.add_layout(bg3)
p.add_layout(label3)
# 绘制第三象限

bg4 = BoxAnnotation(top=y_mean, left=x_mean,fill_alpha=0.1, fill_color='olive')
label4 = Label(x=0.7, y=0.80,text="少量大打折",text_font_size="10pt" )
p.add_layout(bg4)
p.add_layout(label4)
# 绘制第四象限

show(p)

'''
结论:
少量少打折:包括雅诗兰黛、娇兰、兰蔻、薇姿、玉兰油等共5个品牌。
少量大打折:包括悦诗风吟、兰芝、欧珀莱等3个品牌。该类品牌的打折商品较少,但折扣力度较大。
大量小打折:包括妮维雅、美宝莲、蜜丝佛陀等3个品牌。该类型有半数以上的商品都参与了打折活动,但折扣力度并不大。
大量大打折:包括相宜本草、佰草集、自然堂等三大国产品牌。这些品牌不仅有90%以上的商品参与了折扣活动,而且折扣力度很大。
'''

猜你喜欢

转载自blog.csdn.net/qq_42442369/article/details/86737815