<jupyter_start><jupyter_text>Modules<jupyter_code>import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from pylab import rcParams
# For Sarimax
import itertools
import warnings<jupyter_output><empty_output><jupyter_text>Variables and parameters<jupyter_code>CSV_PATH='/home/nicolaesse/TennisTimeSerie/Values_2011_2018.csv'
plt.style.use('fast')<jupyter_output><empty_output><jupyter_text>Data reading Load the data into a DataFrame. fillna and bfill are used to be sure that there's no empty values between first and last day.<jupyter_code>RacketsDF = pd.read_csv(CSV_PATH,sep=";")
RacketsDF = RacketsDF.fillna(RacketsDF.bfill())<jupyter_output><empty_output><jupyter_text>EDA and TS analysis<jupyter_code>RacketsDF.shape
RacketsDF.head()
RacketsDF.dtypes<jupyter_output><empty_output><jupyter_text>We have to transform the DataFrame because we need a DatetimeIndex.<jupyter_code>RacketsDF['DateTime'] = RacketsDF['Month'].apply(lambda x: pd.to_datetime(str(x), format='%d/%m/%Y'))
RacketsDF = RacketsDF.set_index(pd.DatetimeIndex(RacketsDF['DateTime']))
RacketsDF = RacketsDF.drop(['Month','DateTime'], axis=1)
RacketsDF.dtypes
RacketsDF.head()
RacketsDF.plot(figsize=(16, 6))
plt.show()
RacketsDF.describe()
RacketsDF['2018':]
fig, ax1 = plt.subplots(figsize=(15,7))
months = RacketsDF['2018'].index
ax1.set_xlabel('months')
ax1.set_ylabel('Sales')
ax1.plot(months, RacketsDF['2018'], color='navy')
ax1.plot(months, RacketsDF['2017'], color='blue')
ax1.plot(months, RacketsDF['2016'], color='lightblue')
ax1.plot(months, RacketsDF['2015'], color='lime')
plt.grid()

leg_2018 = mpatches.Patch(color='navy', label='2018')
leg_2017 = mpatches.Patch(color='blue', label='2017')
leg_2016 = mpatches.Patch(color='lightblue', label='2016')
leg_2015 = mpatches.Patch(color='lime', label='2015')
plt.legend(handles=[leg_2018,leg_2017,leg_2016,leg_2015])

fig.tight_layout()  # otherwise the right y-label is slightly clipped
plt.title('Deliveries per year', loc='center')

plt.show()
rcParams['figure.figsize'] = 11, 9

RacketsDF_decomp = sm.tsa.seasonal_decompose(RacketsDF, model='additive')
fig = RacketsDF_decomp.plot()
plt.show()<jupyter_output><empty_output><jupyter_text>Dickey-Fuller Test From the plots above plot above it is easy to understand that the TS is not stationary but we also want an analytic test to prove it.<jupyter_code># define Dickey-Fuller Test (DFT) function
import statsmodels.tsa.stattools as ts
def dftest(timeseries):
    dftest = ts.adfuller(timeseries, autolag='AIC')
    dfoutput = pd.Series(dftest[0:4], index=['Test Statistic','p-value','Lags Used','Observations Used'])
    for key,value in dftest[4].items():
        dfoutput['Critical Value (%s)'%key] = value
    print(dfoutput)
    #Determing rolling statistics
    rolmean = timeseries.rolling(12).mean()
    rolstd = timeseries.rolling(12).std()

    #Plot rolling statistics:
    orig = plt.plot(timeseries, color='blue',label='Original')
    mean = plt.plot(rolmean, color='red', label='Rolling Mean')
    std = plt.plot(rolstd, color='black', label = 'Rolling Std')
    plt.legend(loc='best')
    plt.title('Rolling Mean and Standard Deviation')
    plt.show(block=False)
dftest(RacketsDF.Val)<jupyter_output>Test Statistic          -1.622820
p-value                  0.471251
Lags Used               12.000000
Observations Used       74.000000
Critical Value (1%)     -3.521980
Critical Value (5%)     -2.901470
Critical Value (10%)    -2.588072
dtype: float64<jupyter_text>SARIMAX model<jupyter_code># Define the p, d and q parameters to take any value between 0 and 2
p = d = q = range(0, 2)

# Generate all different combinations of p, q and q triplets
pdq = list(itertools.product(p, d, q))

# Generate all different combinations of seasonal p, q and q triplets
seasonal_pdq = [(x[0], x[1], x[2], 12) for x in list(itertools.product(p, d, q))]

warnings.filterwarnings("ignore") # specify to ignore warning messages

listAIC = []
for param in pdq:
    for param_seasonal in seasonal_pdq:
        try:
            mod = sm.tsa.statespace.SARIMAX(RacketsDF,
                                            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))
            listAIC.append(results.aic)
        except:
            continue
listAIC.sort()
print(listAIC[0])
# ARIMA(0, 1, 1)x(0, 1, 1, 12)12
# AIC:329.6331660694662<jupyter_output><empty_output><jupyter_text>Model quality evaluation<jupyter_code>mod = sm.tsa.statespace.SARIMAX(RacketsDF,
                                order=(0, 1, 1),
                                seasonal_order=(0, 1, 1, 12),
                                enforce_stationarity=False,
                                enforce_invertibility=False)

results = mod.fit()
print(results.summary().tables[1])
results.plot_diagnostics(figsize=(15, 12))
plt.show()
pred = results.get_prediction(start=pd.to_datetime('2018-01-01'), dynamic=False)
pred_confidence = pred.conf_int()
pred.predicted_mean
pred_confidence
# plot predictions
ax = RacketsDF['2018-01-01':].plot(label='Number of boxes')
pred.predicted_mean.plot(ax=ax, label='Val (forecast)', alpha=.8)
ax.fill_between(pred_confidence.index, pred_confidence.iloc[:, 0], pred_confidence.iloc[:, 1], color='k', alpha=.1)

ax.set_xlabel('Months')
ax.set_ylabel('Number of boxes')
plt.legend()

plt.show();
RacketsDF_forecasted = pred.predicted_mean
RacketsDF_true = RacketsDF['2018-01-01':]['Val']

mse = ((RacketsDF_forecasted - RacketsDF_true) ** 2).mean()
print('The Mean Squared Error of our forecasts is {}'.format(round(mse, 2)))
RacketsDF_forecasted=RacketsDF_forecasted.round(0)
pd.concat([RacketsDF_true.rename('RacketsDF_true'), RacketsDF_forecasted.rename('RacketsDF_forecasted')], axis=1)<jupyter_output><empty_output><jupyter_text>Predicition of 2019<jupyter_code># Let forcast the following 24 months
pred_uc = results.get_forecast(steps=24)
pred_confidence = pred_uc.conf_int()
ax = RacketsDF.plot(label='observed', figsize=(20, 15))
pred_uc.predicted_mean.plot(ax=ax, label='Forecast')
ax.fill_between(pred_confidence.index,
                pred_confidence.iloc[:, 0],
                pred_confidence.iloc[:, 1], color='k', alpha=.15)
ax.set_xlabel('Months')
ax.set_ylabel('Number of boxes')

plt.legend()
plt.show()
pred_uc.predicted_mean['2019'].round(0)
pred_uc.predicted_mean['2019'].sum().round(0)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13550702961411906, 'fraction_numerical': 0.040382889620101704, 'mean_word_length': 4.472176759410802, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '454910', 'license': 'MIT', 'n_tokens_mistral': 2550, 'n_tokens_neox': 2275, 'n_words': 456, 'path': '01_TimeSeries.ipynb', 'repo_name': 'simboli/Tennis-e-commerce-time-series', 'size': '6686'}