text_html_output_1.png
from matplotlib.offsetbox import AnchoredText

from scipy.signal import periodogram

from sklearn.model_selection import train_test_split

import math

import matplotlib.pyplot as plt

import numpy as np

import optuna

import pandas as pd

import seaborn as sns

import xgboost as xgb

def seasonal_plot(X, y, period, freq, ax=None):
    if ax is None:
        _, ax = plt.subplots()
    palette = sns.color_palette("husl", n_colors=X[period].nunique(),)
    ax = sns.lineplot(
        x=freq,
        y=y,
        hue=period,
        data=X,
        ci=False,
        ax=ax,
        palette=palette,
        legend=False,
    )
    ax.set_title(f"Seasonal Plot ({period}/{freq})")
    for line, name in zip(ax.lines, X[period].unique()):
        y_ = line.get_ydata()[-1]
        ax.annotate(
            name,
            xy=(1, y_),
            xytext=(6, 0),
            color=line.get_color(),
            xycoords=ax.get_yaxis_transform(),
            textcoords="offset points",
            size=14,
            va="center",
        )
    return ax

def plot_periodogram(ts, detrend='linear', ax=None):
    from scipy.signal import periodogram
    fs = pd.Timedelta("1Y") / pd.Timedelta("1D")
    freqencies, spectrum = periodogram(
        ts,
        fs=fs,
        detrend=detrend,
        window="boxcar",
        scaling='spectrum',
    )
    if ax is None:
        _, ax = plt.subplots()
    ax.step(freqencies, spectrum, color="purple")
    ax.set_xscale("log")
    ax.set_xticks([1, 2, 4, 6, 12, 26, 52, 104])
    ax.set_xticklabels(
        [
            "Annual (1)",
            "Semiannual (2)",
            "Quarterly (4)",
            "Bimonthly (6)",
            "Monthly (12)",
            "Biweekly (26)",
            "Weekly (52)",
            "Semiweekly (104)",
        ],
        rotation=30,
    )
    ax.ticklabel_format(axis="y", style="sci", scilimits=(0, 0))
    ax.set_ylabel("Variance")
    ax.set_title("Periodogram")
    return ax

def lagplot(x, y=None, lag=1, standardize=False, ax=None, **kwargs):
    from matplotlib.offsetbox import AnchoredText
    x_ = x.shift(lag)
    if standardize:
        x_ = (x_ - x_.mean()) / x_.std()
    if y is not None:
        y_ = (y - y.mean()) / y.std() if standardize else y
    else:
        y_ = x
    corr = y_.corr(x_)
    if ax is None:
        fig, ax = plt.subplots()
    scatter_kws = dict(
        alpha=0.75,
        s=3,
    )
    line_kws = dict(color='C3', )
    ax = sns.regplot(x=x_,
                     y=y_,
                     scatter_kws=scatter_kws,
                     line_kws=line_kws,
                     lowess=True,
                     ax=ax,
                     **kwargs)
    at = AnchoredText(
        f"{corr:.2f}",
        prop=dict(size="large"),
        frameon=True,
        loc="upper left",
    )
    at.patch.set_boxstyle("square, pad=0.0")
    ax.add_artist(at)
    ax.set(title=f"Lag {lag}", xlabel=x_.name, ylabel=y_.name)
    return ax

def plot_lags(x, y=None, lags=6, nrows=1, lagplot_kwargs={}, **kwargs):
    import math
    kwargs.setdefault('nrows', nrows)
    kwargs.setdefault('ncols', math.ceil(lags / nrows))
    kwargs.setdefault('figsize', (kwargs['ncols'] * 2, nrows * 2 + 0.5))
    fig, axs = plt.subplots(sharex=True, sharey=True, squeeze=False, **kwargs)
    for ax, k in zip(fig.get_axes(), range(kwargs['nrows'] * kwargs['ncols'])):
        if k + 1 <= lags:
            ax = lagplot(x, y, lag=k + 1, ax=ax, **lagplot_kwargs)
            ax.set_title(f"Lag {k + 1}", fontdict=dict(fontsize=14))
            ax.set(xlabel="", ylabel="")
        else:
            ax.axis('off')
    plt.setp(axs[-1, :], xlabel=x.name)
    plt.setp(axs[:, 0], ylabel=y.name if y is not None else x.name)
    fig.tight_layout(w_pad=0.1, h_pad=0.1)
    return fig

train_df = pd.read_csv('../input/tabular-playground-series-sep-2022/train.csv', index_col='date', parse_dates=['date']).drop('row_id', axis=1).to_period(freq='D')
test_df = pd.read_csv('../input/tabular-playground-series-sep-2022/test.csv', index_col='date', parse_dates=['date']).drop('row_id', axis=1).to_period(freq='D')
sub_df = pd.read_csv('../input/tabular-playground-series-sep-2022/sample_submission.csv')

train_df_xgb = train_df.copy()
train_df_xgb['num_sold'] = np.array(train_df['num_sold']) - np.array(train_df['num_sold_predicted'])
train_df_xgb['day'] = train_df_xgb.index.dayofweek
train_df_xgb['week'] = train_df_xgb.index.week
train_df_xgb['dayofyear'] = train_df_xgb.index.dayofyear
train_df_xgb['year'] = train_df_xgb.index.year
train_df_xgb['month'] = train_df_xgb.index.month
train_df_xgb['amount_time'] = train_df_xgb['month'] * 100 + train_df_xgb['day']
train_df_xgb['special_days'] = train_df_xgb['amount_time'].isin([101, 1228, 1229, 1230, 1231]).astype(int)
train_df_xgb['month'] = np.cos(0.5236 * train_df_xgb['month'])
test_df['day'] = test_df.index.dayofweek
test_df['week'] = test_df.index.week
test_df['dayofyear'] = test_df.index.dayofyear
test_df['year'] = test_df.index.year
test_df['month'] = test_df.index.month
test_df['amount_time'] = test_df['month'] * 100 + test_df['day']
test_df['special_days'] = test_df['amount_time'].isin([101, 1228, 1229, 1230, 1231]).astype(int)
test_df['month'] = np.cos(0.5236 * test_df['month'])

def xgb_model(train_data, test_data):
    X = train_data.copy()
    target = X.pop('num_sold')
    X_train, X_valid, y_train, y_valid = train_test_split(X, target)
    xgb_train = xgb.DMatrix(X_train, label=y_train)
    xgb_eval = xgb.DMatrix(X_valid, label=y_valid)
    def objective(trial, xgb_train, xgb_eval):
        params = {'tree_method': trial.suggest_categorical('tree_method', ['gpu_hist']), 'objective': trial.suggest_categorical('objective', ['reg:squarederror']), 'eta': trial.suggest_float('eta', 0.001, 0.3, log=True), 'gamma': trial.suggest_float('gamma', 0.001, 1000, log=True), 'max_depth': trial.suggest_int('max_depth', 3, 12), 'grow_policy': trial.suggest_categorical('grow_policy', ['depthwise', 'lossguide']), 'min_child_weight': trial.suggest_float('min_child_weight', 0.001, 1000, log=True), 'lambda': trial.suggest_float('lambda', 0.001, 100, log=True), 'alpha': trial.suggest_float('alpha', 0.001, 100, log=True), 'colsample_bytree': trial.suggest_float('colsample_bytree', 0.9, 1.0, step=0.05), 'colsample_bylevel': trial.suggest_float('colsample_bylevel', 0.8, 1.0, step=0.05), 'colsample_bynode': trial.suggest_float('colsample_bynode', 0.7, 1.0, step=0.05), 'subsample': trial.suggest_float('subsample', 0.5, 1.0, step=0.05), 'eval_metric': trial.suggest_categorical('eval_metric', ['rmse'])}
        num_round = 1000
        evallist = [(xgb_eval, 'eval')]
        model = xgb.train(params, xgb_train, num_round, evallist, early_stopping_rounds=10, verbose_eval=1000)
        return model.best_score
    study = optuna.create_study(direction='minimize', study_name='Xgboost')
    func = lambda trial: objective(trial, xgb_train, xgb_eval)
    study.optimize(func, n_trials=20)
    best_params = study.best_params
    evallist = [(xgb_eval, 'eval')]
    best_model = xgb.train(best_params, xgb_train, 2000, evallist, early_stopping_rounds=100, verbose_eval=2000)
    xgb_test = xgb.DMatrix(test_data)
    test_preds = best_model.predict(xgb_test)
    y_preds = best_model.predict(xgb.DMatrix(X, label=target))
    return (test_preds, y_preds)

test_preds, y_preds = xgb_model(pd.get_dummies(train_df_xgb.drop('num_sold_predicted', axis=1)), pd.get_dummies(test_df.drop('num_sold', axis=1)))
xgb_y_pred = pd.Series(y_preds, index=train_df.index)
xgb_y_fore = pd.Series(test_preds, index=test_df.index)
_, ax = plt.subplots(figsize=(14, 6))
xgb_y_pred.groupby('date').mean().plot(ax=ax, label='Seasonal Learned by model')
xgb_y_fore.groupby('date').mean().plot(ax=ax, label='Seasonal Forecast by model', color='C3')
train_df_xgb.groupby('date').num_sold.mean().plot(ax=ax, label='Actual Seasonal')
_ = ax.legend()