Kaggle competition: Web Traffic Time Series Forecasting
<SOS> metric: SMAPE Kaggle data source: web-traffic-time-series-forecasting<predict_on_test>
np.random.seed(0)
 warnings.filterwarnings('ignore')
%%time
test_preds = model.predict(test_images )<save_to_csv>
train = pd.read_csv('/kaggle/input/web-traffic-time-series-forecasting/train_2.csv.zip' ).fillna(0 )
feature_names = list(idlookup_data['FeatureName'])
 image_ids = list(idlookup_data['ImageId']-1)
 row_ids = list(idlookup_data['RowId'])
 feature_list = []
for feature in feature_names:
feature_list.append(feature_names.index(feature))
predictions = []
for x,y in zip(image_ids, feature_list):
predictions.append(test_preds[x][y])
 row_ids = pd.Series(row_ids, name = 'RowId')
 locations = pd.Series(predictions, name = 'Location')
 locations = locations.clip(0.0,96.0)
 submission_result = pd.concat([row_ids,locations],axis = 1)
 submission_result.to_csv('submission.csv',index = False )<set_options>
def rmsse(train, y, y_hat):
num = np.sum(np.power(( y - y_hat), 2))
den =(1 /(len(train)- 1)) * np.sum(np.power(np.diff(train), 2))
return np.sqrt(( 1 / len(y)) * num / den)
 def smape(y_true, y_pred):
denominator =(np.abs(y_true)+ np.abs(y_pred)) / 200.0
diff = np.abs(y_true - y_pred)/ denominator
diff[denominator == 0] = 0.0
return np.nanmean(diff)
 def rmse(y_true, y_pred):
return np.sqrt(mean_squared_error(y_true, y_pred))
def ts_folds(x, n, h, val_type='exp_wind'):
assert len(x)- 2 * h > n * h, "horisont or number of folds are too large."
assert n > 0 and h > 0
l = len(x)
 folds = []
if val_type == 'exp_wind':
for i in range(n):
folds.append(( x[:l - h*(i + 1)], x[l - h*(i+1):l - h*i]))
return folds
def plot_ts(x_ts, info):
x = x_ts.values
ts_name = 'X'
fig, axes = plt.subplots(3, 2, figsize=(18, 20))
axes[0, 0].set_title(f"Original, id: {info['id']}", fontsize=16)
 axes[0, 0].plot(x, label=ts_name)
 axes[0, 0].set_ylabel('X', fontsize=16)
 axes[0, 0].set_xlabel('t', fontsize=16)
 axes[0, 0].legend()
plot_acf(x, lags=90, ax=axes[0, 1])
 sns.distplot(x, bins=100, kde=True, ax=axes[1, 0])
 axes[1, 0].set_xlabel('X', fontsize=16)
 axes[1, 0].set_title('Histogram', fontsize=16)
 x_ts.diff().plot(ax=axes[1, 1], title='1 step difference')
 axes[2, 0].set_title('Box plot(grouped by months)', fontsize=16)
 sns.boxplot(x_ts.index.month, x_ts, ax=axes[2, 0])
 axes[2, 1].plot(x_ts, label=ts_name)
 x_ts.rolling(window=7 ).mean().plot(ax=axes[2, 1], label='W=7')
 x_ts.rolling(window=30 ).mean().plot(ax=axes[2, 1], label='W=30')
 x_ts.rolling(window=60 ).mean().plot(ax=axes[2, 1], label='W=60')
 axes[2, 1].legend()
axes[2, 1].set_title('Moving average', fontsize=16)
 axes[2, 1].set_ylabel('X', fontsize=16)
 axes[2, 1].set_xlabel('t', fontsize=16)
 plt.show()
res = seasonal_decompose(x_ts, model='additive')
 fig,(ax1, ax2, ax3, ax4)= plt.subplots(4, 1, figsize=(12, 15))
fig.suptitle('additive decomposition')
 res.observed.plot(ax=ax1)
 ax1.set_ylabel('original')
 res.trend.plot(ax=ax2)
 ax2.set_ylabel('trend')
 res.seasonal.plot(ax=ax3)
 ax3.set_ylabel('seasonal')
 res.resid.plot(ax=ax4)
 ax4.set_ylabel('residuals')
 pass
def plot_prediction(train, val, y_hat, plot_len=None, title=None):
if plot_len == None:
plot_len = len(train)+ len(val)
 l = len(train)
 train_range = np.arange(l)
 val_range = np.arange(l, l + len(val))
all_range = np.arange(l + len(val))
fig = plt.figure(figsize=(14, 8))
plt.plot(train_range, train, '.-b', label='train')
 plt.plot(val_range, val, '.-g', label='val')
 plt.plot(val_range, y_hat, '.-r', label='forecast')
 plt.xlim([all_range[-plot_len:][0], all_range[-plot_len:][-1]])
 plt.legend()
plt.vlines(l, -1e6, 1e6, 'k', 'dashed')
 plt.ylim([np.min([np.min(train[-plot_len:]), np.min(val)])-1, np.max([np.max(train[-plot_len:]), np.max(val)])+10])
 plt.title(title)
 plt.show()
class TransformTS() :
def __init__(self, tr_type, handle_missing=None):
self.tr_type = tr_type
self.handle_missing = handle_missing
def transform(self, x):
if self.tr_type == 'ln_p1':
y = np.log(x + 1)
 elif self.tr_type == 'ln':
y = np.log(x)
 elif self.tr_type == 'sqrt':
y = np.sqrt(x)
 elif self.tr_type == 'boxcox':
y, lb = stats.boxcox(x)
 self.lb = lb
else:
raise ValueError
return y
def reverse(self, x):
if self.tr_type == 'ln_p1':
y = np.exp(x)- 1
elif self.tr_type == 'ln':
y = np.exp(x)
 elif self.tr_type == 'sqrt':
y = np.power(x, 2)
 elif self.tr_type == 'boxcox':
y = scipy.special.inv_boxcox(x, self.lb)
 else:
raise ValueError
return y
pd.set_option('max_columns', None)
 plt.style.use('fivethirtyeight')
 %matplotlib inline
py.init_notebook_mode(connected=True)
 warnings.filterwarnings('ignore')
 print("Libraries imported!" )<train_model>
HORIZONT = 64
def prophet_fc(x, h=HORIZONT):
m = Prophet()
m.fit(x)
 future = m.make_future_dataframe(periods=h)
 forecast = m.predict(future)
 y_hat = forecast['yhat'][-h:]
return y_hat
def naive(x, h=HORIZONT):
return np.ones(h)* np.mean(x[-HORIZONT:])
 def naive2(x, h=HORIZONT):
return np.ones(h)* x[-1]
def arima_mdl(x, order, h=HORIZONT):
p, d, q = order
l = len(x)
 mod = sm.tsa.statespace.SARIMAX(x, order=(p, d, q), trend='c' ).fit(disp=False)
 y_hat = mod.forecast(steps=HORIZONT)
 return y_hat
def agg_weekly(x, window=64, h=HORIZONT, avg_type='mean'):
xs = x[-window:]
medians = [xs[xs.index.weekday == i].median() for i in range(7)]
means = [xs[xs.index.weekday == i].mean() for i in range(7)]
d = x.index[-1].weekday()
y_hat = np.zeros(HORIZONT)
 for n in range(HORIZONT):
if d == 6:
d = 0
else:
d = d + 1
if avg_type == 'median':
y_hat[n] = medians[d]
elif avg_type == 'mean':
y_hat[n] = means[d]
else:
raise ValueError
return y_hat
def exp_smoothing(x_train, config, h=HORIZONT):
t,d,s,p,b,r = config
model = ExponentialSmoothing(x_train, trend=t, damped=d, seasonal=s, seasonal_periods=p)
 model_fit = model.fit(optimized=True, use_boxcox=b, remove_bias=r)
 yhat = model_fit.forecast(h)
 return yhat
class BaseModel(object):

 def __init__(self, train_df, test_df, target, features, categoricals=[],
n_splits=3, cv_method="KFold", group=None, task="regression",
parameter_tuning=False, scaler=None, verbose=True):
self.train_df = train_df
self.test_df = test_df
self.target = target
self.features = features
self.n_splits = n_splits
self.categoricals = categoricals
self.cv_method = cv_method
self.group = group
self.task = task
self.parameter_tuning = parameter_tuning
self.scaler = scaler
self.cv = self.get_cv()
self.verbose = verbose
self.params = self.get_params()
self.y_pred, self.score, self.model, self.oof, self.y_val, self.fi_df = self.fit()
def train_model(self, train_set, val_set):
raise NotImplementedError
def get_params(self):
raise NotImplementedError
def convert_dataset(self, x_train, y_train, x_val, y_val):
raise NotImplementedError
def convert_x(self, x):
return x
def calc_metric(self, y_true, y_pred):
if self.task == "classification":
return log_loss(y_true, y_pred)
 elif self.task == "regression":
return np.sqrt(mean_squared_error(y_true, y_pred))
def get_cv(self):
if self.cv_method == "KFold":
cv = KFold(n_splits=self.n_splits, shuffle=True, random_state=42)
 return cv.split(self.train_df)
 elif self.cv_method == "StratifiedKFold":
cv = StratifiedKFold(n_splits=self.n_splits, shuffle=True, random_state=42)
 return cv.split(self.train_df, self.train_df[self.target])
 elif self.cv_method == "TimeSeriesSplit":
cv = TimeSeriesSplit(max_train_size=None, n_splits=self.n_splits)
 return cv.split(self.train_df)
 elif self.cv_method == "GroupKFold":
cv = GroupKFold(n_splits=self.n_splits, shuffle=True, random_state=42)
 return cv.split(self.train_df, self.train_df[self.target], self.group)
 elif self.cv_method == "StratifiedGroupKFold":
cv = StratifiedGroupKFold(n_splits=self.n_splits, shuffle=True, random_state=42)
 return cv.split(self.train_df, self.train_df[self.target], self.group)
 def fit(self):
oof_pred = np.zeros(( self.train_df.shape[0],))
y_vals = np.zeros(( self.train_df.shape[0],))
y_pred = np.zeros(( self.test_df.shape[0],))
if self.group is not None:
if self.group in self.features:
self.features.remove(self.group)
 if self.group in self.categoricals:
self.categoricals.remove(self.group)
 fi = np.zeros(( self.n_splits, len(self.features)))
 if self.scaler is not None:
numerical_features = [f for f in self.features if f not in self.categoricals]
self.train_df[numerical_features] = self.train_df[numerical_features].fillna(self.train_df[numerical_features].median())
 self.test_df[numerical_features] = self.test_df[numerical_features].fillna(self.test_df[numerical_features].median())
 self.train_df[self.categoricals] = self.train_df[self.categoricals].fillna(self.train_df[self.categoricals].mode().iloc[0])
 self.test_df[self.categoricals] = self.test_df[self.categoricals].fillna(self.test_df[self.categoricals].mode().iloc[0])
 if self.scaler == "MinMax":
scaler = MinMaxScaler()
elif self.scaler == "Standard":
scaler = StandardScaler()
df = pd.concat([self.train_df[numerical_features], self.test_df[numerical_features]], ignore_index=True)
 scaler.fit(df[numerical_features])
 x_test = self.test_df.copy()
x_test[numerical_features] = scaler.transform(x_test[numerical_features])
 x_test = [np.absolute(x_test[i])for i in self.categoricals] + [x_test[numerical_features]]
else:
x_test = self.test_df[self.features]
for fold,(train_idx, val_idx)in enumerate(self.cv):
x_train, x_val = self.train_df.loc[train_idx, self.features], self.train_df.loc[val_idx, self.features]
y_train, y_val = self.train_df.loc[train_idx, self.target], self.train_df.loc[val_idx, self.target]
if self.scaler is not None:
x_train[numerical_features] = scaler.transform(x_train[numerical_features])
 x_val[numerical_features] = scaler.transform(x_val[numerical_features])
 x_train = [np.absolute(x_train[i])for i in self.categoricals] + [x_train[numerical_features]]
x_val = [np.absolute(x_val[i])for i in self.categoricals] + [x_val[numerical_features]]
train_set, val_set = self.convert_dataset(x_train, y_train, x_val, y_val)
 model, importance = self.train_model(train_set, val_set)
 fi[fold, :] = importance
conv_x_val = self.convert_x(x_val)
 y_vals[val_idx] = y_val
oof_pred[val_idx] = model.predict(conv_x_val ).reshape(oof_pred[val_idx].shape)
 x_test = self.convert_x(x_test)
 y_pred += model.predict(x_test ).reshape(y_pred.shape)/ self.n_splits
print('Partial score of fold {} is: {}'.format(fold, self.calc_metric(y_val, oof_pred[val_idx])))
 fi_df = pd.DataFrame()
for n in np.arange(self.n_splits):
tmp = pd.DataFrame()
tmp["features"] = self.features
tmp["importance"] = fi[n, :]
tmp["fold"] = n
fi_df = pd.concat([fi_df, tmp], ignore_index=True)
 gfi = fi_df[["features", "importance"]].groupby(["features"] ).mean().reset_index()
fi_df = fi_df.merge(gfi, on="features", how="left", suffixes=('', '_mean'))
loss_score = self.calc_metric(self.train_df[self.target], oof_pred)
 if self.verbose:
print('Our oof loss score is: ', loss_score)
 return y_pred, loss_score, model, oof_pred, y_vals, fi_df
def plot_feature_importance(self, rank_range=[1, 50]):
fig, ax = plt.subplots(1, 1, figsize=(10, 20))
sorted_df = self.fi_df.sort_values(by = "importance_mean", ascending=False ).reset_index().iloc[self.n_splits *(rank_range[0]-1): self.n_splits * rank_range[1]]
sns.barplot(data=sorted_df, x ="importance", y ="features", orient='h')
 ax.set_xlabel("feature importance")
 ax.spines['top'].set_visible(False)
 ax.spines['right'].set_visible(False)
 return sorted_df<train_model>
t_params = ['add', 'mul', None]
d_params = [True, False]
s_params = ['add', 'mul', None]
p_params = [5, 7, 12, 14, 30]
b_params = [True, False]
r_params = [True, False]
cfg_list = []
for t in t_params:
for d in d_params:
for s in s_params:
for p in p_params:
for b in b_params:
for r in r_params:
if d is True and t is None:
continue
cfg = [t, d, s, p, b, r]
cfg_list.append(cfg)
class LgbModel(BaseModel):

 def train_model(self, train_set, val_set):
verbosity = 100 if self.verbose else 0
model = lgb.train(self.params, train_set, num_boost_round = 5000, valid_sets=[train_set, val_set], verbose_eval=verbosity)
 fi = model.feature_importance(importance_type="gain")
 return model, fi
def convert_dataset(self, x_train, y_train, x_val, y_val):
train_set = lgb.Dataset(x_train, y_train, categorical_feature=self.categoricals)
 val_set = lgb.Dataset(x_val, y_val, categorical_feature=self.categoricals)
 return train_set, val_set
def get_params(self):
params = {
'num_leaves': 127,
'min_data_in_leaf': 50,
'max_depth': -1,
'learning_rate': 0.005,
"boosting_type": "gbdt",
"bagging_seed": 11,
"verbosity": -1,
'random_state': 42,
}
if self.task == "regression":
params["objective"] = "regression"
params["metric"] = "rmse"
elif self.task == "classification":
params["objective"] = "binary"
params["metric"] = "binary_logloss"
if self.parameter_tuning == True:
def objective(trial):
train_x, test_x, train_y, test_y = train_test_split(self.train_df[self.features],
self.train_df[self.target],
test_size=0.3, random_state=42)
 dtrain = lgb.Dataset(train_x, train_y, categorical_feature=self.categoricals)
 dtest = lgb.Dataset(test_x, test_y, categorical_feature=self.categoricals)
 hyperparams = {'num_leaves': trial.suggest_int('num_leaves', 24, 1024),
'boosting_type': 'gbdt',
'objective': params["objective"],
'metric': params["metric"],
'max_depth': trial.suggest_int('max_depth', 4, 16),
'min_child_weight': trial.suggest_int('min_child_weight', 1, 20),
'feature_fraction': trial.suggest_uniform('feature_fraction', 0.4, 1.0),
'bagging_fraction': trial.suggest_uniform('bagging_fraction', 0.4, 1.0),
'bagging_freq': trial.suggest_int('bagging_freq', 1, 7),
'min_child_samples': trial.suggest_int('min_child_samples', 5, 100),
'lambda_l1': trial.suggest_loguniform('lambda_l1', 1e-8, 10.0),
'lambda_l2': trial.suggest_loguniform('lambda_l2', 1e-8, 10.0),
'early_stopping_rounds': 100
}
model = lgb.train(hyperparams, dtrain, valid_sets=dtest, verbose_eval=500)
 pred = model.predict(test_x)
 if self.task == "classification":
return log_loss(test_y, pred)
 elif self.task == "regression":
return np.sqrt(mean_squared_error(test_y, pred))
study = optuna.create_study(direction='minimize')
 study.optimize(objective, n_trials=50)
 print('Number of finished trials: {}'.format(len(study.trials)))
 print('Best trial:')
 trial = study.best_trial
print(' Value: {}'.format(trial.value))
print(' Params: ')
 for key, value in trial.params.items() :
print(' {}: {}'.format(key, value))
params = trial.params
params["learning_rate"] = 0.001
plot_optimization_history(study)
 return params<load_from_csv>
def eval_models(train, y_val, m_list):
models = []
if 'naive1' in m_list:
y_hat = naive(train.values, h=HORIZONT)
 y_hat[y_hat < 0] = 0
models.append({
'name': 'naive1',
'y_pred': y_hat,
'smape': smape(y_val, y_hat),
'rmse': np.sqrt(mean_squared_error(y_hat, y_val)) ,
'model': None} 
)
 if 'naive2' in m_list:
y_hat = naive2(train.values, h=HORIZONT)
 y_hat[y_hat < 0] = 0
models.append({
'name': 'naive2',
'y_pred': y_hat,
'smape': smape(y_val, y_hat),
'rmse': np.sqrt(mean_squared_error(y_hat, y_val)) ,
'model': None} 
)
 if 'prophet' in m_list:
x_df = pd.DataFrame({'ds': train.index, 'y': x_train.values})
 y_hat = prophet_fc(x_df, h=HORIZONT)
 y_hat[y_hat < 0] = 0
models.append({
'name': 'prophet',
'y_pred': y_hat,
'smape': smape(y_val, y_hat),
'rmse': np.sqrt(mean_squared_error(y_hat, y_val)) ,
'model': None} 
)
 for p in range(30):
for d in [0, 1]:
for q in range(4):
m_name = f'arima_{p}_{d}_{q}'
if m_name in m_list:
try:
y_hat = arima_mdl(train,(p, d, q), h=HORIZONT)
 conv = True
except:
y_hat = naive(train.values, h=HORIZONT)
 conv = False
y_hat[y_hat < 0] = 0
models.append({
'name': m_name,
'y_pred': y_hat,
'smape': smape(y_val, y_hat),
'rmse': np.sqrt(mean_squared_error(y_hat, y_val)) ,
'model': None,
'conv': conv,
})
 winds = [7, 32, 64, 96]
for w in winds:
if f'weekly_mean_w-{w}' in m_list:
y_hat = agg_weekly(train, window=w, h=HORIZONT, avg_type='mean')
 y_hat[y_hat < 0] = 0
models.append({
'name': f'weekly_mean_w-{w}',
'y_pred': y_hat,
'smape': smape(y_val, y_hat),
'rmse': np.sqrt(mean_squared_error(y_hat, y_val)) ,
'model': None} 
)
 winds = np.arange(1, 13)* 7
for w in winds:
if f'weekly_median_w-{w}' in m_list:
y_hat = agg_weekly(train, window=w, h=HORIZONT, avg_type='median')
 y_hat[y_hat < 0] = 0
models.append({
'name': f'weekly_median_w-{w}',
'y_pred': y_hat,
'smape': smape(y_val, y_hat),
'rmse': np.sqrt(mean_squared_error(y_hat, y_val)) ,
'model': None} 
)
 for cfg in cfg_list:
if f"ets_{cfg}" in m_list:
train = train + 1
y_hat = exp_smoothing(train, cfg, h=HORIZONT)
 if y_hat.isnull().values.any() or np.isinf(y_hat.values ).any() :
y_hat = naive(train.values, h=HORIZONT)
 conv = False
else:
conv = True
y_hat = y_hat - 1
y_hat[y_hat < 0] = 0
models.append({
'name': f'ets_{cfg}',
'y_pred': y_hat,
'smape': smape(y_val, y_hat),
'rmse': np.sqrt(mean_squared_error(y_hat, y_val)) ,
'model': None,
'conv': conv,} 
)
 return models
data_dict = {}
for i in glob.glob('/kaggle/input/google-cloud-ncaa-march-madness-2020-division-1-womens-tournament/WDataFiles_Stage1/*'):
name = i.split('/')[-1].split('.')[0]
if name != 'WTeamSpellings':
data_dict[name] = pd.read_csv(i)
 else:
data_dict[name] = pd.read_csv(i, encoding='cp1252' )<feature_engineering>
N_FOLDS = 1
MAX_EVAL = 2200
power_trans = True
metr_arr = []
pred_arr = []
m_list = [
'naive1',
'prophet',
'weekly_median_w-28',
'weekly_median_w-35',
'weekly_median_w-42',
'weekly_median_w-49',
'weekly_median_w-56',
'weekly_median_w-63',
"ets_['add', True, 'add', 5, True, False]",
"ets_['add', True, 'add', 7, True, False]",
"ets_['add', True, 'add', 12, True, False]",
"ets_['add', True, 'add', 14, True, False]",
'arima_6_1_1',
]
np.random.seed(0)
 idx = np.arange(train.shape[0])
 ind_list = np.random.choice(idx, size=MAX_EVAL, replace=False)
 for k, i in enumerate(ind_list):
if k % 1000 == 0:
print('step:', k)
 x_df = train.iloc[i]
x_ts = pd.Series(x_df.values[1:].astype(float), index=x_df.index[1:])
 x_ts.index = pd.to_datetime(x_ts.index)
 folds = ts_folds(x_ts, n=N_FOLDS, h=HORIZONT)
 for n in range(N_FOLDS):
x_train = folds[n][0]
y_val = folds[n][1].values
if np.sum(x_train[-64:].values)== 0:
print('zeros')
 y_hat = np.zeros(HORIZONT)
 models = []
for name in m_list:
models.append({
'name': name,
'smape': smape(y_val, y_hat),
'y_pred': y_hat,
'rmse': np.sqrt(mean_squared_error(y_hat, y_val))
})
 else:
models = eval_models(x_train, y_val, m_list)
 for m in models:
x = {
'id': i,
'fold_num': n,
'name': m['name'],
'smape': m['smape'],
'rmse': m['rmse']
}
metr_arr.append(x)
 pred_arr.append({
'id': i,
'fold_num': n,
'smape': m['smape'],
'rmse': m['rmse'],
'name': m['name'],
'y_hat': m['y_pred'],
'x_train': x_train,
'y_val': y_val
})
 if k == MAX_EVAL:
break
metr_df = pd.DataFrame(metr_arr)
 pred_df = pd.DataFrame(pred_arr )
data_dict['WNCAATourneySeeds']['Seed'] = data_dict['WNCAATourneySeeds']['Seed'].apply(lambda x: int(x[1:3]))
data_dict[fname].head()<load_from_csv>
for i in metr_df['id'].unique() :
for n in metr_df['fold_num'].unique() :
d = metr_df[(metr_df['id'] == i)&(metr_df['fold_num'] == n)]
metr_df.loc[(metr_df['id'] == i)&(metr_df['fold_num'] == n), 'smape_adj'] = d['smape'] / d[d['name'] == 'naive1']['smape'].values[0]
metr_df.loc[(metr_df['id'] == i)&(metr_df['fold_num'] == n), 'rmse_adj'] = d['rmse'] / d[d['name'] == 'naive1']['rmse'].values[0]
test = pd.read_csv('.. /input/google-cloud-ncaa-march-madness-2020-division-1-womens-tournament/WSampleSubmissionStage1_2020.csv')
 print(test.shape)
 test.head()<feature_engineering>
print(f'Number of series: {MAX_EVAL}')
 agg_df = df.groupby('name' ).mean().drop(['id', 'fold_num'], axis=1)
 display(agg_df )
test = test.drop(['Pred'], axis=1)
 test['Season'] = test['ID'].apply(lambda x: int(x.split('_')[0]))
test['WTeamID'] = test['ID'].apply(lambda x: int(x.split('_')[1]))
test['LTeamID'] = test['ID'].apply(lambda x: int(x.split('_')[2]))
test.head()<merge>
m_name = agg_df['smape'].idxmin()
print('Models name:', m_name)
 smape_cut = 60
fold_num = 0
ids = df[(df['smape'] > smape_cut)&(df['name'] == m_name)&(df['fold_num'] == fold_num)]['id'].unique()
i = ids[0]
for i in ids[:5]:
x = pred_df[(pred_df['id'] == i)&(pred_df['fold_num'] == fold_num)&(pred_df['name'] == m_name)]
smape_val = x['smape'].values[0]
y_hat = x['y_hat'].values[0]
y_val = x['y_val'].values[0]
x_train = x['x_train'].values[0]
plot_prediction(x_train, y_val, y_hat, plot_len=400, title=f"Id: {i}, SMAPE: {smape_val}")
gameCities = pd.merge(data_dict['WGameCities'], data_dict['Cities'], how='left', on=['CityID'])
 cols_to_use = gameCities.columns.difference(train.columns ).tolist() + ["Season", "WTeamID", "LTeamID"]
train = train.merge(gameCities[cols_to_use], how="left", on=["Season", "WTeamID", "LTeamID"])
 train.head()
cols_to_use = data_dict["WSeasons"].columns.difference(train.columns ).tolist() + ["Season"]
train = train.merge(data_dict["WSeasons"][cols_to_use], how="left", on=["Season"])
 train.head()
cols_to_use = data_dict["WTeams"].columns.difference(train.columns ).tolist()
train = train.merge(data_dict["WTeams"][cols_to_use], how="left", left_on=["WTeamID"], right_on=["TeamID"])
 train.drop(['TeamID'], axis=1, inplace=True)
 train = train.merge(data_dict["WTeams"][cols_to_use], how="left", left_on=["LTeamID"], right_on=["TeamID"], suffixes=('_W', '_L'))
train.drop(['TeamID'], axis=1, inplace=True)
 print(train.shape)
 train.head()<merge>
subm = True
if subm:
print('Building the submission...')
 keys = pd.read_csv('/kaggle/input/web-traffic-time-series-forecasting/key_2.csv.zip')
 keys['date'] = keys['Page'].apply(lambda x: x.split("_")[-1])
 keys['name'] = keys['Page'].apply(lambda x: '_'.join(x.split("_")[:-1]))
keys['horisont_day'] = None
sdate = date(2017, 9, 13)
 edate = date(2017, 11, 13)
 delta = edate - sdate
dates_list = [str(sdate + timedelta(days=i)) for i in range(delta.days + 1)]
for n, d in enumerate(dates_list):
keys.loc[keys['date'] == d, 'horisont_day'] = n
m_list = ['weekly_median_w-49']
res = []
print('Predicting...')
 for k, i in enumerate(np.arange(train.shape[0])) :
if k % 10000 == 0:
print('Step:', k)
 x_df = train.iloc[i]
page = x_df['Page']
x_ts = pd.Series(x_df.values[1:].astype(float), index=x_df.index[1:])
 x_ts.index = pd.to_datetime(x_ts.index)
 if np.sum(x_ts[-50:].values)== 0:
y_hat = np.zeros(HORIZONT)
 else:
models = eval_models(x_ts, np.ones(HORIZONT), m_list)
 y_hat = models[0]['y_pred']
y_hat = y_hat[2:]
for m, y in enumerate(y_hat):
res.append({'name': page, 'horisont_day': m, 'Visits': y})
 res_df = pd.DataFrame(res)
 subm = res_df.merge(keys, how='left', on=['name', 'horisont_day'])
 subm['Visits'] = subm['Visits'].map(np.round ).astype(int)
 subm_df = subm[['Id', 'Visits']].sort_values(by='Id')
 subm_df.to_csv('subm.csv', encoding='utf-8', index=False)