{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Naive Forecast\n\nThis is a naive model that I will describe during class.  Its not bad, but could be so much better.  This model does not consider seasonality or make use of the images or natural language processing elements from this dataset.","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport os\n\nPATH_CSV = '/kaggle/input/applications-of-deep-learning-wustlfall-2022/beach_demand_forecast/'\n\ndf_sales_train = pd.read_csv(os.path.join(PATH_CSV,\"sales_train.csv\"))\ndf_items = pd.read_csv(os.path.join(PATH_CSV,\"items.csv\"))\ndf_resturant = pd.read_csv(os.path.join(PATH_CSV,\"resturants.csv\"))\ndf_sales_test = pd.read_csv(os.path.join(PATH_CSV,\"sales_test.csv\"))\n\ndf_sales_train.date = pd.to_datetime(df_sales_train.date, errors='coerce') \ndf_sales_test.date = pd.to_datetime(df_sales_test.date, errors='coerce') ","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-10-29T21:14:59.546664Z","iopub.execute_input":"2022-10-29T21:14:59.547112Z","iopub.status.idle":"2022-10-29T21:14:59.696913Z","shell.execute_reply.started":"2022-10-29T21:14:59.547017Z","shell.execute_reply":"2022-10-29T21:14:59.695508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We begin by creating one long sequence that combines training and test data. The test data occurs just after the training \"in time\".","metadata":{}},{"cell_type":"code","source":"df_sales = pd.concat([df_sales_train,df_sales_test])\ndf_sales.columns = ['date','item_id','price','item_count','submit_id']\ndf_sales.loc[~df_sales.submit_id.isna(),'submit_id'] = df_sales[~df_sales.submit_id.isna()].submit_id.astype(int)","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:14:59.698570Z","iopub.execute_input":"2022-10-29T21:14:59.698894Z","iopub.status.idle":"2022-10-29T21:14:59.716387Z","shell.execute_reply.started":"2022-10-29T21:14:59.698865Z","shell.execute_reply":"2022-10-29T21:14:59.715051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Utility function to create sequences.","metadata":{}},{"cell_type":"code","source":"def series_to_supervised(data, window=1, lag=1, dropnan=True):\n    cols, names = list(), list()\n    # Input sequence (t-n, ... t-1)\n    for i in range(window, 0, -1):\n        cols.append(data.shift(i))\n        names += [('%s(t-%d)' % (col, i)) for col in data.columns]\n    # Current timestep (t=0)\n    cols.append(data)\n    names += [('%s(t)' % (col)) for col in data.columns]\n    # Target timestep (t=lag)\n    cols.append(data.shift(-lag))\n    names += [('%s(t+%d)' % (col, lag)) for col in data.columns]\n    # Put it all together\n    agg = pd.concat(cols, axis=1)\n    agg.columns = names\n    # Drop rows with NaN values\n    if dropnan:\n        agg.dropna(inplace=True)\n    return agg","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:14:59.717561Z","iopub.execute_input":"2022-10-29T21:14:59.717958Z","iopub.status.idle":"2022-10-29T21:14:59.726858Z","shell.execute_reply.started":"2022-10-29T21:14:59.717934Z","shell.execute_reply":"2022-10-29T21:14:59.725609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Join the items and sales tables so that we can look up the store id for each item.","metadata":{}},{"cell_type":"code","source":"df_items2 = df_items[['id','store_id']]\ndf_train = df_sales.merge(df_items2,left_on='item_id',right_on='id')\nprint(len(df_train))\ndf_train = df_train.sort_values('date').groupby(['item_id', 'store_id', 'date'], as_index=False)\ndf_train = df_train.agg({'item_count':['mean'],'submit_id':['mean']})\nprint(len(df_train))\ndf_train.columns = ['item', 'store', 'date', 'sales', 'submit_id']\nassert sum(df_train.sales.isnull() & df_train.submit_id.isnull()) == 0\ndf_train.head()","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:14:59.727926Z","iopub.execute_input":"2022-10-29T21:14:59.728187Z","iopub.status.idle":"2022-10-29T21:14:59.831189Z","shell.execute_reply.started":"2022-10-29T21:14:59.728148Z","shell.execute_reply":"2022-10-29T21:14:59.830349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Determine the time gap between the last day from training set from the last day of the test set, this will be out lag (the amount of day that need to be forecast).","metadata":{}},{"cell_type":"code","source":"lag_size = (df_sales_test['date'].max().date() - df_sales_train['date'].max().date()).days\nprint('Max date from train set: %s' % df_sales_train['date'].max().date())\nprint('Max date from test set: %s' % df_sales_test['date'].max().date())\nprint('Forecast lag size', lag_size)","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:14:59.833383Z","iopub.execute_input":"2022-10-29T21:14:59.834635Z","iopub.status.idle":"2022-10-29T21:14:59.843306Z","shell.execute_reply.started":"2022-10-29T21:14:59.834582Z","shell.execute_reply":"2022-10-29T21:14:59.841935Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Build the sequence data.","metadata":{}},{"cell_type":"code","source":"window = 29\nseries = series_to_supervised(df_train.drop('date', axis=1), window=window, lag=lag_size, dropnan=False)\nseries.head()","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:14:59.845482Z","iopub.execute_input":"2022-10-29T21:14:59.846317Z","iopub.status.idle":"2022-10-29T21:14:59.960509Z","shell.execute_reply.started":"2022-10-29T21:14:59.846275Z","shell.execute_reply":"2022-10-29T21:14:59.958979Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Remove sequences that did not have enough data.","metadata":{}},{"cell_type":"code","source":"# Remove edge cases, where there were not enough values to complete a series\nlast_item = 'item(t-%d)' % window\nlast_store = 'store(t-%d)' % window\nseries = series[(series['store(t)'] == series[last_store])]\nseries = series[(series['item(t)'] == series[last_item])]","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:14:59.962476Z","iopub.execute_input":"2022-10-29T21:14:59.962867Z","iopub.status.idle":"2022-10-29T21:15:00.115708Z","shell.execute_reply.started":"2022-10-29T21:14:59.962834Z","shell.execute_reply":"2022-10-29T21:15:00.114410Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We will just predict using the sales column.","metadata":{}},{"cell_type":"code","source":"def drop_columns(series, columns):\n    columns_to_drop = [('%s(t+%d)' % (col, lag_size)) for col in columns]\n    for i in range(window, 0, -1):\n        columns_to_drop += [('%s(t-%d)' % (col, i)) for col in columns]\n    columns_to_drop += [('%s(t)' % col) for col in columns]\n    series.drop(columns_to_drop, axis=1, inplace=True)\n    ","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:15:00.117211Z","iopub.execute_input":"2022-10-29T21:15:00.117637Z","iopub.status.idle":"2022-10-29T21:15:00.125547Z","shell.execute_reply.started":"2022-10-29T21:15:00.117596Z","shell.execute_reply":"2022-10-29T21:15:00.123870Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Extract the predictors (x sequences) and the label (future prediction)","metadata":{}},{"cell_type":"code","source":"labels_col = 'sales(t+%d)' % lag_size\nsubmit_id_col = 'submit_id(t+%d)' % lag_size\n\nseries_train = series.loc[series[submit_id_col].isna()].copy(deep=True)\nseries_submit = series.loc[~series[submit_id_col].isna()].copy(deep=True)\nseries_submit = series_submit.drop(labels_col, axis=1)","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:15:00.127198Z","iopub.execute_input":"2022-10-29T21:15:00.127608Z","iopub.status.idle":"2022-10-29T21:15:00.201703Z","shell.execute_reply.started":"2022-10-29T21:15:00.127574Z","shell.execute_reply":"2022-10-29T21:15:00.200724Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Drop all columns except sales\ndrop_columns(series_train,['item','store','submit_id'])\ndrop_columns(series_submit,['item','store'])\nseries_train.dropna(inplace=True)\n#series_submit.dropna(inplace=True)\nsubmit_id = series_submit[submit_id_col].astype(int)\ndrop_columns(series_submit,['submit_id'])\n#series_submit.drop(labels_col, axis=1, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:15:00.203254Z","iopub.execute_input":"2022-10-29T21:15:00.203576Z","iopub.status.idle":"2022-10-29T21:15:00.230232Z","shell.execute_reply.started":"2022-10-29T21:15:00.203545Z","shell.execute_reply":"2022-10-29T21:15:00.229322Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\n# Label\nlabels = series_train[labels_col]\nseries_train = series_train.drop(labels_col, axis=1)\n\nX_train, X_valid, Y_train, Y_valid = train_test_split(series_train, labels.values, test_size=0.4, random_state=0)\nprint('Train set shape', X_train.shape)\nprint('Validation set shape', X_valid.shape)\nX_train.head()","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:15:00.231703Z","iopub.execute_input":"2022-10-29T21:15:00.231945Z","iopub.status.idle":"2022-10-29T21:15:00.670959Z","shell.execute_reply.started":"2022-10-29T21:15:00.231921Z","shell.execute_reply":"2022-10-29T21:15:00.670030Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Final preparation for the x and y.","metadata":{}},{"cell_type":"code","source":"X_train_series = X_train.values.reshape((X_train.shape[0], X_train.shape[1], 1))\nX_valid_series = X_valid.values.reshape((X_valid.shape[0], X_valid.shape[1], 1))\nprint('Train set shape', X_train_series.shape)\nprint('Validation set shape', X_valid_series.shape)","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:15:00.672307Z","iopub.execute_input":"2022-10-29T21:15:00.672686Z","iopub.status.idle":"2022-10-29T21:15:00.682325Z","shell.execute_reply.started":"2022-10-29T21:15:00.672658Z","shell.execute_reply":"2022-10-29T21:15:00.679825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Construct the neural network.\n\n","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf \nfrom keras.models import Sequential, Model\nfrom keras.layers.convolutional import Conv1D, MaxPooling1D\nfrom keras.layers import Dense, LSTM, RepeatVector, TimeDistributed, Flatten, Dropout\nimport keras\n\nepochs = 500 \nbatch = 256\nlr = 0.0003\nadam = tf.keras.optimizers.Adam(lr)\n\nmodel_cnn = Sequential()\nmodel_cnn.add(Conv1D(filters=64, kernel_size=8, activation='relu', input_shape=(X_train_series.shape[1], X_train_series.shape[2])))\nmodel_cnn.add(MaxPooling1D(pool_size=2))\nmodel_cnn.add(Flatten())\nmodel_cnn.add(Dense(50, activation='relu'))\nmodel_cnn.add(Dropout(0.2))\nmodel_cnn.add(Dense(1))\nmodel_cnn.compile(loss='mse', optimizer=adam)\nmodel_cnn.summary()","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:15:00.684336Z","iopub.execute_input":"2022-10-29T21:15:00.684794Z","iopub.status.idle":"2022-10-29T21:15:02.390694Z","shell.execute_reply.started":"2022-10-29T21:15:00.684753Z","shell.execute_reply":"2022-10-29T21:15:02.389266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Fit the neural network.","metadata":{}},{"cell_type":"code","source":"from keras.callbacks import EarlyStopping\n\n# Patience of 5 is fast, but you likely want more!!\n\nmonitor = EarlyStopping(monitor='val_loss', min_delta=1e-3, patience=5, \n        verbose=1, mode='auto', restore_best_weights=True)\n\ncnn_history = model_cnn.fit(X_train_series, Y_train, callbacks=[monitor],\n    validation_data=(X_valid_series, Y_valid), epochs=epochs, verbose=2)","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:15:02.394091Z","iopub.execute_input":"2022-10-29T21:15:02.394688Z","iopub.status.idle":"2022-10-29T21:17:37.842426Z","shell.execute_reply.started":"2022-10-29T21:15:02.394656Z","shell.execute_reply":"2022-10-29T21:17:37.841353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Predict and evaluate the validation data.","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import mean_squared_error\nimport numpy as np\n\ncnn_train_pred = model_cnn.predict(X_train_series)\ncnn_valid_pred = model_cnn.predict(X_valid_series)\nprint('Train rmse:', np.sqrt(mean_squared_error(Y_train, cnn_train_pred)))\nprint('Validation rmse:', np.sqrt(mean_squared_error(Y_valid, cnn_valid_pred)))","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:17:37.843812Z","iopub.execute_input":"2022-10-29T21:17:37.844226Z","iopub.status.idle":"2022-10-29T21:18:28.954994Z","shell.execute_reply.started":"2022-10-29T21:17:37.844191Z","shell.execute_reply":"2022-10-29T21:18:28.953585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Plot the training curve.","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nfig = plt.figure()\nplt.plot(cnn_history.history['loss'], label='Train loss')\nplt.plot(cnn_history.history['val_loss'], label='Validation loss')\nfig.legend()\nfig.suptitle('CNN')\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"MSE\")\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:18:28.956557Z","iopub.execute_input":"2022-10-29T21:18:28.956939Z","iopub.status.idle":"2022-10-29T21:18:29.130806Z","shell.execute_reply.started":"2022-10-29T21:18:28.956904Z","shell.execute_reply":"2022-10-29T21:18:29.129889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Build a Submission File","metadata":{}},{"cell_type":"code","source":"submit_x = series_submit.values\nsubmit_x = submit_x.reshape((submit_x.shape[0], submit_x.shape[1], 1))\nsubmit_pred = model_cnn.predict(submit_x)","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:18:29.132077Z","iopub.execute_input":"2022-10-29T21:18:29.132965Z","iopub.status.idle":"2022-10-29T21:18:29.549701Z","shell.execute_reply.started":"2022-10-29T21:18:29.132933Z","shell.execute_reply":"2022-10-29T21:18:29.548253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submit = pd.DataFrame()\ndf_submit['id'] = submit_id.to_list()\ndf_submit['item_count'] = submit_pred","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:18:29.552192Z","iopub.execute_input":"2022-10-29T21:18:29.552619Z","iopub.status.idle":"2022-10-29T21:18:29.567302Z","shell.execute_reply.started":"2022-10-29T21:18:29.552574Z","shell.execute_reply":"2022-10-29T21:18:29.565832Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submit.to_csv('submit.csv',index=False)","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:18:29.569491Z","iopub.execute_input":"2022-10-29T21:18:29.569888Z","iopub.status.idle":"2022-10-29T21:18:29.591306Z","shell.execute_reply.started":"2022-10-29T21:18:29.569820Z","shell.execute_reply":"2022-10-29T21:18:29.590197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Download the Submit File\n\nYou only need to do this if you wish to view it locally. Otherwise, submit through Kaggle.","metadata":{}},{"cell_type":"code","source":"from IPython.display import FileLink\n\nFileLink(r'submit.csv')","metadata":{"execution":{"iopub.status.busy":"2022-10-29T21:18:29.592441Z","iopub.execute_input":"2022-10-29T21:18:29.593437Z","iopub.status.idle":"2022-10-29T21:18:29.600916Z","shell.execute_reply.started":"2022-10-29T21:18:29.593406Z","shell.execute_reply":"2022-10-29T21:18:29.600222Z"},"trusted":true},"execution_count":null,"outputs":[]}]}