概述
研究目的
进行预测餐饮中每天菜品的销量,提前制定好采购计划,减小库存,提高预算。
分析思路
1.销量异常日展示
2.最冷款慢销菜品展示(可降价) 目的:提升销量
3.最优畅销菜涨价名称展示(可涨价) 目的:提升利润
4.菜品套餐营销组合价格策略(畅销菜涨价+滞销菜降价)*0.95% 目的:促销量
5.菜品偏好相关展示(目的:推送。由于买A菜的人,买了B菜,还买了C菜。推荐下一个有买A菜的人,也尝试C菜)
以一周的销量为主,对每周的销售总量进行预测,对菜在这一周的总销量进行拆解,均分到每一天,了解每一天菜的销量。
实施过程
部分数据如下:
分析程序算法如下:
import matplotlib
import pandas as pd
from sklearn import preprocessing
import numpy as np
from sklearn.preprocessing import Imputer
import matplotlib.pyplot as plt
import warnings
from datetime import datetime
import xlrd
import time
warnings.filterwarnings(“ignore”)
matplotlib.rcParams[‘font.sans-serif’] = [‘FangSong’] # 指定默认字体
matplotlib.rcParams[‘axes.unicode_minus’] = False # 解决保存图像是负号’-'显示为方块的问题
data=pd.read_csv(’/Users/wang/PycharmProjects/untitled2/15650711345953342991000.csv’)#读取数据
df=data[[‘fshopday’,‘ffoodname’,‘fsubsaleqty’]]#去除无关信息
foodname_set=df[‘ffoodname’].unique().tolist()#探寻食品种类
len(foodname_set)#食物种类数量
group_obj = df.groupby(‘ffoodname’)#通过ffoodname键分组
dis_data=group_obj.size()#查看每种食品的非空项数量
dis_data.describe()#非空数量统计
dis_data.name=‘ffoodname_box’
dis_data=dis_data/138 #计算1-缺失率,即非空率
dis_data.plot.box()#非空率箱型图
#通过访问分组信息,按照时间为索引,连接数据
new_cols = pd.DataFrame()
count = 0
for name, group in group_obj:
group = group[[‘fshopday’, ‘fsubsaleqty’]]
group.rename(inplace=True, columns={“fsubsaleqty”: name})#重命名
count += 1
if count == 1:
new_cols = group
else:
new_cols = pd.merge(new_cols, group, how='outer', on='fshopday')#连接新的一天数据与之前的
print('正在拼接第{}个,总共178个'.format(count))
new_cols[‘fshopday’] = pd.to_datetime(new_cols[‘fshopday’])#时间转为datetime
new_cols.index = new_cols[‘fshopday’]#时间变成索引
del new_cols[‘fshopday’]#删除这列
new_cols=new_cols.sort_index()#根据时间排序
copy_cols=new_cols.copy()
#观察缺失值分布图
def get_miss_info(data):
m,n=data.shape
miss_data=np.zeros((m,n))
row_list=[]
col_list=[]
indexs=list(data.index)
columns=list(data.columns)
null_data=data.isnull()
for i in range(m):
for j in range(n):
if(null_data.iloc[i,j]==True):
miss_data[i,j]=1
row_list.append(i)
col_list.append(j)
#plt.figure(figsize=(20, 18))
#plt.scatter(col_list,row_list)
#plt.show()
#get_miss_info(new_cols)
#plt.savefig(‘all_miss.png’)
isnull_rate=new_cols.apply(lambda col:sum(col.isnull())/col.size)#得到缺失率数据
cut_rate=0.5#只保留缺失值小于cut_rate的列名
delete_col_names=list(isnull_rate[isnull_rate>cut_rate].index)#得到缺失率高的列名
new_cols.drop(columns=delete_col_names,inplace=True)#去掉缺失高的列
get_miss_info(new_cols)
#去掉近期的缺失值
isnull_rate=new_cols.iloc[-20:].apply(lambda col:sum(col.isnull())/col.size)#得到缺失率数据
cut_rate=0.3#只保留缺失值小于cut_rate的列名
delete_col_names=list(isnull_rate[isnull_rate>cut_rate].index)#得到缺失率高的列名
new_cols.drop(columns=delete_col_names,inplace=True)#去掉缺失高的列
get_miss_info(new_cols)
#填充缺失值,因为数据是时间序列,采用插值填充,使用前面数据填充后面的,剩下的最前面的缺失值,使用中值填充
#new_cols.fillna(method=‘time’,inplace=True)#先向前填充
col_names=new_cols.columns
for col_name in col_names:
new_cols[col_name]= new_cols[col_name].interpolate(method=‘linear’)
new_cols.fillna(new_cols.median(),inplace=True)#再中位数填充
#最后七天的真实值
true_cols=new_cols.iloc[-7:,:].copy()
#处理异常值
#异常值判断标准x > Q3 + k(Q3 - Q1) OR
#x < Q1 - k(Q3 - Q1)
#k是自己定义的参数
k=5
m=5#使用前m个数进行移动平均
def get_outlier():
describe = new_cols.describe()
count=0
for row in range(new_cols.shape[0]):
for col in range(new_cols.shape[1]):
if (new_cols.iloc[row, col] > (
describe.iloc[6, col] + k * (describe.iloc[6, col] - describe.iloc[4, col]))):#若数太小
print(‘异常值为{}日{}菜种,异常数量{}’.format(new_cols.index[row],new_cols.columns[col],new_cols.iloc[row,col]))
if(row>=m):#若数据不在开头m行和
temp=0
for j in range(1,m+1):#滑动到前几个数据,取平均
temp=temp+new_cols.iloc[row-m,col]
new_cols.iloc[row,col]=temp/m
else:
new_cols.iloc[row,col]=new_cols.iloc[row-1,col]
count=count+1
if( new_cols.iloc[row, col] < (
describe.iloc[4, col] - k * (describe.iloc[6, col] - describe.iloc[4, col]))):
print(‘异常值为{}日{}菜种,异常数量{}’.format(new_cols.index[row],new_cols.columns[col],new_cols.iloc[row,col]))
if( row>=m):#若数据不在开头m行和
temp=0
for j in range(1,m+1):#滑动到前几个数据,取平均
temp=temp+new_cols.iloc[row-m,col]
new_cols.iloc[row,col]=temp/m
else:
new_cols.iloc[row,col]=new_cols.iloc[row-1,col]
count=count+1
return count
print(‘异常值数量:{}’.format(get_outlier()))
#作图分析,探究时间与分布的关系
names=[‘一鸡两吃’,‘下饭姜爆鸡’,‘下饭扑四脆’,‘鲜啤500ml’]
new_cols[names].plot()
#plt.savefig(‘dis.png’)
def is_weenkend(data):
temp=data.weekday()#获得一周第几天,0代表周一,6代表星期天
if(temp>=5):
weekend=1
else:
weekend=0
return weekend
rest_holiday=[
‘2018-12-31’,
‘2019-01-01’,‘2019-02-04’,‘2019-02-05’,‘2019-02-06’,‘2019-02-07’,‘2019-02-08’,
‘2019-04-05’,‘2019-04-29’,‘2019-04-30’,‘2019-05-01’,‘2019-06-07’,‘2019-09-13’,
‘2019-10-01’,‘2019-10-02’,‘2019-10-03’,‘2019-10-04’,‘2019-10-07’,‘2019-12-30’,
‘2019-12-31’,
‘2020-01-01’,‘2020-01-24’,‘2020-01-27’,‘2020-01-28’,‘2020-01-29’,‘2020-01-30’,
‘2020-04-06’,‘2020-05-01’,‘2020-06-25’,‘2020-06-26’,‘2020-10-01’,‘2020-10-02’,
‘2020-10-05’,‘2020-10-06’,‘2020-10-07’,‘2020-10-08’,
‘2021-01-01’,
]
def is_holiday(data):#获得节假日
set_date_str=data.strftime(’%Y-%m-%d’)
if set_date_str in rest_holiday:
is_holiday=1
else:
is_holiday=0
return is_holiday
def get_month(data):#获得月份
month=data.month
if(month==8):
month=7
return str(month)
def get_searon(data):
month=data.month
if(month in [2]):
label=‘1’
elif(month in [3,4,5]):
label=‘2’
else:
label=‘3’
return label
def get_weekday(data):
temp=data.weekday()
return str(temp)
#gghj
def delete_week(text):
temp=[]
for a in text:
if( a.isdigit() or a in [’-’]):
temp.append(a)
text=’’.join(temp)
return text
def get_wendu(text):
return int(text[:-1])
def get_weather(text):
w=[]
for a in text:
if(a in [‘雨’]):
w.append(0)
elif(a in [‘阴’]):
w.append(1)
else:
w.append(2)
if(len(w)0):
return ‘2’
else:
return str(min(w))
def get_wind(text):
return str(int(text[-2]))
def get_poution(text):
if(text[-1]‘优’):
return ‘0’
elif(text[-1]==‘良’):
return ‘1’
else:
return ‘2’
weather=pd.read_excel(’/Users/wang/PycharmProjects/untitled2/weather.xlsx’)
weather[‘日期’]=weather[‘日期’].map(delete_week)
weather[‘日期’] = pd.to_datetime(weather[‘日期’])#时间转为datetime
weather.index = weather[‘日期’]#时间变成索引
weather.index.name=‘date’
new_cols=pd.merge(new_cols, weather, how=‘inner’, left_on=‘fshopday’,right_on=‘日期’)
new_cols.index = new_cols[‘日期’]#时间变成索引
del new_cols[‘日期’]#删除这列
new_cols=new_cols.sort_index()#根据时间排序
new_cols.head()
new_cols[‘is_weekend’]=0
new_cols[‘is_holiday’]=0
new_cols[‘month’]=‘a’
new_cols[‘seaon’]=‘a’
new_cols[‘weekday’]=‘a’
#将是否周末,月份,节假日作为特征,写入dataframe
for row in new_cols.index:
new_cols.loc[row,‘is_weekend’]=is_weenkend(row)#得到周末特征
new_cols.loc[row,‘is_holiday’]=is_holiday(row)#得到节假日特征
new_cols.loc[row,‘month’]=get_month(row)#得到月份特征
new_cols.loc[row,‘seaon’]=get_searon(row)
new_cols.loc[row,‘weekday’]=get_weekday(row)
new_cols[‘天气’]=new_cols[‘天气’].map(get_weather)
new_cols[‘风力’]=new_cols[‘风力’].map(get_wind)
new_cols[‘高温’]=new_cols[‘高温’].map(get_wendu)
new_cols[‘低温’]=new_cols[‘低温’].map(get_wendu)
new_cols[‘污染指数’]=new_cols[‘污染指数’].map(get_poution)
new_cols=pd.get_dummies(new_cols)#对月份进行one-hot编码
dummies_num=26
new_cols.head()
#对数据进行归一化
from sklearn.preprocessing import MinMaxScaler,StandardScaler,RobustScaler
scale=MinMaxScaler()#最大最小归一化
feature_1=scale.fit_transform(new_cols.iloc[:,:-dummies_num])#除了周末,节假日,月份,其他特征进行缩放
all_features=np.hstack((feature_1,new_cols.iloc[:,-dummies_num:].values))#连接所有特征
#制作训练集
day_num=7
split_num=80
#train_data=np.zeros((split_num,day_num,all_features.shape[1]))#训练集数据,可以理解为前7天数据
test_data=np.zeros((split_num,day_num,all_features.shape[1]))
test_label=np.zeros((split_num,7,all_features.shape[1]-dummies_num-2))
#train_label=np.zeros((split_num,7,all_features.shape[1]-dummies_num-2))#训练集标签,可以理解为未来7天数据
train_data=np.zeros((feature_1.shape[0]-day_num-split_num-7-7,day_num,all_features.shape[1]))#测试集数据
train_label=np.zeros((feature_1.shape[0]-day_num-split_num-7-7,7,all_features.shape[1]-dummies_num-2))#测试集标签
for i in range(split_num-20,split_num):#遍历all_features前100行,用i:i+7作为训练数据,i+7:i+14预测
test_data[i,:,:]=all_features[i:i+day_num,:]
test_label[i,:,:]=all_features[i+7:i+14,:(-dummies_num-2)]
test_data[0,:,:]=all_features[-7-day_num:-7,:]
test_label[0,:,:]=all_features[-7:?-dummies_num-2)]
for i in range(split_num,(new_cols.shape[0]-7-day_num-7)):#遍历all_features80行以后的,用i:i+7作为训练数据,i+7:i+14预测。-7为了不用最后7天数据
train_data[i-split_num,:,:]=all_features[i:i+day_num,:]
train_label[i-split_num,:,:]=all_features[i+7:i+14,:(-dummies_num-2)]
#搭建lstm模型
from keras.layers import LSTM,Dense,RepeatVector,TimeDistributed
from keras.models import Sequential,load_model
from keras.callbacks import ModelCheckpoint
from numpy.random import seed
seed(1)
n_steps_in, n_steps_out = day_num, 7#输入时间轴7天,输出也是7天
n_features = all_features.shape[1]# 此例中 n features = 特征数量,
#搭建一个两层的lstm网络
model = Sequential()
model.add(LSTM(32, activation=‘relu’, input_shape=(n_steps_in, n_features)))#第一层lstm网络
model.add(RepeatVector(n_steps_out))#
model.add(LSTM(16, activation=‘relu’, return_sequences=True))#第二层lstm网络
model.add(TimeDistributed(Dense(n_features-dummies_num-2)))#输出特征数量
model.compile(optimizer=‘adam’, loss=‘mse’)#损失函数使用mse,均值损失。优化器使用adam。
‘’’
model = Sequential()
model.add(LSTM(32, activation=‘relu’, input_shape=(n_steps_in, n_features),return_sequences=True))#第一层lstm网络
model.add(LSTM(n_features-dummies_num-2, activation=‘relu’, return_sequences=True))#第二层lstm网络
model.compile(optimizer=‘adam’, loss=‘mse’)
‘’’
filepath = “best_weights.h5”
checkpoint = ModelCheckpoint(filepath, monitor=‘val_loss’, verbose=0, save_best_only=True, mode=‘min’)
callbacks_list = [checkpoint]
model.summary()#模型结构,每一层的输出数量。参数数量
samples=np.zeros((train_data.shape[0],))
#模型权重
temp=0.1
for i in range(samples.shape[0]):
temp=temp+0.1
samples[i]=0.1+temp
history=model.fit(train_data,train_label,epochs=100,batch_size=8,validation_data=(test_data,test_label),sample_weight=samples,callbacks=callbacks_list)#模型训练过程
#画出模型训练和测试孙树图像
#plt.clf()
#plt.plot(history.history[‘val_loss’])
#plt.plot(history.history[‘loss’])
#plt.legend([‘val_loss’, ‘loss’], loc=‘upper left’)
#plt.savefig(‘plot_loss.png’)
model=load_model(‘best_weights.h5’)
#取出最后7天数据,预测未来7天
laster_7days=all_features[-(7+day_num):-7]#取出数据
laster_7days=laster_7days.reshape((1,day_num,-1))#转换数据格式
future_7days=model.predict(laster_7days)#预测未来7天
temp=future_7days[0]
future_7days=np.hstack((temp,np.ones((7,2))))
pre_no_scare=scale.inverse_transform(future_7days)
#pre_no_scare=scale.inverse_transform(future_7days[0][:,:-7])#将数据还原为缩放前
pre=pre_no_scare[:,:-2]
pre=pre.round()#四舍五入结果
#将结果写入dataframe,并且存储结果到csv
dates=[datetime(2019,8,8),datetime(2019,8,9),datetime(2019,8,10),
datetime(2019,8,11),datetime(2019,8,12),datetime(2019,8,13),datetime(2019,8,14)]
data_pre=pd.DataFrame(pre,columns=new_cols.columns[?-dummies_num-2)],index=dates)
data_pre.index,name
cols_list=list(new_cols.columns[?-dummies_num-2)])
data_pre.index.name=‘time’
new_cols.index.name=‘time’
data_out=pd.concat([new_cols[cols_list],data_pre])
print(data_out)
data_out.to_csv(’/Users/wang/PycharmProjects/untitled2/data_out.csv’)
最后
以上就是喜悦自行车为你收集整理的如何卖菜!Python的LSTM递归神经网络算法的全部内容,希望文章能够帮你解决如何卖菜!Python的LSTM递归神经网络算法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复