github地址:github.com/jiahaoabc/C…
目的和背景
目的
对数据进行处理,从‘口味’、‘环境’、‘服务’、‘消费’、‘性价比’这些条件入手,对不同种类餐饮店铺进行各类对比分析,分析上海人的餐饮喜好。
数据背景
基于上海市的一份餐饮数据
总数据量为96389条
数据存在的问题
粗略看了下数据,比较明显的问题有数据缺失以及数据异常(比如口味评分、环境评分等等均为0)
数据初步清洗
读取数据
df1=pd.read_excel('上海餐饮数据.xlsx')
去除空值
df1.dropna(inplace=True)
print('去除缺失值后剩余数据量:',len(df1))
去除空值后剩下96255条数据
去除异常值
在粗略查看数据的时候,发现'口味','环境','服务'这三者的数据要么同时为异常值0,要么同时全部正常。为了证明这一猜想,查看'口味','环境','服务'这三者的正常值的数据量分别为多少
len(df1[df1['口味']>0]),len(df1[df1['环境']>0]),len(df1[df1['服务']>0])
(78583, 78583, 78583)
数量一样,可以判定上面的猜测是正确的,因此去掉'口味','环境','服务'这三者其中一种的异常数据,另外两者异常数据也会跟着去除。这里我们对异常值采取删除处理,
去掉'口味','环境','服务','人均消费'异常的数据
data=df1[(df1['服务']>0)&(df1['人均消费']>0)]
print(len(data))
清洗后剩下54886条正常数据
数据转换
从'口味'、环境'、'服务'以及'人均消费'这其中的一个单一变量不方便判断一家店铺整体的整体情况,中国人比较热衷于性价比,用性价比来评判一家店铺的整体情况不失为一个好办法。对于一家餐饮店铺,相信大部分人的关注程度应当是口味>环境>服务(至少我个人是这样),所以分配的权重比为:
口味:环境:服务=5:3:2
这里计算性价比为:
性价比=(口味评分*0.5+环境评分*0.3+服务评分*0.2)/人均消费
data['性价比']=(data['口味']*0.5+data['环境']*0.3+data['服务']*0.2)/data['人均消费']
数据进一步处理
初步箱型图
def boxplot(data,*args):
fig,axes=plt.subplots(1,len(args),figsize=(15,6))
for i in range(0,len(args)):
data.boxplot(column=[args[i]],ax=axes[i])
boxplot(data,'口味','人均消费','性价比')#查看‘口味(环境、服务)’、‘人均消费’、‘性价比’箱型图
此时的数据和图简直不忍直视。。。,存在不少极端的数据,有些‘人均消费’数值甚至在五六千以上(虽然可能存在这么贵,但这样的数据会干扰数据整体拟合度,需要去掉)
再次去除异常值
def remove_outliers(data,col):
Q1=data[col].quantile(q=0.25)#下四分位数
Q3=data[col].quantile(q=0.75)#上四分位
IQR=Q3-Q1#四分位数全距
if col=='口味':
down_limit=Q1-1.5*IQR#下温和异常值边界
up_limit=Q3+1.5*IQR#上温和异常值边界
else:
down_limit=Q1-3*IQR#下极度异常值边界
up_limit=Q3+3*IQR#上极度异常值边界
print(col,'下上四分位,下上异常边界值分别为:',Q1,Q3,down_limit,up_limit)
clean_data=data[(data[col] > down_limit)&(data[col] < up_limit)]
return clean_data
data_clean=remove_outliers(data,'口味')
data_clean=remove_outliers(data_clean,'人均消费')
data_clean=remove_outliers(data_clean,'性价比')
这里说明一下为何‘人均消费’和'性价比’没有去除温和异常值,首先'口味'的数值集中在0-10之间,所以它的数据是比较集中的,可直接去除所有异常值。
'人均消费'和'性价比’的各个数值'如下:
人均消费 下上四分位,下上极度异常边界值分别为: 24.0 87.0 -165.0 276.0
性价比 下上四分位,下上异常边界值分别为: 0.0925974025974026 0.3090909090909091 -0.5568831168831169 0.9585714285714285
人均消费和性价比有些数据比较高,但是不一定是错误数据,有些店铺的消费确实比较多,有些店铺也可能真的很划算,所以此时应该扩大以下正常值范围,‘包容’一些温和异常值(价格在276以下的,性价比在0.96以内的),只去掉一些极度异常的值
清洗后箱型图
boxplot(data_clean,'口味','人均消费','性价比')
虽然看着还存在不少异常值,这些异常值是上面说到的留下的温和异常值,这些都是可以接受的。
此时还剩下53059条正常数据
数据分组
对各类型菜品店铺进行分组
def data_groupby(data,col):
data_group=data[['类别','口味','人均消费','性价比']]
data_group=data_group.groupby(col).mean() #求平均值
return data_group
data_group=data_groupby(data_clean,'类别')
前五行数据如下:
数据归一化
对数据进行归一化处理,易于明白数据差异和大小。
def data_norm(data,*args):
for i in range(0,len(args)):
col_name=args[i]+'_norm'
data[col_name]=(data[args[i]]-data[args[i]].min())/(data[args[i]].max()-data[args[i]].min())
return data
data_deal=data_norm(data_group,'口味','人均消费','性价比')
columns=['口味','口味_norm','人均消费','人均消费_norm','性价比','性价比_norm']#改变列名顺序
data_deal=data_deal[columns]
#大部分中国人喜欢划算,我们以性价比排序
data_deal.sort_values(by='性价比_norm',inplace = True, ascending=False)
data_deal.head()
data_deal.tail()
性价比最高五行数据如下:
性价比倒数五行数据如下:
数据可视化
这里选择bokeh作为可视化工具
模块导入以及画布基本设置
导入相关模块
from bokeh.plotting import figure,show,output_file
from bokeh.models import ColumnDataSource
from bokeh.models.annotations import BoxAnnotation
from bokeh.models import HoverTool
from bokeh.layouts import gridplot
import copy
标签改为英文,添加size字段(下面散点图点大小)、拷贝两个对象生图
data_deal.index.name='type'
data_deal.columns=['kw','kw_norm','price','price_norm','xjb','xjb_norm']
data_deal['size'] = data_deal['kw_norm'] * 40 # 添加size字段作为点的大小
data_deal_2=copy.deepcopy(data_deal)
data_deal_3=copy.deepcopy(data_deal)
设置工具、标签
hover = HoverTool(tooltips=[("餐饮类型", "@type"),
("人均消费", "@price"),
("性价比得分", "@xjb_norm"),
("口味得分", "@kw_norm")
])
餐饮类别—人均消费—口味—性价比关系散点图
散点图生图代码
source=ColumnDataSource(data_deal)
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='red',line_dash=[6,4],fill_alpha = 0.6,
size = 'size')
不同餐饮‘人均消费’、‘口味’、‘性价比’之间的关系。每个点分别代表一类餐饮,圆圈大小表示口味评分,圆圈越大,味道越好
口味—类别关系柱状图
图形生成代码
data_deal_2.sort_values(by='kw_norm',inplace=True,ascending=False)#口味评分从大到小牌
data_type_2=data_deal_2.index.tolist()
source2=ColumnDataSource(data_deal_2)
kw=figure(plot_width=800,plot_height=250,title='口味得分',x_range=data_type_2,
tools=[hover,'box_select,reset,xwheel_zoom,pan,crosshair'])
kw.vbar(x='type',top='kw_norm',source=source2,width=0.9,alpha=0.8,color='black')
人均消费—类别关系柱状图
图形生成代码
data_deal_3.sort_values(by='price_norm',inplace=True,ascending=False)
data_type_3=data_deal_3.index.tolist()
source3=ColumnDataSource(data_deal_3)
price = figure(plot_width=800, plot_height=250, title='人均消费得分',x_range=data_type_3,
tools=[hover,'box_select,reset,xwheel_zoom,pan,crosshair'])
price.vbar(x='type', top='price_norm', source=source3,width=0.9, alpha = 0.8,color = 'red')
可视化结论
根据数据,总的来说
在所有菜系中,南菜(南方小菜)、素菜、火锅最迎合上海人的口味,味道浓烈的北菜(东北菜)和辛辣的湘菜(湖南菜)使得他们无法消受,因此可以发现上海人饮食较为清淡。
口味评分最低的是常菜,家常菜里缺乏了亲人的味道以及一家人的其乐融融,或许再厉害的大厨做出的家常菜都难以获得消费者的青睐吧。
甜点、快餐、面馆占据性价比前三甲,虽然口味得分较低,但物价高涨、生活节奏紧张的上海,使得这三类低价,便捷的食物在所有餐饮食物里脱颖而出。
令人惊讶的是,疆菜(新疆菜/清真菜)这一菜系无论是从口味、人均消费还是性价比来看都获得了上海人民的认可。
助餐、蟹宴、午茶性价比最低,吃着蟹宴,喝着下午茶,消费不考虑性价比和价格,大概这就是有钱上海人的快乐吧。