{"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":"# Data Preprocessing","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\n\nPATH_CSV = '/kaggle/input/applications-of-deep-learning-wustlfall-2022/beach_demand_forecast/'\nPATH_CAM = '/kaggle/input/applications-of-deep-learning-wustlfall-2022/beach_demand_forecast/cam/'\n\ndf_sales_train = pd.read_csv(os.path.join(PATH_CSV,\"sales_train.csv\"))\ndf_sales_test = pd.read_csv(os.path.join(PATH_CSV,\"sales_test.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\"))\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-11-29T00:51:15.608635Z","iopub.execute_input":"2022-11-29T00:51:15.608972Z","iopub.status.idle":"2022-11-29T00:51:15.739439Z","shell.execute_reply.started":"2022-11-29T00:51:15.608943Z","shell.execute_reply":"2022-11-29T00:51:15.738464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sales = pd.concat([df_sales_train, df_sales_test])\ndf_sales.columns = ['date','item_id','price','sales','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-11-29T00:51:15.740989Z","iopub.execute_input":"2022-11-29T00:51:15.741267Z","iopub.status.idle":"2022-11-29T00:51:15.753069Z","shell.execute_reply.started":"2022-11-29T00:51:15.741240Z","shell.execute_reply":"2022-11-29T00:51:15.752371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sales","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:15.754009Z","iopub.execute_input":"2022-11-29T00:51:15.754347Z","iopub.status.idle":"2022-11-29T00:51:15.769790Z","shell.execute_reply.started":"2022-11-29T00:51:15.754320Z","shell.execute_reply":"2022-11-29T00:51:15.768862Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Deseason and Detrend","metadata":{}},{"cell_type":"markdown","source":"Begin by producing a line graph of all sales over the provided 3-year timespan.","metadata":{}},{"cell_type":"code","source":"import plotly.express as px\n\ndf_plot = df_sales_train[['date','item_count']].groupby(['date']).mean().reset_index()\nfig = px.line(df_plot, x=\"date\", y=\"item_count\", title='RAW Sales by Date')\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:15.770758Z","iopub.execute_input":"2022-11-29T00:51:15.771043Z","iopub.status.idle":"2022-11-29T00:51:15.851038Z","shell.execute_reply.started":"2022-11-29T00:51:15.770998Z","shell.execute_reply":"2022-11-29T00:51:15.850056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Detrending\n\nCan you see an overall trend in this data? Beyond just the seasonality?","metadata":{}},{"cell_type":"code","source":"from scipy import signal\n\ndf_plot.item_count = signal.detrend(df_plot.item_count)\n\nfig = px.line(df_plot, x=\"date\", y=\"item_count\", title='RAW Sales by Date')\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:15.854245Z","iopub.execute_input":"2022-11-29T00:51:15.854539Z","iopub.status.idle":"2022-11-29T00:51:15.925590Z","shell.execute_reply.started":"2022-11-29T00:51:15.854495Z","shell.execute_reply":"2022-11-29T00:51:15.924694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## De-Seasoning\n\nLets remove the seasonality.","metadata":{}},{"cell_type":"code","source":"from statsmodels.tsa.seasonal import seasonal_decompose\nfrom matplotlib import pyplot\n\ndf_plot = df_sales_train[['date','item_count']].groupby(['date']).mean()\n\nadjustment = seasonal_decompose(df_plot.item_count, model='multiplicative', period=7) \n\nadjustment.plot()\npyplot.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:15.926829Z","iopub.execute_input":"2022-11-29T00:51:15.927135Z","iopub.status.idle":"2022-11-29T00:51:16.563140Z","shell.execute_reply.started":"2022-11-29T00:51:15.927109Z","shell.execute_reply":"2022-11-29T00:51:16.562438Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Notice how the yearly seasonality was detected as the trend? The weekly seasonality was detected as seasonal. Without zooming you cannot see the ups and downs of the individual days of the week.","metadata":{}},{"cell_type":"code","source":"adjustment.trend","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:16.564109Z","iopub.execute_input":"2022-11-29T00:51:16.564835Z","iopub.status.idle":"2022-11-29T00:51:16.571825Z","shell.execute_reply.started":"2022-11-29T00:51:16.564805Z","shell.execute_reply":"2022-11-29T00:51:16.571066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"adjustment.seasonal","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:16.572943Z","iopub.execute_input":"2022-11-29T00:51:16.573835Z","iopub.status.idle":"2022-11-29T00:51:16.585647Z","shell.execute_reply.started":"2022-11-29T00:51:16.573807Z","shell.execute_reply":"2022-11-29T00:51:16.584590Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = px.line(adjustment.trend)\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:16.586857Z","iopub.execute_input":"2022-11-29T00:51:16.587416Z","iopub.status.idle":"2022-11-29T00:51:16.657662Z","shell.execute_reply.started":"2022-11-29T00:51:16.587381Z","shell.execute_reply":"2022-11-29T00:51:16.656897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"adjustment2 = seasonal_decompose(adjustment.trend.dropna(), model='multiplicative', period=365) \n\nadjustment2.plot()\npyplot.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:16.658764Z","iopub.execute_input":"2022-11-29T00:51:16.659257Z","iopub.status.idle":"2022-11-29T00:51:17.265256Z","shell.execute_reply.started":"2022-11-29T00:51:16.659225Z","shell.execute_reply":"2022-11-29T00:51:17.264402Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = px.line(adjustment2.seasonal)\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.266248Z","iopub.execute_input":"2022-11-29T00:51:17.266509Z","iopub.status.idle":"2022-11-29T00:51:17.335268Z","shell.execute_reply.started":"2022-11-29T00:51:17.266484Z","shell.execute_reply":"2022-11-29T00:51:17.334455Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = px.line(adjustment2.trend)\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.336408Z","iopub.execute_input":"2022-11-29T00:51:17.336785Z","iopub.status.idle":"2022-11-29T00:51:17.403244Z","shell.execute_reply.started":"2022-11-29T00:51:17.336748Z","shell.execute_reply":"2022-11-29T00:51:17.402680Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.linear_model import LinearRegression\n\nX = np.arange(len(adjustment2.trend.dropna())).reshape(-1, 1)\ny = adjustment2.trend.dropna().values\n\nreg = LinearRegression().fit(X, y)\nreg.score(X, y)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.404155Z","iopub.execute_input":"2022-11-29T00:51:17.404521Z","iopub.status.idle":"2022-11-29T00:51:17.412131Z","shell.execute_reply.started":"2022-11-29T00:51:17.404497Z","shell.execute_reply":"2022-11-29T00:51:17.411299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"reg.coef_, reg.intercept_","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.416218Z","iopub.execute_input":"2022-11-29T00:51:17.416465Z","iopub.status.idle":"2022-11-29T00:51:17.426777Z","shell.execute_reply.started":"2022-11-29T00:51:17.416430Z","shell.execute_reply":"2022-11-29T00:51:17.425976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Resulting Dataset\nLets see the dataset \"flattened\".","metadata":{}},{"cell_type":"code","source":"df_plot2 = df_plot.copy()\n\ndf_plot2.item_count = df_plot2.item_count / adjustment.seasonal / adjustment2.seasonal / adjustment2.trend\n\nfig = px.line(df_plot2.reset_index(), x=\"date\", y=\"item_count\", title='RAW Sales by Date')\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.427813Z","iopub.execute_input":"2022-11-29T00:51:17.428239Z","iopub.status.idle":"2022-11-29T00:51:17.498865Z","shell.execute_reply.started":"2022-11-29T00:51:17.428212Z","shell.execute_reply":"2022-11-29T00:51:17.497977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_adjustment = pd.DataFrame()\ndf_adjustment['seasonal_week'] = adjustment.seasonal\ndf_adjustment['seasonal_year'] = adjustment2.seasonal\ndf_adjustment['trend'] = adjustment2.trend\n\ndf_adjustment","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.499908Z","iopub.execute_input":"2022-11-29T00:51:17.500166Z","iopub.status.idle":"2022-11-29T00:51:17.520828Z","shell.execute_reply.started":"2022-11-29T00:51:17.500143Z","shell.execute_reply":"2022-11-29T00:51:17.519989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i in range(3):\n    df_adjustment.iloc[i, 1] = df_adjustment.iloc[i+365, 1]\n    df_adjustment.iloc[-1-i, 1] = df_adjustment.iloc[-1-i-365, 1]\n\ndf_adjustment[df_adjustment['seasonal_year'].isna()]","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.521973Z","iopub.execute_input":"2022-11-29T00:51:17.522370Z","iopub.status.idle":"2022-11-29T00:51:17.535380Z","shell.execute_reply.started":"2022-11-29T00:51:17.522336Z","shell.execute_reply":"2022-11-29T00:51:17.534589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_adjustment['X'] = np.arange(-185, -185+df_adjustment.shape[0])","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.536492Z","iopub.execute_input":"2022-11-29T00:51:17.537243Z","iopub.status.idle":"2022-11-29T00:51:17.543584Z","shell.execute_reply.started":"2022-11-29T00:51:17.537204Z","shell.execute_reply":"2022-11-29T00:51:17.542588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_adjustment['trend_pred'] = reg.predict(df_adjustment['X'].values.reshape(-1, 1))","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.545101Z","iopub.execute_input":"2022-11-29T00:51:17.545471Z","iopub.status.idle":"2022-11-29T00:51:17.555033Z","shell.execute_reply.started":"2022-11-29T00:51:17.545439Z","shell.execute_reply":"2022-11-29T00:51:17.554177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_adjustment[df_adjustment['trend'].isna()]\n#df_adjustment[~df_adjustment['trend'].isna()]","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.556271Z","iopub.execute_input":"2022-11-29T00:51:17.556519Z","iopub.status.idle":"2022-11-29T00:51:17.574910Z","shell.execute_reply.started":"2022-11-29T00:51:17.556495Z","shell.execute_reply":"2022-11-29T00:51:17.574043Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_adjustment_forecast = pd.DataFrame(index=pd.date_range('2021-10-01','2021-12-31',freq='D'), )\n\ndf_adjustment_forecast['seasonal_week'] = df_adjustment.iloc[-7:,0].to_list()*13 + df_adjustment.iloc[-7:-6,0].to_list()\ndf_adjustment_forecast['seasonal_year'] = df_adjustment.iloc[-365:-365+92,1].to_list()\ndf_adjustment_forecast['trend'] = np.nan\ndf_adjustment_forecast['X'] = np.arange(819, 819+df_adjustment_forecast.shape[0])\ndf_adjustment_forecast['trend_pred'] = reg.predict(df_adjustment_forecast['X'].values.reshape(-1, 1))\n\ndf_adjustment_forecast","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.575954Z","iopub.execute_input":"2022-11-29T00:51:17.576201Z","iopub.status.idle":"2022-11-29T00:51:17.599491Z","shell.execute_reply.started":"2022-11-29T00:51:17.576177Z","shell.execute_reply":"2022-11-29T00:51:17.598571Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_adjustment = pd.concat([df_adjustment, df_adjustment_forecast])","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.600758Z","iopub.execute_input":"2022-11-29T00:51:17.601151Z","iopub.status.idle":"2022-11-29T00:51:17.608704Z","shell.execute_reply.started":"2022-11-29T00:51:17.601122Z","shell.execute_reply":"2022-11-29T00:51:17.607910Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We will save the adjustment table to a binary pickle form, so we can later reload it exactly as it is. We will make use of this table during day 2.","metadata":{}},{"cell_type":"code","source":"df_sales_adj = df_sales.merge(df_adjustment[['seasonal_week', 'seasonal_year', 'trend_pred']],right_index=True,left_on='date')\ndf_sales_adj['adjust'] = df_sales_adj.sales / df_sales_adj.seasonal_week / df_sales_adj.seasonal_year / df_sales_adj.trend_pred\n\ndf_sales_adj","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.610205Z","iopub.execute_input":"2022-11-29T00:51:17.611009Z","iopub.status.idle":"2022-11-29T00:51:17.645607Z","shell.execute_reply.started":"2022-11-29T00:51:17.610981Z","shell.execute_reply":"2022-11-29T00:51:17.644738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Extract Data from Street Images with YOLO","metadata":{}},{"cell_type":"code","source":"import sys\n\n!git clone https://github.com/ultralytics/yolov5 --tag 6.2  # clone\n!mv /kaggle/working/6.2 /kaggle/working/yolov5\n%pip install -qr /kaggle/working/yolov5/requirements.txt  # install\nsys.path.insert(0,'/kaggle/working/yolov5/')\n\nimport torch\nimport utils\ndisplay = utils.notebook_init()  # checks","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:17.646821Z","iopub.execute_input":"2022-11-29T00:51:17.647081Z","iopub.status.idle":"2022-11-29T00:51:34.935414Z","shell.execute_reply.started":"2022-11-29T00:51:17.647056Z","shell.execute_reply":"2022-11-29T00:51:34.934219Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from os import walk\nimport datetime\nimport tqdm\n\n# Model\nyolo_model = torch.hub.load('ultralytics/yolov5', 'yolov5s')  # or yolov5n - yolov5x6, custom\n\nfilenames = next(walk(PATH_CAM), (None, None, []))[2]  \n\nlist_date = []\nlist_people_street = []\nlist_people_beach = []\nx_cutoff = 800\n\nfor file in tqdm.tqdm(filenames):\n    if file=='1.jpg': continue\n    filename = os.path.join(PATH_CAM, file)\n    results = yolo_model(filename)\n    df = results.pandas().xyxy[0]\n    people_street = len(df[(df.name=='person') & (df.xmin<x_cutoff)]) \n    people_beach = len(df[(df.name=='person') & (df.xmin>=x_cutoff)])\n    dt = datetime.datetime.strptime(file[:10], '%Y_%m_%d')\n    list_date.append(dt)\n    list_people_street.append(people_street)\n    list_people_beach.append(people_beach)\n\ndf_street_view = pd.DataFrame({'date':list_date,'people_street':list_people_street, 'people_beach':list_people_beach})\ndf_street_view","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:34.937342Z","iopub.execute_input":"2022-11-29T00:51:34.938071Z","iopub.status.idle":"2022-11-29T00:51:51.429722Z","shell.execute_reply.started":"2022-11-29T00:51:34.938036Z","shell.execute_reply":"2022-11-29T00:51:51.425830Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Engineer Time Series Features","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\n\ndef drop_columns(df, columns):\n    columns_to_drop = [('%s(t+%d)' % (col, future_span)) 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    df.drop(columns_to_drop, axis=1, inplace=True, errors='ignore')","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.431238Z","iopub.status.idle":"2022-11-29T00:51:51.432109Z","shell.execute_reply.started":"2022-11-29T00:51:51.431840Z","shell.execute_reply":"2022-11-29T00:51:51.431867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We will link the season and trend adjustments.","metadata":{}},{"cell_type":"code","source":"df_items2 = df_items[['id','store_id']]\ndf_train = df_sales_adj.merge(df_items2,left_on='item_id',right_on='id')\n\ndf_train","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.433555Z","iopub.status.idle":"2022-11-29T00:51:51.434447Z","shell.execute_reply.started":"2022-11-29T00:51:51.434163Z","shell.execute_reply":"2022-11-29T00:51:51.434189Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Merge people counts \ntemp = len(df_train)\ndf_train = df_train.merge(df_street_view)\nassert len(df_train) == temp\n\ndf_train","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.436074Z","iopub.status.idle":"2022-11-29T00:51:51.436827Z","shell.execute_reply.started":"2022-11-29T00:51:51.436546Z","shell.execute_reply":"2022-11-29T00:51:51.436573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Sort/agg\ndf_train = df_train.sort_values('date').groupby(['item_id', 'store_id', 'date'], as_index=False)\ndf_train = df_train.agg({'adjust':['mean'],'sales':['mean'],'seasonal_week':['mean'],'seasonal_year':['mean'],'trend_pred':['mean'],'people_street':['mean'],'people_beach':['mean'],'submit_id':['mean']})\ndf_train.columns = ['item', 'store', 'date', 'adjust', 'sales', 'seasonal_week', 'seasonal_year', 'trend', 'people_street', 'people_beach', 'submit_id']\ndf_train.head()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.438284Z","iopub.status.idle":"2022-11-29T00:51:51.438929Z","shell.execute_reply.started":"2022-11-29T00:51:51.438644Z","shell.execute_reply":"2022-11-29T00:51:51.438671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Lets also engineer two features. This gives the neural network some information about what day of the week and day of the year we are in. Ideally, these are not needed with seasonality generally removed; however, if some seasonality and trend remain, maybe these two features help the neural network to overcome.","metadata":{}},{"cell_type":"code","source":"df_train['dow'] = df_train['date'].dt.dayofweek\ndf_train['doy'] = df_train['date'].dt.dayofyear\n\ndf_train","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.440653Z","iopub.status.idle":"2022-11-29T00:51:51.441383Z","shell.execute_reply.started":"2022-11-29T00:51:51.441192Z","shell.execute_reply":"2022-11-29T00:51:51.441212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Build the sequence data.","metadata":{}},{"cell_type":"code","source":"future_span = (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', future_span)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.442447Z","iopub.status.idle":"2022-11-29T00:51:51.443114Z","shell.execute_reply.started":"2022-11-29T00:51:51.442808Z","shell.execute_reply":"2022-11-29T00:51:51.442837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Remove sequences that did not have enough data.","metadata":{}},{"cell_type":"code","source":"window = 29\nseries = series_to_supervised(df_train.drop('date', axis=1), window=window, lag=future_span, dropnan=False)\n\n# 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\n# last_dow = 'dow(t-%d)' % window\n# last_doy = 'doy(t-%d)' % window\n\nseries = series[(series['store(t+%d)' % future_span] == series[last_store])]\nseries = series[(series['item(t+%d)' % future_span] == series[last_item])]\n\nseries","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.444322Z","iopub.status.idle":"2022-11-29T00:51:51.444835Z","shell.execute_reply.started":"2022-11-29T00:51:51.444577Z","shell.execute_reply":"2022-11-29T00:51:51.444602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We will predict with adjusted sales, and our engineered features.","metadata":{}},{"cell_type":"code","source":"labels_col = 'adjust(t+%d)' % future_span\nsubmit_id_col = 'submit_id(t+%d)' % future_span\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)\n\nprint(series_train.shape, series_submit.shape)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.445837Z","iopub.status.idle":"2022-11-29T00:51:51.446321Z","shell.execute_reply.started":"2022-11-29T00:51:51.446066Z","shell.execute_reply":"2022-11-29T00:51:51.446091Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Label\nlabels = series_train[labels_col]\nseries_train.drop(labels_col, axis=1, inplace=True)\nseries_train.drop('item(t+%d)' % future_span, axis=1, inplace=True)\nseries_train.drop('store(t+%d)' % future_span, axis=1, inplace=True)\nseries_train.drop('dow(t+%d)' % future_span, axis=1, inplace=True)\nseries_train.drop('doy(t+%d)' % future_span, axis=1, inplace=True)\nseries_train.drop('people_street(t+%d)' % future_span, axis=1, inplace=True)\nseries_train.drop('people_beach(t+%d)' % future_span, axis=1, inplace=True)\nseries_train.drop('submit_id(t+%d)' % future_span, axis=1, inplace=True)\n\n# store the seasonal and trend\nunadjust_sales_col = 'sales(t+%d)' % future_span\nseasonal_week_col = 'seasonal_week(t+%d)' % future_span\nseasonal_year_col = 'seasonal_year(t+%d)' % future_span\ntrend_col = 'trend(t+%d)' % future_span\n\nhold_sales = series_train[unadjust_sales_col]\nhold_seasonal_week = series_train[seasonal_week_col]\nhold_seasonal_year = series_train[seasonal_year_col]\nhold_trend = series_train[trend_col]\n\nseries_train.drop(unadjust_sales_col, axis=1, inplace=True)\nseries_train.drop(seasonal_week_col, axis=1, inplace=True)\nseries_train.drop(seasonal_year_col, axis=1, inplace=True)\nseries_train.drop(trend_col, axis=1, inplace=True)\n\nseries_train","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.448221Z","iopub.status.idle":"2022-11-29T00:51:51.448741Z","shell.execute_reply.started":"2022-11-29T00:51:51.448453Z","shell.execute_reply":"2022-11-29T00:51:51.448479Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get adjust sales sequences\nseries2 = series_train.copy()\ndrop_columns(series2, ['item','store','dow', 'doy', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend', 'people_street', 'people_beach'])\nsales_series = series2.values\n\n# Day of week as a number\nseries2 = series_train.copy()\ndrop_columns(series2, ['item','store','adjust', 'doy', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend', 'people_street', 'people_beach'])\ndow_series = series2.values\n\n# Get day of year sequences\nseries2 = series_train.copy()\ndrop_columns(series2, ['item','store','dow', 'adjust', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend', 'people_street', 'people_beach'])\ndoy_series = series2.values\n\n# Get number of people sequences\nseries2 = series_train.copy()\ndrop_columns(series2, ['item','store','dow', 'doy', 'adjust', 'people_beach', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend'])\npeople_street_series = series2.values\n\nseries2 = series_train.copy()\ndrop_columns(series2, ['item','store','dow', 'doy', 'adjust', 'people_street', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend'])\npeople_beach_series = series2.values\n\n# Create x\nt1 = sales_series.reshape(sales_series.shape + (1,))\nt2 = dow_series.reshape(dow_series.shape + (1,)) \nt3 = doy_series.reshape(doy_series.shape + (1,))\nt4 = people_street_series.reshape(people_street_series.shape + (1,))\nt5 = people_beach_series.reshape(people_beach_series.shape + (1,))\nx1 = np.concatenate([t1,t2,t3,t4,t5],axis=2)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.450102Z","iopub.status.idle":"2022-11-29T00:51:51.450612Z","shell.execute_reply.started":"2022-11-29T00:51:51.450330Z","shell.execute_reply":"2022-11-29T00:51:51.450354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Double check that all input data is of the same shape.","metadata":{}},{"cell_type":"code","source":"print(t1.shape)\nprint(t2.shape)\nprint(t3.shape)\nprint(t4.shape)\nprint(t5.shape)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.451949Z","iopub.status.idle":"2022-11-29T00:51:51.452429Z","shell.execute_reply.started":"2022-11-29T00:51:51.452177Z","shell.execute_reply":"2022-11-29T00:51:51.452200Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Vectorize Item Names with Glove Embeddings","metadata":{}},{"cell_type":"code","source":"!wget -c \"https://nlp.stanford.edu/data/glove.6B.zip\"\n!unzip glove.6B.zip\n\nfrom gensim.test.utils import datapath, get_tmpfile\nfrom gensim.models import KeyedVectors\nfrom gensim.scripts.glove2word2vec import glove2word2vec\n\nglove_file = 'glove.6B.300d.txt'\ntmp_file = get_tmpfile(\"test_word2vec.txt\")\n_ = glove2word2vec(glove_file, tmp_file)\nw2vec_model = KeyedVectors.load_word2vec_format(tmp_file)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.453862Z","iopub.status.idle":"2022-11-29T00:51:51.454344Z","shell.execute_reply.started":"2022-11-29T00:51:51.454088Z","shell.execute_reply":"2022-11-29T00:51:51.454111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def process_title(model, name):\n    v = None\n    i = 0\n    for word in name.split(' '):\n        word = word.lower()\n        if word == 'vegi': \n            word = \"vegetable\"\n        if word == 'smoothy': \n            word = \"malt\"\n        i+=1\n        if v is None and word in model:\n            v=model[word].copy()\n        elif word in model:\n            v+=model[word]\n    v/=i\n    return v","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.455594Z","iopub.status.idle":"2022-11-29T00:51:51.456081Z","shell.execute_reply.started":"2022-11-29T00:51:51.455824Z","shell.execute_reply":"2022-11-29T00:51:51.455849Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"item_lookup = {}\nfor i, name in zip(list(df_items.id),list(df_items.name)):\n    v = process_title(w2vec_model,name)\n    item_lookup[i] = v","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.457465Z","iopub.status.idle":"2022-11-29T00:51:51.459202Z","shell.execute_reply.started":"2022-11-29T00:51:51.458921Z","shell.execute_reply":"2022-11-29T00:51:51.458948Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create predictors (x)\nvec_size = w2vec_model['test'].shape[0]\n\nlst = []\nfor item in list(series_train['item(t-1)']):\n    lst.append(item_lookup[item])\n\nx2 = np.concatenate(lst).reshape((series_train.shape[0],vec_size))\n\nx = [x1,x2]","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.460620Z","iopub.status.idle":"2022-11-29T00:51:51.461232Z","shell.execute_reply.started":"2022-11-29T00:51:51.460960Z","shell.execute_reply":"2022-11-29T00:51:51.460985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(x1.shape, x2.shape)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.462543Z","iopub.status.idle":"2022-11-29T00:51:51.463026Z","shell.execute_reply.started":"2022-11-29T00:51:51.462773Z","shell.execute_reply":"2022-11-29T00:51:51.462796Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train the Network","metadata":{}},{"cell_type":"markdown","source":"Extract the predictors (x sequences) and the label (future prediction)","metadata":{}},{"cell_type":"code","source":"TEST_SIZE = 0.4\n\nmask = np.random.random(size=x[0].shape[0]) < TEST_SIZE\n\nX_train = []\nX_valid = []\n\nfor subx in x:\n    X_train.append(subx[~mask])\n    X_valid.append(subx[mask])\n\nY_train = labels.values[~mask]\nY_valid = labels.values[mask]\n\nprint('Train set shape x1:', X_train[0].shape)\nprint('Train set shape x2:', X_train[1].shape)\nprint('Validation set shape x1:', X_valid[0].shape)\nprint('Validation set shape x2:', X_valid[1].shape)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.464601Z","iopub.status.idle":"2022-11-29T00:51:51.465084Z","shell.execute_reply.started":"2022-11-29T00:51:51.464831Z","shell.execute_reply":"2022-11-29T00:51:51.464855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Y_train_seasonal_week = hold_seasonal_week.values[~mask]\nY_valid_seasnoal_week = hold_seasonal_week.values[mask]\n\nY_train_seasonal_year = hold_seasonal_year.values[~mask]\nY_valid_seasnoal_year = hold_seasonal_year.values[mask]\n\nY_train_trend = hold_trend.values[~mask]\nY_valid_trend = hold_trend.values[mask]","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.466059Z","iopub.status.idle":"2022-11-29T00:51:51.466567Z","shell.execute_reply.started":"2022-11-29T00:51:51.466284Z","shell.execute_reply":"2022-11-29T00:51:51.466306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Construct the neural network.","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, concatenate, Input\nimport keras\n\nepochs = 500\nbatch = 256\nlr = 0.0003\nadam = tf.keras.optimizers.Adam(lr)\n\nmodel = Sequential()\n\nA1 = Input(shape=(X_train[0].shape[1], X_train[0].shape[2]),name='A1')\nA2 = Conv1D(filters=64, kernel_size=8, activation='relu')(A1)\nA3 = MaxPooling1D(pool_size=2)(A2)\nA4 = Flatten()(A3)\nA5 = Dense(50, activation='relu')(A4)\nA6 = Dropout(0.2)(A5)\n\nB1 = Input(shape=X_train[1].shape[1],name='B1')\nB2 = Dense(16, activation='relu',name='B2')(B1)\n\nM1 = concatenate([A6,B2])\nM2 = Dense(1,name='M2')(M1)\n\nmodel = Model(inputs=[A1, B1],outputs=[M2])\nmodel.compile(loss='mse', optimizer=adam)\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.468035Z","iopub.status.idle":"2022-11-29T00:51:51.468544Z","shell.execute_reply.started":"2022-11-29T00:51:51.468266Z","shell.execute_reply":"2022-11-29T00:51:51.468289Z"},"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\nmonitor = EarlyStopping(monitor='val_loss', min_delta=1e-3, patience=10, \n        verbose=1, mode='auto', restore_best_weights=True)\n\ncnn_history = model.fit(X_train, Y_train, callbacks=[monitor],\n    validation_data=(X_valid, Y_valid), epochs=epochs, verbose=2)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.470863Z","iopub.status.idle":"2022-11-29T00:51:51.471595Z","shell.execute_reply.started":"2022-11-29T00:51:51.471292Z","shell.execute_reply":"2022-11-29T00:51:51.471318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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-11-29T00:51:51.472959Z","iopub.status.idle":"2022-11-29T00:51:51.473779Z","shell.execute_reply.started":"2022-11-29T00:51:51.473477Z","shell.execute_reply":"2022-11-29T00:51:51.473501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import mean_squared_error \n\ncnn_train_pred = model.predict(X_train) \ncnn_valid_pred = model.predict(X_valid) \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-11-29T00:51:51.475344Z","iopub.status.idle":"2022-11-29T00:51:51.476351Z","shell.execute_reply.started":"2022-11-29T00:51:51.476080Z","shell.execute_reply":"2022-11-29T00:51:51.476106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Y_train_actual = hold_sales.values[~mask]\nY_valid_actual = hold_sales.values[mask]\n\ncnn_train_pred2 = cnn_train_pred.flatten() * Y_train_seasonal_week * Y_train_seasonal_year * Y_train_trend\ncnn_valid_pred2 = cnn_valid_pred.flatten() * Y_valid_seasnoal_week * Y_valid_seasnoal_year * Y_valid_trend\n\nprint('Train rmse:', np.sqrt(mean_squared_error(Y_train_actual, cnn_train_pred2)))\nprint('Validation rmse:', np.sqrt(mean_squared_error(Y_valid_actual, cnn_valid_pred2)))","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.477396Z","iopub.status.idle":"2022-11-29T00:51:51.477761Z","shell.execute_reply.started":"2022-11-29T00:51:51.477570Z","shell.execute_reply":"2022-11-29T00:51:51.477588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build a Submission File","metadata":{}},{"cell_type":"code","source":"submit_id = series_submit[submit_id_col].astype(int)\n\nseries_submit.drop(labels_col, axis=1, inplace=True)\nseries_submit.drop('item(t+%d)' % future_span, axis=1, inplace=True)\nseries_submit.drop('store(t+%d)' % future_span, axis=1, inplace=True)\nseries_submit.drop('dow(t+%d)' % future_span, axis=1, inplace=True)\nseries_submit.drop('doy(t+%d)' % future_span, axis=1, inplace=True)\nseries_submit.drop('people_street(t+%d)' % future_span, axis=1, inplace=True)\nseries_submit.drop('people_beach(t+%d)' % future_span, axis=1, inplace=True)\nseries_submit.drop('submit_id(t+%d)' % future_span, axis=1, inplace=True)\n\n# store the seasonal and trend\n#hold_sales_submit = series_submit[unadjust_sales_col]\nhold_seasonal_week_submit = series_submit[seasonal_week_col]\nhold_seasonal_year_submit = series_submit[seasonal_year_col]\nhold_trend_submit = series_submit[trend_col]\n\nseries_submit.drop(unadjust_sales_col, axis=1, inplace=True)\nseries_submit.drop(seasonal_week_col, axis=1, inplace=True)\nseries_submit.drop(seasonal_year_col, axis=1, inplace=True)\nseries_submit.drop(trend_col, axis=1, inplace=True)\n\nseries_submit","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.478662Z","iopub.status.idle":"2022-11-29T00:51:51.479004Z","shell.execute_reply.started":"2022-11-29T00:51:51.478818Z","shell.execute_reply":"2022-11-29T00:51:51.478852Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get sales sequences\nseries2 = series_submit.copy()\ndrop_columns(series2, ['item','store','dow', 'doy', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend', 'people_street', 'people_beach'])\nsales_series = series2.values\n\n# Day of week as a number\nseries2 = series_submit.copy()\ndrop_columns(series2, ['item','store','adjust', 'doy', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend', 'people_street', 'people_beach'])\ndow_series = series2.values\n\n# Get day of year sequences\nseries2 = series_submit.copy()\ndrop_columns(series2, ['item','store','dow', 'adjust', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend', 'people_street', 'people_beach'])\ndoy_series = series2.values\n\n# Get number of people sequences\nseries2 = series_submit.copy()\ndrop_columns(series2, ['item','store','dow', 'doy', 'adjust', 'people_beach', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend'])\npeople_street_series = series2.values\n\nseries2 = series_submit.copy()\ndrop_columns(series2, ['item','store','dow', 'doy', 'adjust', 'people_street', 'submit_id', 'sales', 'seasonal_week', 'seasonal_year', 'trend'])\npeople_beach_series = series2.values\n\n\n# Create x\nt1 = sales_series.reshape(sales_series.shape + (1,))\nt2 = dow_series.reshape(dow_series.shape + (1,)) \nt3 = doy_series.reshape(doy_series.shape + (1,))\nt4 = people_street_series.reshape(people_street_series.shape + (1,))\nt5 = people_beach_series.reshape(people_beach_series.shape + (1,))\nx1 = np.concatenate([t1,t2,t3,t4,t5],axis=2)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.480019Z","iopub.status.idle":"2022-11-29T00:51:51.480331Z","shell.execute_reply.started":"2022-11-29T00:51:51.480181Z","shell.execute_reply":"2022-11-29T00:51:51.480196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(t1.shape)\nprint(t2.shape)\nprint(t3.shape)\nprint(t4.shape)\nprint(t5.shape)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.481136Z","iopub.status.idle":"2022-11-29T00:51:51.481436Z","shell.execute_reply.started":"2022-11-29T00:51:51.481285Z","shell.execute_reply":"2022-11-29T00:51:51.481300Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create predictors (x)\nvec_size = w2vec_model['test'].shape[0]\n\nlst = []\nfor item in list(series_submit['item(t-1)']):\n    lst.append(item_lookup[item])\n\nx2 = np.concatenate(lst).reshape((series_submit.shape[0],vec_size))\n\nx_submit = [x1,x2]","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.482236Z","iopub.status.idle":"2022-11-29T00:51:51.482564Z","shell.execute_reply.started":"2022-11-29T00:51:51.482390Z","shell.execute_reply":"2022-11-29T00:51:51.482405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submit_pred = model.predict(x_submit)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.483366Z","iopub.status.idle":"2022-11-29T00:51:51.483703Z","shell.execute_reply.started":"2022-11-29T00:51:51.483521Z","shell.execute_reply":"2022-11-29T00:51:51.483550Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submit_pred = submit_pred.flatten() * hold_seasonal_week_submit.values * hold_seasonal_year_submit.values * hold_trend_submit.values","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.484705Z","iopub.status.idle":"2022-11-29T00:51:51.485005Z","shell.execute_reply.started":"2022-11-29T00:51:51.484855Z","shell.execute_reply":"2022-11-29T00:51:51.484869Z"},"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-11-29T00:51:51.485781Z","iopub.status.idle":"2022-11-29T00:51:51.486084Z","shell.execute_reply.started":"2022-11-29T00:51:51.485927Z","shell.execute_reply":"2022-11-29T00:51:51.485941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submit.item_count[df_submit['item_count']<0] = 0","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.487118Z","iopub.status.idle":"2022-11-29T00:51:51.487427Z","shell.execute_reply.started":"2022-11-29T00:51:51.487276Z","shell.execute_reply":"2022-11-29T00:51:51.487291Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submit.to_csv('submission.csv',index=False)","metadata":{"execution":{"iopub.status.busy":"2022-11-29T00:51:51.488201Z","iopub.status.idle":"2022-11-29T00:51:51.488499Z","shell.execute_reply.started":"2022-11-29T00:51:51.488349Z","shell.execute_reply":"2022-11-29T00:51:51.488363Z"},"trusted":true},"execution_count":null,"outputs":[]}]}