{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"markdown","source":"# Light GBM with engineered features\n\n** Note to self**: this kernel will purposfully avoid using the feature visitStartTime directly as this appears to lead to overfit models on the public Leader Board. i.e. very good results for no apparent reason... "},{"metadata":{"_uuid":"af39079273f24d92b9da0e6ecc4613ccc71fd441"},"cell_type":"markdown","source":"### Libraries "},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport time\nimport warnings\nimport datetime\n\n#Plotting\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nplt.style.use('ggplot')\n\n#Sklearn\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.model_selection import KFold\n\n#lgm and graph viz\nimport graphviz \nimport lightgbm as lgb\n\nwarnings.filterwarnings('ignore')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c52b2cbc7e2df1501bb4cd70e55f7c47af7daf8b"},"cell_type":"code","source":"os.listdir('../input/kernel-for-saving-files')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ddfd0f6739c9a22f681978b63cc8447c86d2cbdf"},"cell_type":"markdown","source":"## Loading files which were partially preprocessed from previous kernel\n\n- Categories are label encoded\n- Local time field is calculated (_local_hourofday)\n- Time since last visit is already calculated"},{"metadata":{"trusted":true,"_uuid":"d50cf91c486f248a8e861e7684583e4999fa5232"},"cell_type":"code","source":"%%time\ntrain_df = pd.read_pickle('../input/kernel-for-saving-files/train_flat_local_cat_enc.pkl')\ntest_df = pd.read_pickle('../input/kernel-for-saving-files/test_flat_local_cat_enc.pkl')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f9b40e46958ca3a9c11dd5716e13bf0a7ab6af9c"},"cell_type":"code","source":"train_df.info()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f10390cce140ec6a4336fc29a3211620dcbce4e6"},"cell_type":"markdown","source":"# Feature engineering \n\n## Columns definitions"},{"metadata":{"trusted":true,"_uuid":"35cc6ef868f116009b9290e3a7d51f3310bc4eee"},"cell_type":"code","source":"# Extract target values and Ids\ncat_cols = ['channelGrouping','device.browser',\n       'device.deviceCategory', 'device.isMobile', 'device.operatingSystem',\n       'geoNetwork.city', 'geoNetwork.continent', 'geoNetwork.country',\n       'geoNetwork.metro', 'geoNetwork.networkDomain', 'geoNetwork.region',\n       'geoNetwork.subContinent','trafficSource.adContent',\n       'trafficSource.adwordsClickInfo.adNetworkType',\n       'trafficSource.adwordsClickInfo.gclId',\n       'trafficSource.adwordsClickInfo.isVideoAd',\n       'trafficSource.adwordsClickInfo.page',\n       'trafficSource.adwordsClickInfo.slot', 'trafficSource.campaign',\n       'trafficSource.isTrueDirect', 'trafficSource.keyword',\n       'trafficSource.medium', 'trafficSource.referralPath',\n       'trafficSource.source'  ]\n\n\nnum_cols = ['visitNumber', 'totals.bounces', 'totals.hits',\n            'totals.newVisits', 'totals.pageviews' ]\n\ninteraction_cols = ['totals.hits / totals.pageviews', 'totals.hits * totals.pageviews','visitNumber / totals.hits']\n\nvisitStartTime = ['visitStartTime']\n\ntime_cols = ['_dayofweek', '_monthofyear', '_dayofyear', '_local_hourofday', '_time_since_last_visit']\n\nID_cols = ['date', 'fullVisitorId', 'sessionId', 'visitId']\n\ntarget_col = ['totals.transactionRevenue']\n\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"622a64108a91adf9889f557faa2b6cd879235ec6"},"cell_type":"markdown","source":"## Time features\n"},{"metadata":{"trusted":true,"_uuid":"9ef7a6112f8bce55e32de3bfe5765b2c0f72e54c"},"cell_type":"markdown","source":"### Other simple date based features "},{"metadata":{"trusted":true,"_uuid":"dbd7746468a20e7c03d1a1c1f0d5a9ad9e7aee7d"},"cell_type":"code","source":"train_df['_dayofweek'] = train_df['visitStartTime'].dt.dayofweek\ntrain_df['_monthofyear'] = train_df['visitStartTime'].dt.month\ntrain_df['_dayofyear'] = train_df['visitStartTime'].dt.dayofyear\n#train_df['_dayofmonth'] = train_df['visitStartTime'].dt.day\n\ntest_df['_dayofweek'] = test_df['visitStartTime'].dt.dayofweek\ntest_df['_monthofyear'] = test_df['visitStartTime'].dt.month\ntest_df['_dayofyear'] = test_df['visitStartTime'].dt.dayofyear\n#test_df['_dayofmonth'] = test_df['visitStartTime'].dt.day\n\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"861b0f2aa680f8e9e3401d0a98580100518b8f69"},"cell_type":"markdown","source":"## Interaction feature\n\nOnly a few are selected currently.."},{"metadata":{"trusted":true,"_uuid":"1ce075620d4140828ea4918e1136de7f6e810ba3"},"cell_type":"code","source":"%%time\nfrom itertools import combinations\n\nto_interact_cols = ['visitNumber', 'totals.hits', 'totals.pageviews']\n\n#Numeric as float\nfor n in [num_cols + time_cols]:\n    train_df[n] = train_df[n].fillna(0).astype('float')\n    test_df[n] = test_df[n].fillna(0).astype('float')\n    \n\n\ndef numeric_interaction_terms(df, columns):\n    for c in combinations(columns,2):\n        df['{} / {}'.format(c[0], c[1]) ] = df[c[0]] / df[c[1]]\n        df['{} * {}'.format(c[0], c[1]) ] = df[c[0]] * df[c[1]]\n        df['{} - {}'.format(c[0], c[1]) ] = df[c[0]] - df[c[1]]\n    return df\n\n\ntrain_df = numeric_interaction_terms(train_df,to_interact_cols )\ntest_df = numeric_interaction_terms(test_df,to_interact_cols )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ffc65bef3bbee5025d62451303a2d58440af380f"},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"887de33967143a2333f57373bd9557cf5132ad7b"},"cell_type":"markdown","source":"# Pre-processing"},{"metadata":{"_uuid":"d4e2eee243d2b3255f42449fa0197808c9518e10"},"cell_type":"markdown","source":"## Label encoding\nAlready done"},{"metadata":{"_uuid":"b8bf19c520063a3b4cbd8726383e05e2eb698d81"},"cell_type":"markdown","source":"## Target, index and extraction of datasets"},{"metadata":{"trusted":true,"_uuid":"6058c799d44df84d27acaa8ca20af8212e6097db"},"cell_type":"code","source":"train_df['totals.transactionRevenue'] = train_df['totals.transactionRevenue'].fillna(0).astype('float')\n\n#Index\ntrain_idx = train_df['fullVisitorId']\ntest_idx = test_df['fullVisitorId']\n\n#Targets\ntrain_target = np.log1p(train_df.groupby(\"fullVisitorId\")[\"totals.transactionRevenue\"].sum())\ntrain_y = np.log1p(train_df[\"totals.transactionRevenue\"].values)\n\n#Datasets\ntrain_X = train_df[cat_cols + num_cols + time_cols + interaction_cols].copy()\ntest_X = test_df[cat_cols + num_cols + time_cols + interaction_cols].copy()\n\nprint(train_X.shape)\nprint(test_X.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6bc4a7143d5c33d2da340e8065ff972526ff4dec"},"cell_type":"code","source":"train_X.info()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"74bc8b9f4d5b8f790d5333d01ac6a8b20df1606f"},"cell_type":"markdown","source":"# Light GBM \n## Initialize (Sklearn wrapper)"},{"metadata":{"trusted":true,"_uuid":"a97569f5739149e55a5038e3c822455ec5be6c50"},"cell_type":"code","source":"from lightgbm import LGBMRegressor\n\n#Initialize LGBM\ngbm = LGBMRegressor(objective = 'regression', \n                     boosting_type = 'dart', \n                     metric = 'rmse',\n                     n_estimators = 10000, #10000\n                     num_leaves = 54, #10\n                     learning_rate = 0.005, #0.01\n                     #bagging_fraction = 0.9,\n                     #feature_fraction = 0.3,\n                     bagging_seed = 0,\n                     max_depth = 10,\n                     reg_alpha = 0.436193,\n                     reg_lambda = 0.479169,\n                     colsample_bytree = 0.508716,\n                     min_split_gain = 0.024766\n                    )\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"85c6e5a2123a7daa6c8d16433b5fd25ab1015d67"},"cell_type":"markdown","source":"## Fit the model\n**In a nutshell**: K-fold training where each fold is used once for early stopping validation. At each fold, a test prediction is made using the trained model. Final prediction is an average of the K predictions\n\n**Steps:**\n- Fit the LGBM model K times on the dataset - the Kth fold\n - For each fitted model, predict on validation set (oof_pred) and on test set (sub_preds)\n - Average presub_preds for final predictions\n\nIdea for averaged models comes from: https://www.kaggle.com/sz8416/lb-1-4439-gacr-prediction-eda-lgb-baseline"},{"metadata":{"trusted":true,"_uuid":"59637b78789000f750d3977655cbe397db73f644"},"cell_type":"code","source":"%%time\n#Initilization\nall_K_fold_results = []\nkf = KFold(n_splits=5, shuffle = True)\noof_preds = np.zeros(train_X.shape[0])\nsub_preds = np.zeros(test_X.shape[0])\n\n\nfor dev_index, val_index in kf.split(train_X):\n    X_dev, X_val = train_X.iloc[dev_index], train_X.iloc[val_index]\n    y_dev, y_val = train_y[dev_index], train_y[val_index]\n\n    #Fit the model\n    model = gbm.fit(X_dev,y_dev, eval_set=[(X_val, y_val)],verbose = 100, \n                    eval_metric = 'rmse', early_stopping_rounds = 100) #100\n    \n    #Predict out of fold \n    oof_preds[val_index] = gbm.predict(X_val, num_iteration= model.best_iteration_)\n    \n    oof_preds[oof_preds < 0] = 0\n    \n    #Predict on test set based on current fold model. Average results\n    sub_prediction = gbm.predict(test_X, num_iteration= model.best_iteration_) / kf.n_splits\n    sub_prediction[sub_prediction<0] = 0\n    sub_preds = sub_preds + sub_prediction\n    \n    #Save current fold values\n    fold_results = {'best_iteration_' : model.best_iteration_, \n                   'best_score_' : model.best_score_['valid_0']['rmse'], \n                   'evals_result_': model.evals_result_['valid_0']['rmse'],\n                   'feature_importances_' : model.feature_importances_}\n\n    all_K_fold_results.append(fold_results.copy())\n    \n\nresults = pd.DataFrame(all_K_fold_results)\n\n\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"08293093bf5f847937c9bc8bfa0eaa4727a9b2a3"},"cell_type":"markdown","source":"## Visualization, RMSE and saving utility functions \nA helper function which plots the RMSE as a function of iterations, a box plot of the RMSE, and the average feature importance (with std error bars)\n\n**Note**: exponentiating the predictions made on $log(y)$ might not be mathematically valid... to be investigated further. See this discussion https://www.kaggle.com/c/ga-customer-revenue-prediction/discussion/67206"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"0f801c637b26ac920aaad49693b70e32661d0395"},"cell_type":"code","source":"def RMSE_log_sum(pred_val, val_df):\n    #set negative values to zero\n    pred_val[pred_val < 0] = 0\n    \n    #Build new dataframe\n    val_pred_df = pd.DataFrame(data = {'fullVisitorId': val_df['fullVisitorId'].values, \n                                       'transactionRevenue': val_df['totals.transactionRevenue'].values,\n                                      'predictedRevenue':np.expm1(pred_val) })\n    #Compute sum\n    val_pred_df = val_pred_df.groupby('fullVisitorId').sum().reset_index()\n\n    mse_log_sum = mean_squared_error( np.log1p(val_pred_df['transactionRevenue'].values), \n                             np.log1p(val_pred_df['predictedRevenue'].values)  )\n\n    #print('log (sum + 1): ',np.sqrt(mse_log_sum))\n    return np.sqrt(mse_log_sum)\n\n\ndef save_submission(pred_test, test_df, file_name):\n    #Zero negative predictions\n    pred_test[pred_test < 0] = 0\n    \n    #Create temporary dataframe\n    sub_df = pd.DataFrame(data = {'fullVisitorId':test_df['fullVisitorId'], \n                             'predictedRevenue':np.expm1(pred_test)})\n    sub_df = sub_df.groupby('fullVisitorId').sum().reset_index()\n    sub_df.columns = ['fullVisitorId', 'predictedLogRevenue']\n    sub_df['predictedLogRevenue'] = np.log1p(sub_df['predictedLogRevenue'])\n    sub_df.to_csv(file_name, index = False)\n\n    \ndef visualize_results(results):\n#Utility function to plot fold loss and best model feature importance\n    plt.figure(figsize=(16, 12))\n\n    #----------------------------------------\n    # Plot validation loss\n    plt.subplot(2,2,1)\n\n    for K in range(results.shape[0]):\n        plt.plot(np.arange(len(results.evals_result_[K])), results.evals_result_[K], label = 'fold {}'.format(K))\n\n    plt.xlabel('Boosting iterations')\n    plt.ylabel('RMSE')\n    plt.title('Validation loss vs boosting iterations')\n    plt.legend()\n\n    #----------------------------------------\n    # Plot box plot of RMSE\n    plt.subplot(2, 2, 2)    \n    scores = results.best_score_\n    plt.boxplot(scores)\n    rmse_mean = np.mean(scores)\n    rmse_std = np.std(scores)\n    plt.title('RMSE Mean:{:.3f} Std: {:.4f}'.format(rmse_mean,rmse_std ))\n    \n    #----------------------------------------\n    # Plot feature importance\n    #feature_importance = results.sort_values('best_score_').feature_importances_[0]\n    df_feature_importance = pd.DataFrame.from_records(results.feature_importances_)\n    feature_importance = df_feature_importance.mean()\n    std_feature_importance = df_feature_importance.std()\n    \n    # make importances relative to max importance\n    #feature_importance = 100.0 * (mean_feature_importance / mean_feature_importance.sum())\n    sorted_idx = np.argsort(feature_importance)\n    pos = np.arange(sorted_idx.shape[0]) + .5\n    plt.subplot(2, 1, 2)\n    plt.bar(pos, feature_importance[sorted_idx], align='center', yerr = std_feature_importance)\n    xlabels = [ train_X.columns.values[i] for i in sorted_idx]\n    plt.xticks(pos, xlabels, rotation = 90)\n    plt.xlabel('Feature')\n    plt.ylabel('Avg Importance score')\n    plt.title('Mean Feature Importance over K folds') \n    \n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f45c6b7b8a7310dd6d8dcb736fde6d9180fc7ba4"},"cell_type":"code","source":"print('Session level CV score: ', np.mean(results.best_score_))\nprint('User level CV score: ', RMSE_log_sum(oof_preds, train_df))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"aade80dc82853dab38c56e4be2e8b78d0f420b6f"},"cell_type":"code","source":"results.evals_result_","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8a77aad0ec45a5ed544d11f5a51ab6d7350d5802"},"cell_type":"markdown","source":"## Validation RMSE and feature importance "},{"metadata":{"trusted":true,"_uuid":"a1e52ce1bdac43bedbe79f4ee357b0f210391883"},"cell_type":"code","source":"visualize_results(results)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"74771f1c06f4b46722f34d643a51baa162bfc5cc"},"cell_type":"markdown","source":"## Visualize the first decision tree\n"},{"metadata":{"trusted":true,"_uuid":"a53295e707f71ddcb37ee879d0c83a76aae018b3"},"cell_type":"code","source":"import graphviz \ndot_data = lgb.create_tree_digraph(model, tree_index = 1,show_info=['split_gain'])\n\ngraph = graphviz.Source(dot_data)  \ngraph ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"72c841e0795e7874b4688ff08748bf4b1face9fa"},"cell_type":"markdown","source":"# Error analysis\n## Distributions of true and predicted log revenues "},{"metadata":{"trusted":true,"_uuid":"0aa7ba76638152f6bec03ac45d0dd40d75d1e08e"},"cell_type":"code","source":"error_df = pd.DataFrame(data = {'visitStartTime':train_df['visitStartTime'],'fullVisitorId':train_df['sessionId'], \n                                'True_log_revenue' : np.log1p(train_df['totals.transactionRevenue']), \n                                'Predicted_log_revenue':oof_preds  })\n\nerror_df['Difference'] = error_df['True_log_revenue'] - error_df['Predicted_log_revenue']\nerror_df['True_is_non_zero'] = error_df['True_log_revenue'] > 0\n#temp_df.columns = ['fullVisitorId', 'predictedLogRevenue']\n#sub_df['predictedLogRevenue'] = np.log1p(sub_df['predictedLogRevenue'])\n#sub_df.to_csv(file_name, index = False)\nerror_df.head(100).sort_values('True_log_revenue')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4937a4dda51a2eeb60d4c00cedd4b6c354543b0a"},"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize = (20,7))\n\n\nsns.distplot(error_df[error_df['True_is_non_zero'] == False]['True_log_revenue'], ax = ax1, label = 'true')\nsns.distplot(error_df[error_df['True_is_non_zero'] == False ]['Predicted_log_revenue'], ax = ax1, label = 'pred')\nax1.legend()\nax1.set_ylim(0,.1)\nax1.set_xlabel('Log revenue (session)')\nax1.set_title('Distribution of log revenues for sessions with zero true revenue ')\n\nsns.distplot(error_df[error_df['True_is_non_zero'] == True]['True_log_revenue'], ax = ax2, label = 'true')\nsns.distplot(error_df[error_df['True_is_non_zero'] == True ]['Predicted_log_revenue'], ax = ax2, label = 'pred')\nax2.legend()\nax2.set_ylim(0,.5)\nax2.set_xlabel('Log revenue (session)')\nax2.set_title('Distribution of log revenues for sessions with non zero true revenue ')\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dd36321e360cc52cbfac3709c09dedabb1596003"},"cell_type":"code","source":"sorted_non_zero = error_df[error_df['True_is_non_zero'] == True].sort_values('visitStartTime')\n\n\nplt.figure(figsize = (20,15))\nplt.subplot(2,2,1)\nplt.plot(sorted_non_zero.visitStartTime, sorted_non_zero.True_log_revenue , label = 'True')\nplt.plot(sorted_non_zero.visitStartTime, sorted_non_zero.Predicted_log_revenue , alpha = .5, label = 'Pred')\nplt.title('Log revenue over time (non zero true sessions only)')\nplt.legend()\nplt.xlabel('Time: sessions')\n\nplt.subplot(2,2,2)\ndaily_error_non_zero_df = sorted_non_zero.set_index('visitStartTime', drop = True).resample('D').mean()\nplt.plot(daily_error_non_zero_df.index, daily_error_non_zero_df.True_log_revenue , label = 'True')\nplt.plot(daily_error_non_zero_df.index, daily_error_non_zero_df.Predicted_log_revenue , label = 'Pred')\nplt.title('Daily average log revenue (non zero true sessions only)')\n\nplt.subplot(2,2,3)\nweekly_error_df = error_df.set_index('visitStartTime', drop = True).resample('W').mean()\nplt.plot(weekly_error_df.index, weekly_error_df.True_log_revenue , label = 'True')\nplt.plot(weekly_error_df.index, weekly_error_df.Predicted_log_revenue , label = 'Pred')\nplt.title('Weekly average log revenue (all session)')\n\n\nplt.subplot(2,2,4)\ndaily_error_df = error_df.set_index('visitStartTime', drop = True).resample('D').mean()\nplt.plot(daily_error_df.index, daily_error_df.True_log_revenue , label = 'True')\nplt.plot(daily_error_df.index, daily_error_df.Predicted_log_revenue , label = 'Pred')\nplt.title('Daily average log revenue (all session)')\n\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6dfe1d5daddae07b49600c89fcf6d6ebb3845983"},"cell_type":"code","source":"sorted_non_zero = error_df[error_df['True_is_non_zero'] == True].sort_values('visitStartTime')\nsorted_zero = error_df[error_df['True_is_non_zero'] == False].sort_values('visitStartTime')\n\n\nplt.figure(figsize = (20,5))\nplt.subplot(1,3,1)\nts_error_df = error_df.set_index('visitStartTime', drop = True)\ndifference_rev_df = error_df.sort_values('visitStartTime')\nplt.plot(error_df.visitStartTime, error_df.Difference , label = 'True - predicted', color = 'grey')\nplt.title('Train - Pred (log rev) for all sessions')\n\nplt.subplot(1,3,2)\nplt.plot(sorted_non_zero.visitStartTime, sorted_non_zero.Difference , label = 'True - predicted',\n         color = 'grey')\nplt.title('Train - Pred for non zero sessions only')\n\nplt.subplot(1,3,3)\nplt.plot(sorted_zero.visitStartTime, sorted_zero.Difference,\n         color = 'grey')\nplt.title('Train - Pred for zero sessions only')\n\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a6289bf25a29f28cb675d575e4221b4baacbb212"},"cell_type":"code","source":"\nsns.jointplot(x=\"True_log_revenue\", y=\"Predicted_log_revenue\", data=sorted_non_zero)\ndisplay('Joint distribution of log rev for non zero sessions only')\n\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d7e742cb272823fbcba0b8ccb5c301c281405924"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5962fba097f8fe60cecdd0d026bc3de7f2acd722"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"10ee8ed7e6350ee5228a3ccd9923a65d0451a54f"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7485dc2e46591f4834e2db5fef27c4d46d8f2f94"},"cell_type":"code","source":"pred_test[pred_test < 0] = 0\n    \n    #Create temporary dataframe\n    sub_df = pd.DataFrame(data = {'fullVisitorId':test_df['fullVisitorId'], \n                             'predictedRevenue':np.expm1(pred_test)})\n    sub_df = sub_df.groupby('fullVisitorId').sum().reset_index()\n    sub_df.columns = ['fullVisitorId', 'predictedLogRevenue']\n    sub_df['predictedLogRevenue'] = np.log1p(sub_df['predictedLogRevenue'])\n    sub_df.to_csv(file_name, index = False)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"72384a79e5263aa44f83db2f0d64be23456b803a"},"cell_type":"markdown","source":"## Save submission "},{"metadata":{"trusted":true,"_uuid":"883a79acb3ba12eb84d20cb250674df699b6822a"},"cell_type":"code","source":"save_submission(sub_preds, test_df, 'submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cef24a2ceadc7a6c18e90a59d93f4501658d5eb1"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}