5種用于預(yù)測銷售的機(jī)器學(xué)習(xí)技術(shù)
預(yù)測銷售是機(jī)器學(xué)習(xí)(ML)的常見且必不可少的用途。預(yù)測銷售可用于確定基準(zhǔn)并確定新計(jì)劃的增量影響,根據(jù)預(yù)期需求規(guī)劃資源以及規(guī)劃未來預(yù)算。在本文中,我將展示如何實(shí)現(xiàn)5種不同的ML模型來預(yù)測銷售。
初期準(zhǔn)備
首先我們先加載數(shù)據(jù)并將其轉(zhuǎn)換為一個(gè)結(jié)構(gòu),然后將其用于每個(gè)模型。以原始格式,每一行數(shù)據(jù)代表十個(gè)商店中一天的銷售額。我們的目標(biāo)是預(yù)測月度銷售額,因此我們將首先將所有商店和天數(shù)合并為月度總銷售額。
- def load_data():
- return pd.read_csv('D:\Jupyter\dataset\demand-forecasting-kernels-only/train.csv')
- def monthly_sales(data):
- monthly_data = data.copy()
- monthly_datamonthly_data.date = monthly_data.date.apply(lambda x: str(x)[:-3])
- monthly_datamonthly_data = monthly_data.groupby('date')['sales'].sum().reset_index()
- monthly_data.date = pd.to_datetime(monthly_data.date)
- return monthly_data
- monthly_df = monthly_sales(sales_data)
- monthly_df.head()
在我們的新數(shù)據(jù)框中,每一行現(xiàn)在代表所有商店在給定月份的總銷售額。
如果我們繪制隨時(shí)間變化的每月總銷售量,我們會(huì)看到平均每月銷售量隨時(shí)間增加,這意味著我們的數(shù)據(jù)不是固定的。為了使其平穩(wěn),我們將計(jì)算每月銷售額之間的差異,并將其作為新列添加到我們的數(shù)據(jù)框中。
- def get_diff(data):
- data['sales_diff'] = data.sales.diff()
- datadata = data.dropna()
- data.to_csv('D:/Jupyter/dataset/demand-forecasting-kernels-only/stationary_df.csv')
- return data
- stationary_df = get_diff(monthly_df)
下面是差異轉(zhuǎn)換前后數(shù)據(jù)外觀的直觀表示:
比較差異前后的平穩(wěn)性
現(xiàn)在,我們的數(shù)據(jù)代表了每月的銷售額,并且已經(jīng)將其轉(zhuǎn)換為固定值,接下來我們將為不同的模型類型設(shè)置數(shù)據(jù)。為此,我們將定義兩種不同的結(jié)構(gòu):一種將用于ARIMA建模,另一種將用于其余的模型。
對于我們的Arima模型,我們只需要一個(gè)日期時(shí)間索引和因變量(銷售額差異)列。
- def generate_arima_data(data):
- dt_data = data.set_index('date').drop('sales', axis=1)
- dt_data.dropna(axis=0)
- dt_data.to_csv('D:/Jupyter/dataset/demand-forecasting-kernels-only/arima_df.csv')
- return dt_data
- arima_datetime = generate_arima_data(stationary_df)
對于其他模型,我們將創(chuàng)建一個(gè)新的數(shù)據(jù)框,其中每個(gè)特征代表上個(gè)月的銷售額。為了確定在我們的特征集中包含多少個(gè)月,我們將觀察自相關(guān)和部分自相關(guān)圖,并在ARIMA建模中使用選擇滯后時(shí)間的規(guī)則。這樣,我們就可以為我們的ARIMA和回歸模型保持一致的回顧周期。
自相關(guān)和局部自相關(guān)圖
基于上述情況,我們將選擇回溯期為12個(gè)月。因此,我們將生成一個(gè)包含13列的數(shù)據(jù)框,12個(gè)月每個(gè)月為1列,而我們的因變量即銷售額差異列為第1列。
- def generate_supervised(data):
- supervised_df = data.copy()
- #create column for each lag
- for i in range(1,13):
- col_name = 'lag_' + str(i)
- supervised_df[col_name] = supervised_df['sales_diff'].shift(i)
- #drop null values
- supervised_dfsupervised_df = supervised_df.dropna().reset_index(drop=True)
- supervised_df.to_csv('D:/Jupyter/dataset/demand-forecasting-kernels-only/model_df.csv', index=False)
- return supervised_df
- model_df = generate_supervised(stationary_df)
現(xiàn)在我們有兩個(gè)獨(dú)立的數(shù)據(jù)結(jié)構(gòu),一個(gè)是Arima結(jié)構(gòu),它包含一個(gè)datetime索引,另一個(gè)是監(jiān)督結(jié)構(gòu),它包含滯后時(shí)間特征。
ARIMA和受監(jiān)督的數(shù)據(jù)框用于銷售預(yù)測
建模
為了創(chuàng)建和評估所有的模型,我們使用了一系列執(zhí)行以下函數(shù)的輔助函數(shù)。
- 訓(xùn)練、測試、拆分:我們將數(shù)據(jù)分開,使過去的12個(gè)月成為測試集的一部分,其余數(shù)據(jù)用于訓(xùn)練我們的模型
- 縮放數(shù)據(jù):使用最小-最大縮放器,我們將縮放數(shù)據(jù),以便所有變量都在-1到1的范圍內(nèi)
- 反向縮放:運(yùn)行模型后,我們將使用此輔助函數(shù)來反轉(zhuǎn)步驟2的縮放
- 創(chuàng)建一個(gè)預(yù)測數(shù)據(jù)框:生成一個(gè)數(shù)據(jù)框,其中包括在測試集中捕獲的實(shí)際銷售額和模型的預(yù)測結(jié)果,以便我們能夠量化我們的成功
- 對模型評分:這個(gè)輔助函數(shù)將保存我們預(yù)測的均方根誤差(RMSE)和均值絕對誤差(MAE),以比較五個(gè)模型的性能
1. 回歸模型:線性回歸,隨機(jī)森林回歸,XGBoost
對于我們的回歸模型,我們可以使用scikit-learn庫的fit-predict結(jié)構(gòu)。因此,我們可以建立一個(gè)基礎(chǔ)建模結(jié)構(gòu),我們將針對每個(gè)模型進(jìn)行調(diào)用。下面的函數(shù)調(diào)用上面概述的許多輔助函數(shù)來拆分?jǐn)?shù)據(jù),運(yùn)行模型并輸出RMSE和MAE分?jǐn)?shù)。
- def regressive_model(train_data, test_data, model, model_name):
- # Call helper functions to create X & y and scale data
- X_train, y_train, X_test, y_test, scaler_object =
- scale_data(train_data, test_data)
- # Run regression model
- mod = model
- mod.fit(X_train, y_train)
- predictions = mod.predict(X_test)
- # Call helper functions to undo scaling & create prediction df
- original_df = pd.read_csv('D:/Jupyter/dataset/demand-forecasting-kernels-only/train.csv')
- unscaled = undo_scaling(predictions, X_test, scaler_object)
- unscaled_df = predict_df(unscaled, original_df)
- # Call helper functions to print scores and plot results
- get_scores(unscaled_df, original_df, model_name)
- plot_results(unscaled_df, original_df, model_name)
- # Separate data into train and test sets
- train, test = tts(model_df)
- # Call model frame work for linear regression
- regressive_model(train, test, LinearRegression(),'LinearRegression')
- # Call model frame work for random forest regressor
- regressive_model(train, test,
- RandomForestRegressor(n_estimators=100,
- max_depth=20),
- 'RandomForest')
- # Call model frame work for XGBoost
- regressive_model(train, test, XGBRegressor(n_estimators=100,
- learning_rate=0.2),
- 'XGBoost')
下面的輸出顯示了每個(gè)回歸模型的預(yù)測(紅色)覆蓋在實(shí)際銷售(藍(lán)色)之上。雖然結(jié)果看起來很相似,但細(xì)微的差別相當(dāng)于幾千美元的銷售額,我們將在下面的比較部分中看到。
2. 長短期記憶(LSTM)
LSTM是一種遞歸神經(jīng)網(wǎng)絡(luò),對于使用順序數(shù)據(jù)進(jìn)行預(yù)測特別有用。為此,我們將使用非常簡單的LSTM。為了提高準(zhǔn)確性,可以添加周期性特征和附加模型復(fù)雜性。
- def lstm_model(train_data, test_data):
- X_train, y_train, X_test, y_test, scaler_object = scale_data(train_data, test_data)
- X_trainX_train = X_train.reshape(X_train.shape[0], 1, X_train.shape[1])
- X_testX_test = X_test.reshape(X_test.shape[0], 1, X_test.shape[1])
- model = Sequential()
- model.add(LSTM(4, batch_input_shape=(1, X_train.shape[1], X_train.shape[2]),
- stateful=True))
- model.add(Dense(1))
- model.add(Dense(1))
- model.compile(loss='mean_squared_error', optimizer='adam')
- model.fit(X_train, y_train, epochs=200, batch_size=1, verbose=1,
- shuffle=False)
- predictions = model.predict(X_test,batch_size=1)
- original_df = load_original_df()
- unscaled = undo_scaling(predictions, X_test, scaler_object, lstm=True)
- unscaled_df = predict_df(unscaled, original_df)
- get_scores(unscaled_df, original_df, 'LSTM')
- plot_results(unscaled_df, original_df, 'LSTM')
生成的圖看起來與上面的三個(gè)回歸圖相似,因此我們將繼續(xù)比較結(jié)果,直到我們看到下面的誤差為止。
LSTM模型預(yù)測與實(shí)際銷售額
3. ARIMA
ARIMA模型看起來與上面的模型略有不同。我們使用statsmodels SARIMAX軟件包來訓(xùn)練模型并生成動(dòng)態(tài)預(yù)測。SARIMA模型分為幾個(gè)部分。
- AR:表示為p,是自回歸模型
- I:用d表示,是微分項(xiàng)
- MA:表示為q,是移動(dòng)平均模型
- S:使我們能夠添加周期性成分
在下面的代碼中,我們定義我們的模型,然后對數(shù)據(jù)的最后12個(gè)月進(jìn)行動(dòng)態(tài)預(yù)測。對于標(biāo)準(zhǔn)的非動(dòng)態(tài)預(yù)測,下個(gè)月的預(yù)測是使用前幾個(gè)月的實(shí)際銷售額進(jìn)行的。相反,對于動(dòng)態(tài)預(yù)測,使用前幾個(gè)月的預(yù)測銷售額進(jìn)行下個(gè)月的預(yù)測。
- def lstm_model(train_data, test_data):
- X_train, y_train, X_test, y_test, scaler_object = scale_data(train_data, test_data)
- X_trainX_train = X_train.reshape(X_train.shape[0], 1, X_train.shape[1])
- X_testX_test = X_test.reshape(X_test.shape[0], 1, X_test.shape[1])
- model = Sequential()
- model.add(LSTM(4, batch_input_shape=(1, X_train.shape[1], X_train.shape[2]),
- stateful=True))
- model.add(Dense(1))
- model.add(Dense(1))
- model.compile(loss='mean_squared_error', optimizer='adam')
- model.fit(X_train, y_train, epochs=200, batch_size=1, verbose=1,
- shuffle=False)
- predictions = model.predict(X_test,batch_size=1)
- original_df = load_original_df()
- unscaled = undo_scaling(predictions, X_test, scaler_object, lstm=True)
- unscaled_df = predict_df(unscaled, original_df)
- get_scores(unscaled_df, original_df, 'LSTM')
- plot_results(unscaled_df, original_df, 'LSTM')
同樣,結(jié)果看起來還不錯(cuò)。我們將在下面進(jìn)一步進(jìn)行挖掘。
ARIMA模型預(yù)測與實(shí)際銷售額
比較模型
為了比較模型性能,我們將查看均方根誤差(RMSE)和均值絕對誤差(MAE)。這些指標(biāo)通常都用于比較模型性能,但是它們的直覺和數(shù)學(xué)含義略有不同。
- MAE:均值絕對誤差告訴我們,我們的預(yù)測與真實(shí)值之間的距離。在這種情況下,所有誤差的權(quán)重都相同。
- RMSE:我們通過取所有平方誤差之和的平方根來計(jì)算RMSE。當(dāng)我們平方時(shí),較大的誤差對整體誤差有較大的影響,而較小的誤差對整體誤差沒有太大的影響。
從上面的輔助函數(shù)中,我們使用get_scores計(jì)算每個(gè)模型的RMSE和MAE分?jǐn)?shù)。這些分?jǐn)?shù)保存在字典中并保存起來。為了進(jìn)行比較,我們將把字典轉(zhuǎn)換成Pandas數(shù)據(jù)框并繪制結(jié)果。
- def create_results_df():
- results_dict = pickle.load(open("model_scores.p", "rb"))
- results_dict.update(pickle.load(open("arima_model_scores.p", "rb")))
- restults_df = pd.DataFrame.from_dict(results_dict, orient='index',
- columns=['RMSE', 'MAE','R2'])
- restults_dfrestults_df = restults_df.sort_values(by='RMSE', ascending=False).reset_index()
- return restults_df
- results = create_results_df()
這為我們提供了以下數(shù)據(jù)框。
我們可以看到,盡管我們的模型輸出在上圖中看起來相似,但它們的準(zhǔn)確度確實(shí)有所不同。下面是可以幫助我們看到差異的視覺效果。
比較模型性能
結(jié)論
我們看到的是,總體而言,XGBoost模型具有最佳性能,緊隨其后的是ARIMA和LSTM模型。需要注意的是,以上所有模型都是以其最基本的形式衍生的,以演示如何將其用于銷售預(yù)測。僅對模型進(jìn)行了微調(diào),以最大程度地減少復(fù)雜性。例如,LSTM可以具有許多其他節(jié)點(diǎn)和層以提高性能。
要確定哪種模型適合您的用例,應(yīng)考慮以下內(nèi)容:
- 模型復(fù)雜度與可解釋性的程度。
- 可以調(diào)整模型,并可以對函數(shù)進(jìn)行設(shè)計(jì)以包括周期性信息,節(jié)假日,周末等。
- 了解如何使用結(jié)果以及如何輸入數(shù)據(jù)來更新模型。
- 使用交叉驗(yàn)證或類似技術(shù)來調(diào)整模型,以避免數(shù)據(jù)過度擬合。