پروژه ای در آنالیز و پیش بینی سری زمانی با استفاده از پایتون

پروژه ای در آنالیز و پیش بینی سری زمانی با استفاده از پایتون

آنالیز سری زمانی، روش های آنالیز داده های سری زمانی برای استخراج آمار معنادار و سایر ویژگیهای را دربر می گیرد. پیش بینی سری زمانی، بکارگیری یک مدل برای پیش بینی مقادیر آینده براساس مقادیر پیشتر مشاهده شده است.

سری زمانی(Time series)، به میزان گسترده ای برای داده های ناایستا(non-stationary) مانند اقتصاد، آب و هوا، قیمت سهام و خرده فروشی مورد استفاده قرار میگیرد. در این پست رویکردهای مختلف پیش بینی سری زمانی مربوط به یک فروشگاه خرده فروشی را شرح خواهیم داد. بیایید شروع کنیم!

داده

داده های فروش یک فروشگاه بزرگ را بکار می بریم که از این قسمت قابل دانلود هستند.

In [1]:
import warnings
import itertools
import numpy as np
import matplotlib.pyplot as plt
warnings.filterwarnings("ignore")
plt.style.use('fivethirtyeight')
import pandas as pd
import statsmodels.api as sm
import matplotlib
matplotlib.rcParams['axes.labelsize'] = 14
matplotlib.rcParams['xtick.labelsize'] = 12
matplotlib.rcParams['ytick.labelsize'] = 12
matplotlib.rcParams['text.color'] = 'k'

دسته های مختلفی در داده های فروش این فروشگاه بزرگ وجود دارد، ما، کار خود را با آنالیز و پیش بینی سری زمانی فروش مبلمان آغاز می کنیم.

In [2]:
df = pd.read_excel("Superstore.xls")
furniture = df.loc[df['Category'] == 'Furniture']
In [3]:
furniture.head()
Out[3]:
Row IDOrder IDOrder DateShip DateShip ModeCustomer IDCustomer NameSegmentCountryCityPostal CodeRegionProduct IDCategorySub-CategoryProduct NameSalesQuantityDiscountProfit
01CA-2016-1521562016-11-082016-11-11Second ClassCG-12520Claire GuteConsumerUnited StatesHenderson42420SouthFUR-BO-10001798FurnitureBookcasesBush Somerset Collection Bookcase261.960020.0041.9136
12CA-2016-1521562016-11-082016-11-11Second ClassCG-12520Claire GuteConsumerUnited StatesHenderson42420SouthFUR-CH-10000454FurnitureChairsHon Deluxe Fabric Upholstered Stacking Chairs,…731.940030.00219.5820
34US-2015-1089662015-10-112015-10-18Standard ClassSO-20335Sean O’DonnellConsumerUnited StatesFort Lauderdale33311SouthFUR-TA-10000577FurnitureTablesBretford CR4500 Series Slim Rectangular Table957.577550.45-383.0310
56CA-2014-1158122014-06-092014-06-14Standard ClassBH-11710Brosina HoffmanConsumerUnited StatesLos Angeles90032WestFUR-FU-10001487FurnitureFurnishingsEldon Expressions Wood and Plastic Desk Access…48.860070.0014.1694
1011CA-2014-1158122014-06-092014-06-14Standard ClassBH-11710Brosina HoffmanConsumerUnited StatesLos Angeles90032WestFUR-TA-10001539FurnitureTablesChromcraft Rectangular Conference Tables1706.184090.2085.3092

5 rows × 21 columns

یک داده خوب در مورد فروش مبلمان در بازه زمانی 4 ساله را در اختیار داریم.

In [4]:
furniture['Order Date'].min(), furniture['Order Date'].max()
Out[4]:
(Timestamp('2014-01-06 00:00:00'), Timestamp('2017-12-30 00:00:00'))

پیش پردازش داده ها

این مرحله، حذف ستونهایی که نیاز نداریم، بررسی مقادیر از دست رفته، تجمیع دادگان فروش  براساس تاریخ و موارد دیگر را دربر می گیرد.

In [5]:
cols = ['Row ID', 'Order ID', 'Ship Date', 'Ship Mode', 'Customer ID', 'Customer Name', 'Segment', 'Country', 'City', 'State', 'Postal Code', 'Region', 'Product ID', 'Category', 'Sub-Category', 'Product Name', 'Quantity', 'Discount', 'Profit']
furniture.drop(cols, axis=1, inplace=True)

furniture = furniture.sort_values('Order Date')

furniture.isnull().sum()
Out[5]:
Order Date    0
Sales         0
dtype: int64
In [6]:
furniture = furniture.groupby('Order Date')['Sales'].sum().reset_index()
In [7]:
furniture.head()
Out[7]:
Order DateSales
02014-01-062573.820
12014-01-0776.728
22014-01-1051.940
32014-01-119.940
42014-01-13879.939

 

شاخص گذاری با استفاده از داده های سری زمانی

 

In [8]:
furniture = furniture.set_index('Order Date')
furniture.index
Out[8]:
DatetimeIndex(['2014-01-06', '2014-01-07', '2014-01-10', '2014-01-11',
               '2014-01-13', '2014-01-14', '2014-01-16', '2014-01-19',
               '2014-01-20', '2014-01-21',
               ...
               '2017-12-18', '2017-12-19', '2017-12-21', '2017-12-22',
               '2017-12-23', '2017-12-24', '2017-12-25', '2017-12-28',
               '2017-12-29', '2017-12-30'],
              dtype='datetime64[ns]', name='Order Date', length=889, freq=None)

کار با داده های تاریخ و زمان فعلی می تواند دشوار و پیچیده باشد، لذا، به جای آن، از میانگین مقدار فروش روزانه ی آن در ماه استفاده می کنیم و آغاز هر ماه را به عنوان برچسب زمان بکار می بریم.

In [9]:
y = furniture['Sales'].resample('MS').mean()

نگاهی اجمالی به داده های فروش مبلمان سال 2017

In [10]:
y['2017':]
Out[10]:
Order Date
2017-01-01     397.602133
2017-02-01     528.179800
2017-03-01     544.672240
2017-04-01     453.297905
2017-05-01     678.302328
2017-06-01     826.460291
2017-07-01     562.524857
2017-08-01     857.881889
2017-09-01    1209.508583
2017-10-01     875.362728
2017-11-01    1277.817759
2017-12-01    1256.298672
Freq: MS, Name: Sales, dtype: float64

 

مصورسازی داده های سری زمانی فروش مبلمان

 

In [11]:
y.plot(figsize=(15, 6))
plt.show()

تعدادی الگوی قابل تمایز در نمودار زمانی ترسیم شده نمایان می گردد. سری زمانی مصور شده، دارای الگوی فصلی است. مثلا فروش، همواره در آغاز سال، پایین و در پایان سال، بالا است. یک روند رو به بالا در طول هر سال به همراه دو ماه فروش کم در میانه ی سال مشاهده می شود.

همچنین، این امکان وجود دارد که داده های خود را با استفاده از یک روش موسوم به تجزیه سری زمانی مصور سازیم که تجزیه سری زمانی به سه مولفه متمایز: روند، فصلی بودن و نویز را میسر می سازد.

In [12]:
from pylab import rcParams
rcParams['figure.figsize'] = 18, 8

decomposition = sm.tsa.seasonal_decompose(y, model='additive')
fig = decomposition.plot()
plt.show()

نمودار قسمت بالا به وضوح نشان می دهد که فروش مبلمان، بی ثبات است و درضمن، فصلی بودن آن مشهود میباشد.

پیش بینی سری زمانی با استفاده از ARIMA

ما برآنیم که یکی از متداول ترین روش های پیش بینی سری زمانی، مشهور به ARIMA را بکار گیریم که مخفف میانگین متحرک یکپارچه خودهمبسته است.

مدل های ARIMA، با علامت ARIMA(p, d, q) نشان داده می شوند. این سه پارامتر برای فصلی بودن، روند و نویز درنظر گرفته می شوند.

In [13]:
p = d = q = range(0, 2)
pdq = list(itertools.product(p, d, q))
seasonal_pdq = [(x[0], x[1], x[2], 12) for x in list(itertools.product(p, d, q))]

print('Examples of parameter combinations for Seasonal ARIMA...')
print('SARIMAX: {} x {}'.format(pdq[1], seasonal_pdq[1]))
print('SARIMAX: {} x {}'.format(pdq[1], seasonal_pdq[2]))
print('SARIMAX: {} x {}'.format(pdq[2], seasonal_pdq[3]))
print('SARIMAX: {} x {}'.format(pdq[2], seasonal_pdq[4]))
Examples of parameter combinations for Seasonal ARIMA...
SARIMAX: (0, 0, 1) x (0, 0, 1, 12)
SARIMAX: (0, 0, 1) x (0, 1, 0, 12)
SARIMAX: (0, 1, 0) x (0, 1, 1, 12)
SARIMAX: (0, 1, 0) x (1, 0, 0, 12)

این مرحله، مرحله انتخاب پارامتر برای مدل سری زمانی ARIMA فروش مبلمان است. در این مرحله با استفاده از یک «جستجوی شبکه ای(Grid Search)» سعی در یافتن مجموعه بهینه ای از پارامترهایی که بهترین عملکرد را برای مدل ما نتیجه می دهد، داریم.

In [14]:
for param in pdq:
    for param_seasonal in seasonal_pdq:
        try:
            mod = sm.tsa.statespace.SARIMAX(y,
                                            order=param,
                                            seasonal_order=param_seasonal,
                                            enforce_stationarity=False,
                                            enforce_invertibility=False)
            results = mod.fit()
            print('ARIMA{}x{}12 - AIC:{}'.format(param, param_seasonal, results.aic))
        except:
            continue
ARIMA(0, 0, 0)x(0, 0, 0, 12)12 - AIC:769.0817523205916
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(0, 0, 0)x(0, 0, 1, 12)12 - AIC:1262.9006294892013
ARIMA(0, 0, 0)x(0, 1, 0, 12)12 - AIC:477.71701309202774
ARIMA(0, 0, 0)x(1, 0, 0, 12)12 - AIC:497.2314433418337
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(0, 0, 0)x(1, 0, 1, 12)12 - AIC:839.0882059077763
ARIMA(0, 0, 0)x(1, 1, 0, 12)12 - AIC:318.0047199116341
ARIMA(0, 0, 1)x(0, 0, 0, 12)12 - AIC:720.9252270758096
ARIMA(0, 0, 1)x(0, 0, 1, 12)12 - AIC:2790.5484339930917
ARIMA(0, 0, 1)x(0, 1, 0, 12)12 - AIC:466.56074298091255
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(0, 0, 1)x(1, 0, 0, 12)12 - AIC:499.56493917605627
ARIMA(0, 0, 1)x(1, 0, 1, 12)12 - AIC:2617.162308375466
ARIMA(0, 0, 1)x(1, 1, 0, 12)12 - AIC:319.9884876946869
ARIMA(0, 1, 0)x(0, 0, 0, 12)12 - AIC:677.8947668259311
ARIMA(0, 1, 0)x(0, 0, 1, 12)12 - AIC:1413.64772985159
ARIMA(0, 1, 0)x(0, 1, 0, 12)12 - AIC:486.63785672282035
ARIMA(0, 1, 0)x(1, 0, 0, 12)12 - AIC:497.78896630044073
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(0, 1, 0)x(1, 0, 1, 12)12 - AIC:1352.6147833065181
ARIMA(0, 1, 0)x(1, 1, 0, 12)12 - AIC:319.7714068109212
ARIMA(0, 1, 1)x(0, 0, 0, 12)12 - AIC:649.9056176816952
ARIMA(0, 1, 1)x(0, 0, 1, 12)12 - AIC:2549.569029416418
ARIMA(0, 1, 1)x(0, 1, 0, 12)12 - AIC:458.87055484828625
ARIMA(0, 1, 1)x(1, 0, 0, 12)12 - AIC:486.1832977442827
ARIMA(0, 1, 1)x(1, 0, 1, 12)12 - AIC:2674.7168338900806
ARIMA(0, 1, 1)x(1, 1, 0, 12)12 - AIC:310.75743684173517
ARIMA(1, 0, 0)x(0, 0, 0, 12)12 - AIC:692.1645522067712
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(1, 0, 0)x(0, 0, 1, 12)12 - AIC:1123.1962646827074
ARIMA(1, 0, 0)x(0, 1, 0, 12)12 - AIC:479.46321478521355
ARIMA(1, 0, 0)x(1, 0, 0, 12)12 - AIC:480.92593679351984
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(1, 0, 0)x(1, 0, 1, 12)12 - AIC:1062.882600460342
ARIMA(1, 0, 0)x(1, 1, 0, 12)12 - AIC:304.4664675084592
ARIMA(1, 0, 1)x(0, 0, 0, 12)12 - AIC:665.7794442186298
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(1, 0, 1)x(0, 0, 1, 12)12 - AIC:2653.503813142992
ARIMA(1, 0, 1)x(0, 1, 0, 12)12 - AIC:468.3685195815004
ARIMA(1, 0, 1)x(1, 0, 0, 12)12 - AIC:482.5763323876868
ARIMA(1, 0, 1)x(1, 0, 1, 12)12 - AIC:3279.779685811484
ARIMA(1, 0, 1)x(1, 1, 0, 12)12 - AIC:306.0156002158217
ARIMA(1, 1, 0)x(0, 0, 0, 12)12 - AIC:671.2513547541902
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(1, 1, 0)x(0, 0, 1, 12)12 - AIC:1382.9018241552365
ARIMA(1, 1, 0)x(0, 1, 0, 12)12 - AIC:479.20034222811347
ARIMA(1, 1, 0)x(1, 0, 0, 12)12 - AIC:475.3403658785043
ARIMA(1, 1, 0)x(1, 0, 1, 12)12 - AIC:1788.4519073447418
ARIMA(1, 1, 0)x(1, 1, 0, 12)12 - AIC:300.6270901345414
ARIMA(1, 1, 1)x(0, 0, 0, 12)12 - AIC:649.0318019835566
ARIMA(1, 1, 1)x(0, 0, 1, 12)12 - AIC:2706.243082489858
ARIMA(1, 1, 1)x(0, 1, 0, 12)12 - AIC:460.4762687610458
ARIMA(1, 1, 1)x(1, 0, 0, 12)12 - AIC:469.52503546607596
ARIMA(1, 1, 1)x(1, 0, 1, 12)12 - AIC:2576.305524683936
/Users/majidhazari/anaconda3/lib/python3.6/site-packages/statsmodels/base/model.py:508: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
ARIMA(1, 1, 1)x(1, 1, 0, 12)12 - AIC:297.7875439533362

خروجی بالا نشان می دهد که SARIMAX(1, 1, 1)x(1, 1, 0, 12)، کمترین مقدار AIC به میزان ۲۹۷.۷۸ را نتیجه می دهد. لذا، آن را به عنوان بهترین گزینه درنظر می گیریم.

برازاندن مدل ARIMA

In [15]:
mod = sm.tsa.statespace.SARIMAX(y,
                                order=(1, 1, 1),
                                seasonal_order=(1, 1, 0, 12),
                                enforce_stationarity=False,
                                enforce_invertibility=False)
results = mod.fit()
print(results.summary().tables[1])
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
ar.L1          0.0146      0.342      0.043      0.966      -0.655       0.684
ma.L1         -1.0000      0.360     -2.781      0.005      -1.705      -0.295
ar.S.L12      -0.0253      0.042     -0.609      0.543      -0.107       0.056
sigma2      2.958e+04   1.22e-05   2.43e+09      0.000    2.96e+04    2.96e+04
==============================================================================

باید همواره باید امکانات عیب شناسی(diagnostics) مدل را به منظور تحقیق و بررسی هر نوع رفتار غیرمعمول  اجرا کنیم.

In [16]:
results.plot_diagnostics(figsize=(16, 8))
plt.show()

مدل ما کامل و بی عیب نیست، امکانات عیب شناسی مدل ما نشان می دهد که باقی مانده های(residuals) مدل، دارای توزیع نزدیک به توزیع نرمال هستند.

ارزیابی پیش بینی ها

فروش پیش بینی شده را با فروش واقعی سری زمانی مقایسه می کنیم و پیش بینی های بازه زمانی 1/1/2017 تا پایان داده ها را مشخص می نماییم تا میزان دقت پیش بینی های خود را دریابیم.

In [17]:
pred = results.get_prediction(start=pd.to_datetime('2017-01-01'), dynamic=False)
pred_ci = pred.conf_int()
ax = y['2014':].plot(label='observed')
pred.predicted_mean.plot(ax=ax, label='One-step ahead Forecast', alpha=.7, figsize=(14, 7))
ax.fill_between(pred_ci.index,
                pred_ci.iloc[:, 0],
                pred_ci.iloc[:, 1], color='k', alpha=.2)
ax.set_xlabel('Date')
ax.set_ylabel('Furniture Sales')
plt.legend()
plt.show()

نمودار خطی، مقادیر مشاهده شده را در مقایسه با مقادیر پیش بینی شده نشان می دهد. در مجموع پیش بینی های ما با مقادیر واقعی  بسیار همخوانی دارد که نشانگر یک روند رو به بالاست که از ابتدای سال آغاز می شود و نزدیک به انتهای سال، فصلی است.

In [18]:
y_forecasted = pred.predicted_mean
y_truth = y['2017-01-01':]
mse = ((y_forecasted - y_truth) ** 2).mean()
print('The Mean Squared Error of our forecasts is {}'.format(round(mse, 2)))
The Mean Squared Error of our forecasts is 22993.57
In [19]:
print('The Root Mean Squared Error of our forecasts is {}'.format(round(np.sqrt(mse), 2)))
The Root Mean Squared Error of our forecasts is 151.64

خطای میانگین مربعات (MSE) یک برآوردگر  در آمار، میانگین مربعات خطاها، یعنی میانگین مربع تفاوت میان مقادیر مشاهده شده (واقعی) و آنچه که برآورد می شود را می سنجد. MSE، یک معیار برای سنجش کیفیت یک برآوردگر است که همواره غیرمنفی است و هرچه MSE کوچک تر باشد، یافتن خط بهترین برازش، نزدیک تر (دقیق تر) می شود.

خطای ریشه میانگین مربعات (RMSE) به ما می گوید که مدل مان قادر به پیش بینی میانگین فروش روزانه مبلمان در مجموعه داده های آزمایشی با خطایی معادل ۱۵۱.۶۴ واحد با داده واقعی است.

فروش روزانه مبلمان ما، از حدود 400 تا بیش از 1200 را دربر می گیرد. این مدل، بنظر من، تاکنون مدل نسبتا خوبی بوده است.

پیش بینی و مصور سازی آنها

In [20]:
pred_uc = results.get_forecast(steps=100)
pred_ci = pred_uc.conf_int()
ax = y.plot(label='observed', figsize=(14, 7))
pred_uc.predicted_mean.plot(ax=ax, label='Forecast')
ax.fill_between(pred_ci.index,
                pred_ci.iloc[:, 0],
                pred_ci.iloc[:, 1], color='k', alpha=.25)
ax.set_xlabel('Date')
ax.set_ylabel('Furniture Sales')
plt.legend()
plt.show()

جدول ما، فصلی بودن فروش مبلمان را به وضوح نشان می دهد. چنانچه با آینده بسیار دورتر، دست به پیش بینی بزنیم، طبیعی است که اطمینان کمتری به مقادیر پیش بینی شده داشته باشیم. فاصله های اطمینان ایجاد شده (نمایش به عنوان بازه خاکستری) این امر را بیان می کند، که با آینده بسیار دورتر، بزرگ تر می شود.

آنالیز سری زمانی مبلمان در قسمت بالا، کنجکاوی بنده را در رابطه با دیگر دسته ها و چگونگی مقایسه آن ها با یکدیگر در طول زمان برانگیخت. لذا برآنیم تا سری زمانی مبلمان و تجهیزات اداری را مقایسه نماییم.

مقایسه سری زمانی مبلمان با سری زمانی تجهیزات اداری

با توجه به داده ها تعداد فروش تجهیزات اداری طی این سالها نسبت به مبلمان بسیار بیشتر بوده است.

In [21]:
furniture = df.loc[df['Category'] == 'Furniture']
office = df.loc[df['Category'] == 'Office Supplies']
furniture.shape, office.shape
Out[21]:
((2121, 21), (6026, 21))

کاوش داده ها

ما می خواهیم فروش دو دسته را در همین دوره زمانی مقایسه کنیم. این امر به معنای ترکیب دو محموعه داده در یک مجموعه و ترسیم نمودار سری زمانی این دو مجموعه در یک نمودار است.

In [22]:
cols = ['Row ID', 'Order ID', 'Ship Date', 'Ship Mode', 'Customer ID', 'Customer Name', 'Segment', 'Country', 'City', 'State', 'Postal Code', 'Region', 'Product ID', 'Category', 'Sub-Category', 'Product Name', 'Quantity', 'Discount', 'Profit']
furniture.drop(cols, axis=1, inplace=True)
office.drop(cols, axis=1, inplace=True)

furniture = furniture.sort_values('Order Date')
office = office.sort_values('Order Date')

furniture = furniture.groupby('Order Date')['Sales'].sum().reset_index()
office = office.groupby('Order Date')['Sales'].sum().reset_index()

furniture = furniture.set_index('Order Date')
office = office.set_index('Order Date')

y_furniture = furniture['Sales'].resample('MS').mean()
y_office = office['Sales'].resample('MS').mean()

furniture = pd.DataFrame({'Order Date':y_furniture.index, 'Sales':y_furniture.values})
office = pd.DataFrame({'Order Date': y_office.index, 'Sales': y_office.values})

store = furniture.merge(office, how='inner', on='Order Date')
store.rename(columns={'Sales_x': 'furniture_sales', 'Sales_y': 'office_sales'}, inplace=True)
store.head()
Out[22]:
Order Datefurniture_salesoffice_sales
02014-01-01480.194231285.357647
12014-02-01367.93160063.042588
22014-03-01857.291529391.176318
32014-04-01567.488357464.794750
42014-05-01432.049188324.346545
In [23]:
plt.figure(figsize=(20, 8))
plt.plot(store['Order Date'], store['furniture_sales'], 'b-', label = 'furniture')
plt.plot(store['Order Date'], store['office_sales'], 'r-', label = 'office supplies')
plt.xlabel('Date'); plt.ylabel('Sales'); plt.title('Sales of Furniture and Office Supplies')
plt.legend()
Out[23]:
<matplotlib.legend.Legend at 0x1c0e43eb38>

مشاهده می کنیم که فروش مبلمان و تجهیزات اداری دارای یک الگوی فصلی مشابه است. اوایل سال، فصلِ فروش کم برای هر دو دسته است. این طور بنظر می رسد که زمان تابستان برای تجهیزات اداری نیز زمان کسادی است، درضمن، میانگین فروش روزانه مبلمان در اکثر ماه ها از میانگین فروش روزانه تجهیزات اداری بیشتر است. این امر طبیعی است، چراکه مقدار مبلمان نسبت به مقدار تجهیزات اداری بایستی بسیار بیشتر باشد. میانگین فروش روزانه تجهیزات اداری، هر از گاهی از مبلمان پیشی می گیرد. بیایید مشخص کنیم برای اولین بار چه زمانی فروش تجهیزات اداری از فروش مبلمان پیش افتاد.

In [24]:
first_date = store.ix[np.min(list(np.where(store['office_sales'] > store['furniture_sales'])[0])), 'Order Date']

print("Office supplies first time produced higher sales than furniture is {}.".format(first_date.date()))
Office supplies first time produced higher sales than furniture is 2014-07-01.

مدل سازی سری زمانی با استفاده از Prophet

ابزار پیش بینی Prophet که توسط فیسبوک در سال 2017 منتشر شد، برای آنالیز سری زمانی طراحی شده است که دارای الگوهایی در بازه های زمانی مختلف مانند سالانه، هفتگی یا روزانه هستند. این ابزار قابلیت های پیشرفته ای برای مدل سازی تاثیرات تعطیلات بر سری زمانی برخوردار است. بنابراین در این قسمت میخواهیم از Prophet استفاده کنیم.

In [25]:
from fbprophet import Prophet

furniture = furniture.rename(columns={'Order Date': 'ds', 'Sales': 'y'})
furniture_model = Prophet(interval_width=0.95)
furniture_model.fit(furniture)

office = office.rename(columns={'Order Date': 'ds', 'Sales': 'y'})
office_model = Prophet(interval_width=0.95)
office_model.fit(office)

furniture_forecast = furniture_model.make_future_dataframe(periods=36, freq='MS')
furniture_forecast = furniture_model.predict(furniture_forecast)
office_forecast = office_model.make_future_dataframe(periods=36, freq='MS')
office_forecast = office_model.predict(office_forecast)

plt.figure(figsize=(18, 6))
furniture_model.plot(furniture_forecast, xlabel = 'Date', ylabel = 'Sales')
plt.title('Furniture Sales')
INFO:fbprophet.forecaster:Disabling weekly seasonality. Run prophet with weekly_seasonality=True to override this.
INFO:fbprophet.forecaster:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
INFO:fbprophet.forecaster:Disabling weekly seasonality. Run prophet with weekly_seasonality=True to override this.
INFO:fbprophet.forecaster:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
Out[25]:
Text(0.5,1,'Furniture Sales')
<Figure size 1296x432 with 0 Axes>
In [26]:
plt.figure(figsize=(18, 6))
office_model.plot(office_forecast, xlabel = 'Date', ylabel = 'Sales')
plt.title('Office Supplies Sales');
<Figure size 1296x432 with 0 Axes>

 

مقایسه پیش بینی ها

ما، پیشتر، پیش بینی هایی برای سه سال آینده ی این دو دسته انجام داده ایم. حال با کنار هم گذاشتن آن ها، پیش بینی های انجام شده را مورد مقایسه قرار می دهیم.

In [27]:
furniture_names = ['furniture_%s' % column for column in furniture_forecast.columns]
office_names = ['office_%s' % column for column in office_forecast.columns]

merge_furniture_forecast = furniture_forecast.copy()
merge_office_forecast = office_forecast.copy()

merge_furniture_forecast.columns = furniture_names
merge_office_forecast.columns = office_names

forecast = pd.merge(merge_furniture_forecast, merge_office_forecast, how = 'inner', left_on = 'furniture_ds', right_on = 'office_ds')
forecast = forecast.rename(columns={'furniture_ds': 'Date'}).drop('office_ds', axis=1)
forecast.head()
Out[27]:
Datefurniture_trendfurniture_yhat_lowerfurniture_yhat_upperfurniture_trend_lowerfurniture_trend_upperfurniture_additive_termsfurniture_additive_terms_lowerfurniture_additive_terms_upperfurniture_yearlyoffice_additive_termsoffice_additive_terms_loweroffice_additive_terms_upperoffice_yearlyoffice_yearly_loweroffice_yearly_upperoffice_multiplicative_termsoffice_multiplicative_terms_loweroffice_multiplicative_terms_upperoffice_yhat
02014-01-01731.350832270.581563832.506447731.350832731.350832-178.935009-178.935009-178.935009-178.935009-132.487041-132.487041-132.487041-132.487041-132.487041-132.4870410.00.00.0297.861111
12014-02-01733.442293133.431899692.107776733.442293733.442293-324.072006-324.072006-324.072006-324.072006-288.224139-288.224139-288.224139-288.224139-288.224139-288.2241390.00.00.0149.596082
22014-03-01735.331355401.077560954.158981735.331355735.331355-69.359319-69.359319-69.359319-69.3593190.8473730.8473730.8473730.8473730.8473730.8473730.00.00.0445.416558
32014-04-01737.422817319.794257882.437425737.422817737.422817-140.383817-140.383817-140.383817-140.383817-89.140087-89.140087-89.140087-89.140087-89.140087-89.1400870.00.00.0362.901168
42014-05-01739.446812290.154074823.525334739.446812739.446812-172.281896-172.281896-172.281896-172.281896-183.186206-183.186206-183.186206-183.186206-183.186206-183.1862060.00.00.0276.086083

5 rows × 31 columns

مصورسازی روند و پیش بینی

In [28]:
plt.figure(figsize=(10, 7))
plt.plot(forecast['Date'], forecast['furniture_trend'], 'b-')
plt.plot(forecast['Date'], forecast['office_trend'], 'r-')
plt.legend(); plt.xlabel('Date'); plt.ylabel('Sales')
plt.title('Furniture vs. Office Supplies Sales Trend')
Out[28]:
Text(0.5,1,'Furniture vs. Office Supplies Sales Trend')
In [29]:
plt.figure(figsize=(10, 7))
plt.plot(forecast['Date'], forecast['furniture_yhat'], 'b-')
plt.plot(forecast['Date'], forecast['office_yhat'], 'r-')
plt.legend(); plt.xlabel('Date'); plt.ylabel('Sales')
plt.title('Furniture vs. Office Supplies Estimate')
Out[29]:
Text(0.5,1,'Furniture vs. Office Supplies Estimate')

روندها و الگوها

ما اکنون می توانین مدل های Prophet را برای بررسی روندهای مختلف این دو دسته در داده ها مورد استفاده قرار دهیم.

 

In [30]:
furniture_model.plot_components(furniture_forecast)
Out[30]:
In [31]:
office_model.plot_components(office_forecast)
Out[31]:

خوب است بدانید که فروش هم مبلمان و هم تجهیزات اداری در طول زمان، افزایش خطی داشته است و این رشد را ادامه خواهد داشت، هرچند رشد تجهیزات اداری اندکی سریع تر بنظر می آید.

آوریل، بدترین ماه برای مبلمان و فوریه، بدترین ماه برای تجهیزات اداری است. دسامبر، بهترین ماه برای مبلمان و اکتبر، بهترین ماه برای تجهیزات اداری است.

آنالیزهای سری زمانی بسیاری همچون پیش بینی با استفاده از محدودیت های عدم قطعیت (uncertainty bounds)، نقطه تغییر  (change point) و تشخیص آنومالی  و پیش بینی سری زمانی با استفاده از منبع داده خارجی وجود دارد. ما تنها شروع کننده بودیم!

آیا سوالی دارید؟

سوال خود را در بخش نظرات بپرسید، سعی میکنم به آنها جواب مناسب بدم.

2 دیدگاه دربارهٔ «پروژه ای در آنالیز و پیش بینی سری زمانی با استفاده از پایتون»

  1. سلام
    آیا در زمینه پیش بینی ارز دیجیتالی بیت کوین با سری های زمانی روشی را می شناسید که دقت و حساسیت بالایی داشته باشد چه خودتان زحمت کشیده باشد چه ارجاع دهید.
    سپاس بابت پاسخگویی

    پاسخ
    • سلام
      چون در رابطه با قیمت ارزهای دیجیتال عوامی بسیار زیادی درگیر هستند معمولا روش های آماری و یا شبکه های عمیق به تنهایی خیلی دقت بالایی ندارند.

      پاسخ

دیدگاهتان را بنویسید