一、字段介绍,有些字段没用,具体见项目代码
二、导入相应的科学计算库
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
import seaborn as sns
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
%matplotlib inline
plt.style.use("ggplot")
cook_df1 = pd.read_excel("meal_order_detail.xlsx",sheet_name='meal_order_detail1')
cook_df2 = pd.read_excel("meal_order_detail.xlsx",sheet_name='meal_order_detail2')
cook_df3 = pd.read_excel("meal_order_detail.xlsx",sheet_name="meal_order_detail3")
# 将三个工作簿合并为cook_df
cook_df = pd.concat([cook_df1,cook_df2,cook_df3],axis=0)
cook_df.head(5)
cook_df.info()
不难发现,实际上有分析价值的数据字段只有一部分,另一部分均为空,因此要删掉全都为空的列。判断是否为空(或者是否不为空),使用isnull()函数和notnull()函数,要结合any()和all()来使用
cond1 = cook_df.notnull().all()
# 利用dataframe的布尔索引
cook_df = cook_df.loc[:,cond1] #不能使用iloc
cook_df.head(5)
cook_df.columns.tolist()
三、分析数据
A 基于销售额的分析
A-1 计算每一笔订单的总消费价格 - 将订单编号order_id进行分组
cook_df['price_sum'] = cook_df['counts'] * cook_df["amounts"]
#每一笔订单的总消费价格
ord_pri_t10 = cook_df.groupby(by='order_id')['price_sum'].sum().sort_values(ascending=False)[:10]
# ord_pri_t10 = cook_df.groupby(by='order_id').sum()['price_sum'].sort_values(ascending=False)[:10]
plt.figure(figsize=(6,4),dpi=100)
ord_pri_t10.plot(kind='bar')
plt.ylabel("消费价格")
plt.xlabel("订单编号")
plt.title("消费金额top10的订单")
A-2 计算2016年8月总销售额、来客数和客单价
#总销售额
cook_df['price_sum'] = cook_df['counts'] * cook_df["amounts"]
sale_ = sum(cook_df['price_sum'])
sale_
463704
# 来客数相当于订单数量,只需计算订单的数量即可 -- 取出订单编号的字段,进行去重即可
custom = len(set(cook_df['order_id'].values.tolist()))
custom
942
## 客单价
sale_ / custom
492.2547770700637
A-3 分析一周中的每一天的销售额
#先获取每一个时间的星期
cook_df['week_day'] = cook_df['place_order_time'].dt.day_name()
cook_df['week_day']
#对week_day进行分组,在对price_sum求和,得出一个星期中每一天的销售额
week_day_sum = cook_df.groupby(by='week_day')['price_sum'].sum()
week_day_sum
plt.figure(figsize=(6,4),dpi=100)
week_day_sum.plot(kind='bar')
plt.xticks(rotation=45)
plt.title("一周中每一天的销量")
B 基于菜品的分析
B-1 计算最受欢迎的前10道菜品名称和价格
cook_df.groupby(by='dishes_name').sum()['counts'].sort_values(ascending=False)
df = cook_df.groupby(by='dishes_name').sum()
fig = plt.figure(figsize=(6,4),dpi=100)
cook_top10 = df.sort_values(by='counts',ascending=False)[0:10]['counts']
cook_top10.plot(kind='bar')
cook_top10.plot(kind='line',color='red')
#旋转x轴
plt.xticks(rotation=45)
#添加文本
for name,count in enumerate(cook_top10):
plt.text(x=name,y=count+5,s=count,ha='center',color='green')
#添加标题
plt.title('2016年8月最受欢迎的10道菜品')
通过计算发现,最多的是小碗米饭,其次是大碗米饭,而最多的菜而是凉拌菠菜
B-2 每一道菜的单价、销售量和销售额
#每一道菜品的单价
dish_price = cook_df[['dishes_name',"amounts"]].drop_duplicates().set_index('dishes_name')
dish_price
#每一道菜品的销量
dish_counts = cook_df.groupby(by='dishes_name')['counts'].sum().to_frame()
dish_counts
### 每一道菜的销售额
dish_amounts = cook_df.groupby(by='dishes_name')['price_sum'].sum().to_frame()
dish_amounts
将前面三个进行拼接 – concat()函数
dish_sale = pd.concat([dish_price,dish_counts,dish_amounts],axis=1)
dish_sale.sort_values(by='counts',ascending=False).head(10)
B-3 分析菜品价格和销量之间的关系 – pd.corr()函数
plt.figure(dpi=100)
sns.heatmap(data=dish_sale.corr(),cmap="Accent",annot=True)
B-4 分析每一个价格区间的销售量
cook_df['price_range'] = pd.cut(cook_df['amounts'],bins=3)
cook_df
#### 求每一个分区的总销售量
price_range = cook_df.groupby(by='price_range')['counts'].sum()
price_range
plt.figure(figsize=(3,3),dpi=100)
price_range.plot.pie(autopct='%1.2f%%',shadow=True,explode=[0.1,0.05,0.05])
plt.legend(['低价格','中价格','高价格'])
plt.title("各个菜品价格区间的销售量")
C 基于消费时间的分析
C-1 分析一天当中哪些时段有哪些订单,哪些订单量最多,以小时为单位
分析:从订单的时时间来看,所有数据都分布在10-24点之间,可以将其分成5个时段来分别统计
首先明确的是
- 统计的对象是订单的小时,计算每一个时间段的订单个数
- 首先要对小时分组,每一个小时内有哪些订单(订单编号会重复),在对订单编号进行分组,最后得出每一个时间有哪些订单编号(不重复)
# 先提取出每一个订单时间的小时
cook_df["hour"] = cook_df['place_order_time'].map(lambda d:d.hour)
#对小时和订单编号分组
hr_ord = cook_df.groupby(by=['hour','order_id']).sum()['counts']
hr_ord
#### 求出每一个时间的订单数量
hours= [i[0] for i in hr_ord.index.tolist()]
hr_ord_nums = pd.value_counts(hours).sort_index()
plt.figure(figsize=(6,4),dpi=100)
hr_ord_nums.plot(kind='bar')
pd.value_counts(object)和df.value_counts()都是可以的。不难得出,每一天的18点到21点订单量最多,其次就是11点道13点的,因为正值饭点
C-2 分析上中下旬的销售额
(cook_df1['counts'] * cook_df1['amounts']).sum()
128832
(cook_df2['counts'] * cook_df2['amounts']).sum()
167974
(cook_df3['counts'] * cook_df3['amounts']).sum()
166898
C-3 分别计算每一天中饭(最早时间-16点)和晚饭(16-最晚时间)两个时段的总销售额
_less_16 = cook_df[cook_df['hour']<=16]
_less_16.head()
因为要统计每一天的销售额,所以要对天进行分组,再对销售额进行求和
#### 先要提取出消费日期的date部分,直接改变精度即可
_less_16['date'] = _less_16['place_order_time'].values.astype("datetime64[D]")
less_16_sale = _less_16.groupby(by='date')['price_sum'].sum()
less_16_sale
_more_16 = cook_df[cook_df['hour']>16]
_more_16['date'] = _more_16['place_order_time'].values.astype("datetime64[D]")
more_16_sale = _more_16.groupby(by='date')['price_sum'].sum()
more_16_sale
#### 将两个合并成一个dataframe
time_range_sale = pd.concat([less_16_sale,more_16_sale],axis=1)
time_range_sale.columns = ['16点之前的','16点之后的']
time_range_sale
time_range_sale.plot(figsize=(10,4))
分析结果:
- 可以看出来,每天晚饭的阶段的销售额要明显高于中饭阶段
- 而且可以看出两组图像都有峰值,而且峰值都是在每周的周六周天的,这也足以说明周末的两天里,销售额显然较平时要多得多