{"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":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport plotly.express as px\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport datetime\nfrom tqdm import tqdm\n\nfrom xgboost.sklearn      import XGBRegressor\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-07-10T16:34:02.147435Z","iopub.execute_input":"2022-07-10T16:34:02.147908Z","iopub.status.idle":"2022-07-10T16:34:02.418052Z","shell.execute_reply.started":"2022-07-10T16:34:02.147868Z","shell.execute_reply":"2022-07-10T16:34:02.416662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Loading the dataframes\ndf_train = pd.read_csv(\"/kaggle/input/ashrae-energy-prediction/train.csv\")\ndf_weather_train = pd.read_csv(\"/kaggle/input/ashrae-energy-prediction/weather_train.csv\")\ndf_building = pd.read_csv(\"/kaggle/input/ashrae-energy-prediction/building_metadata.csv\")\n\ndf_test = pd.read_csv(\"/kaggle/input/ashrae-energy-prediction/test.csv\")\ndf_weather_test =   pd.read_csv(\"/kaggle/input/ashrae-energy-prediction/weather_test.csv\")\n\nsubmission = pd.read_csv(\"/kaggle/input/ashrae-energy-prediction/sample_submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:36:20.885675Z","iopub.execute_input":"2022-07-10T16:36:20.88651Z","iopub.status.idle":"2022-07-10T16:37:14.486008Z","shell.execute_reply.started":"2022-07-10T16:36:20.886463Z","shell.execute_reply":"2022-07-10T16:37:14.484534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Accuracy metrics\n#both entries must be arrays. Both cannot be series\n\nfrom statsmodels.tsa.stattools import acf\nfrom sklearn.metrics import r2_score\n\ndef forecast_accuracy(actual, forecast):\n    \n    #mape = np.mean(100*np.abs(forecast - actual)/np.abs(actual))        # MAPE  (mean absolute percentage error)\n    #me   = np.mean(forecast - actual)                                   # ME    (mean error)\n    #mae  = np.mean(np.abs(forecast - actual))                           # MAE   (mean absolute error)\n    #mpe  = np.mean((forecast - actual)/actual)                          # MPE   (mean percentage error)\n    #rmse = np.mean((forecast - actual)**2)**.5                          # RMSE  (root mean square error) \n    msle= np.mean((np.log(forecast+1) - np.log(actual+1))**2)           # MSLE  (mean square logarithmic error)\n    rmsle = (msle)**.5\n    #corr = np.corrcoef(forecast, actual)[0,1]                           # corr  (pearson R coefficient)\n    #rsquared = r2_score(actual,forecast)                                #R-squared\n    \n    #mins = np.amin(np.hstack([forecast[:,None], actual[:,None]]), axis=1)\n    #maxs = np.amax(np.hstack([forecast[:,None], actual[:,None]]), axis=1)  \n    #minmax = (1 - np.mean(mins/maxs)).round(3)                          # minmax\n    \n    #acf1 = acf(forecast-actual)[1]                                      # ACF1 (first order auto correlation order)\n\n    results = ({\n                'rmsle':rmsle,\n              })\n    \n    results = pd.DataFrame.from_dict(results,orient='index',columns=['value'])\n    \n    df_results= pd.DataFrame(list(zip (actual, forecast )  ) , columns= ['valid' , 'pred'] ) \n    \n    return results.round(4),df_results\n#forecast_accuracy(y_valid, y_pred)","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:37:36.803198Z","iopub.execute_input":"2022-07-10T16:37:36.804867Z","iopub.status.idle":"2022-07-10T16:37:36.974564Z","shell.execute_reply.started":"2022-07-10T16:37:36.804796Z","shell.execute_reply":"2022-07-10T16:37:36.973235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Function to reduce the memory usage\nfrom pandas.api.types import is_datetime64_any_dtype as is_datetime\nfrom pandas.api.types import is_categorical_dtype\ndef reduce_mem_usage(df):\n    \"\"\" iterate through all the columns of a dataframe and modify the data type\n        to reduce memory usage.        \n    \"\"\"\n    start_mem = df.memory_usage().sum() / 1024**2\n    print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))\n    \n    for col in df.columns:\n        if is_datetime(df[col]) or is_categorical_dtype(df[col]):\n            # skip datetime type or categorical type\n            continue\n            \n        col_type = df[col].dtype\n        \n        if col_type != object:\n            c_min = df[col].min()\n            c_max = df[col].max()\n            if str(col_type)[:3] == 'int':\n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                    df[col] = df[col].astype(np.int32)\n                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                    df[col] = df[col].astype(np.int64)  \n            else:\n                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n                    df[col] = df[col].astype(np.float16)\n                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n                    df[col] = df[col].astype(np.float32)\n                else:\n                    df[col] = df[col].astype(np.float64)\n        else:\n            df[col] = df[col].astype('category')\n\n        \n    end_mem = df.memory_usage().sum() / 1024**2\n    print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))\n    print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))\n    \n    return df","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:37:49.002072Z","iopub.execute_input":"2022-07-10T16:37:49.003287Z","iopub.status.idle":"2022-07-10T16:37:49.017071Z","shell.execute_reply.started":"2022-07-10T16:37:49.003231Z","shell.execute_reply":"2022-07-10T16:37:49.015827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Reducing sizes of the datasets\ndf_train = reduce_mem_usage(df_train)                       \ndf_weather_train = reduce_mem_usage(df_weather_train)\ndf_building = reduce_mem_usage(df_building)\ndf_test = reduce_mem_usage(df_test)    \ndf_weather_test = reduce_mem_usage(df_weather_test)    ","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:38:12.293954Z","iopub.execute_input":"2022-07-10T16:38:12.294918Z","iopub.status.idle":"2022-07-10T16:38:21.192Z","shell.execute_reply.started":"2022-07-10T16:38:12.294868Z","shell.execute_reply":"2022-07-10T16:38:21.190811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Merging train dataset with the building site and weather conditions\ndf_train = pd.merge(df_train, df_building, how='left', on='building_id')\ndf_train = pd.merge(df_train, df_weather_train, how='left', on=['site_id','timestamp'])","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:38:31.261116Z","iopub.execute_input":"2022-07-10T16:38:31.261651Z","iopub.status.idle":"2022-07-10T16:38:40.4795Z","shell.execute_reply.started":"2022-07-10T16:38:31.26161Z","shell.execute_reply":"2022-07-10T16:38:40.478101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Creating features for dates\ndf_train['timestamp']=df_train['timestamp'].astype('datetime64[ns]')\ndf_train['hour']=df_train['timestamp'].dt.hour\ndf_train['day']=df_train['timestamp'].dt.day\ndf_train['month']=df_train['timestamp'].dt.month\ndf_train['year']=df_train['timestamp'].dt.year","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:38:40.483301Z","iopub.execute_input":"2022-07-10T16:38:40.483708Z","iopub.status.idle":"2022-07-10T16:38:48.593601Z","shell.execute_reply.started":"2022-07-10T16:38:40.48367Z","shell.execute_reply":"2022-07-10T16:38:48.59232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Reducing again the size of df_train set\ndf_train = reduce_mem_usage(df_train)  ","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:38:56.706339Z","iopub.execute_input":"2022-07-10T16:38:56.706705Z","iopub.status.idle":"2022-07-10T16:39:05.136651Z","shell.execute_reply.started":"2022-07-10T16:38:56.70667Z","shell.execute_reply":"2022-07-10T16:39:05.135265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training models","metadata":{}},{"cell_type":"code","source":"# A model will be created for each building and for each type of meters. This will allow to drop some columns that will no longer be necessary.\n\ndf_train.drop(columns=['site_id','primary_use','square_feet','year_built','floor_count'],inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:40:39.69253Z","iopub.execute_input":"2022-07-10T16:40:39.694053Z","iopub.status.idle":"2022-07-10T16:40:41.321873Z","shell.execute_reply.started":"2022-07-10T16:40:39.693987Z","shell.execute_reply":"2022-07-10T16:40:41.320352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Funciton to create lags \n\ndef lag_feature(df,lags,cols ):\n    for col in cols:\n        #print('Adding lag feature in ',col)\n        tmp=df[['timestamp',col]]\n        for i in lags:\n            horas = datetime.timedelta(hours=i)\n            shifted=tmp.copy()\n            shifted.columns=['timestamp',col+'_shifted_'+str(i)]\n            shifted['timestamp']=shifted['timestamp'] +horas\n            df=pd.merge(df,shifted,on=['timestamp'],how='left')\n    return df","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:41:03.080216Z","iopub.execute_input":"2022-07-10T16:41:03.080802Z","iopub.status.idle":"2022-07-10T16:41:03.088418Z","shell.execute_reply.started":"2022-07-10T16:41:03.080762Z","shell.execute_reply":"2022-07-10T16:41:03.087295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Function to train each model for each building and meter\n\ndef Training(df):\n    models = [ ]\n    buildings = np.sort(df['building_id'].unique())\n    for building_id in tqdm(buildings,desc='progreso',position=0):\n\n        df1 = df[df['building_id']==building_id]\n        meters = df1['meter'].unique()\n        \n        for meter in meters:\n  \n            df2 = df1[df1['meter']==meter].reset_index(drop=True)\n            \n            # Using first 70% of values for the train set and the remaining 30% for the valid (test) set\n            days = (df2['timestamp'].iloc[-1]-df2['timestamp'].iloc[0])\n            train_cut = days*0.7\n            time = df2['timestamp'].iloc[0] + train_cut\n            index_cut = df2[df2['timestamp']<str(time.date())].index[-1]\n            \n            #Spliting train and test \"valid\" sets to improve the accuracy of the xgb model\n            df2.loc[df2.index <= index_cut, \"set\"] = \"train\"\n            df2.loc[df2.index > index_cut, \"set\"] = \"test\"\n            \n            # Creating new set with the lags\n            matrix=lag_feature(df2,[1,24],[\"air_temperature\",\"cloud_coverage\",\"dew_temperature\",\"precip_depth_1_hr\",\"sea_level_pressure\",\"wind_direction\",\"wind_speed\"])\n            \n            features = matrix.drop(columns=['building_id','meter','timestamp','meter_reading','set']).columns\n            \n            X_train=matrix[matrix['set']=='train'][features]\n            X_valid=matrix[matrix['set']=='test'][features]\n\n            Y_train=matrix.loc[matrix['set']=='train']['meter_reading']\n            Y_valid=matrix.loc[matrix['set']=='test']['meter_reading']\n                                    \n            model = XGBRegressor(\n                max_depth=10,\n                n_estimators=1000,\n                min_child_weight=0.5, \n                colsample_bytree=0.8, \n                subsample=0.8, \n                eta=0.1,\n                seed=42)\n            \n            model.fit(\n                X_train, \n                Y_train, \n                eval_metric=\"rmse\", \n                eval_set=[(X_train, Y_train),(X_valid, Y_valid)], \n                verbose=False, \n                early_stopping_rounds = 20)\n            \n            Y_pred = model.predict(X_valid)\n            \n            score = forecast_accuracy(Y_valid, Y_pred)[0].iloc[0].value\n                                              \n            # Saving the model for each building_id and meter   \n            resultado = [ building_id  , meter ,  model ,score ]     \n                                                                            \n            models.append( resultado)\n            \n            \n    df_modelos = pd.DataFrame ( models , columns =  ['building_id' , 'meter' , 'model', 'score'] )       \n    \n    return df_modelos     ","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:49:44.988569Z","iopub.execute_input":"2022-07-10T16:49:44.989006Z","iopub.status.idle":"2022-07-10T16:49:45.003565Z","shell.execute_reply.started":"2022-07-10T16:49:44.98897Z","shell.execute_reply":"2022-07-10T16:49:45.002194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" df_modelos= Training(df_train)","metadata":{"execution":{"iopub.status.busy":"2022-07-10T16:49:47.024623Z","iopub.execute_input":"2022-07-10T16:49:47.025881Z","iopub.status.idle":"2022-07-10T18:02:07.574067Z","shell.execute_reply.started":"2022-07-10T16:49:47.025825Z","shell.execute_reply":"2022-07-10T18:02:07.573134Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Testing ","metadata":{}},{"cell_type":"code","source":"# Merging test dataset with the building site and weather conditions\ndf_test = pd.merge(df_test, df_building, how='left', on='building_id')\ndf_test = pd.merge(df_test, df_weather_test, how='left', on=['site_id','timestamp'])","metadata":{"execution":{"iopub.status.busy":"2022-07-10T18:02:07.576299Z","iopub.execute_input":"2022-07-10T18:02:07.576827Z","iopub.status.idle":"2022-07-10T18:02:24.552008Z","shell.execute_reply.started":"2022-07-10T18:02:07.576789Z","shell.execute_reply":"2022-07-10T18:02:24.550843Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test['timestamp']=df_test['timestamp'].astype('datetime64[ns]')\ndf_test['hour']=df_test['timestamp'].dt.hour\ndf_test['day']=df_test['timestamp'].dt.day\ndf_test['month']=df_test['timestamp'].dt.month\ndf_test['year']=df_test['timestamp'].dt.year","metadata":{"execution":{"iopub.status.busy":"2022-07-10T18:02:24.553971Z","iopub.execute_input":"2022-07-10T18:02:24.554416Z","iopub.status.idle":"2022-07-10T18:02:40.544008Z","shell.execute_reply.started":"2022-07-10T18:02:24.554369Z","shell.execute_reply":"2022-07-10T18:02:40.54276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test.drop(columns=['site_id','primary_use','square_feet','year_built','floor_count'],inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-07-10T18:02:40.546749Z","iopub.execute_input":"2022-07-10T18:02:40.547096Z","iopub.status.idle":"2022-07-10T18:02:46.032689Z","shell.execute_reply.started":"2022-07-10T18:02:40.547064Z","shell.execute_reply":"2022-07-10T18:02:46.031404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test = reduce_mem_usage(df_test)   ","metadata":{"execution":{"iopub.status.busy":"2022-07-10T18:02:46.034564Z","iopub.execute_input":"2022-07-10T18:02:46.035073Z","iopub.status.idle":"2022-07-10T18:03:00.49005Z","shell.execute_reply.started":"2022-07-10T18:02:46.035019Z","shell.execute_reply":"2022-07-10T18:03:00.488809Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Function to predit the results for each building and meter\n\ndef predict_test( df, df_modelos):\n    \n    df['Y_pred']= None\n    buildings = np.sort(df['building_id'].unique())\n    \n    for building_id in tqdm(buildings,desc='progreso',position=0):\n\n        df1 = df[df['building_id']==building_id]\n        meters = df1['meter'].unique()\n           \n        for meter in meters:\n\n            df2 = df1[df1['meter']==meter].reset_index(drop=True)\n            \n            model = df_modelos[(df_modelos['building_id']==building_id) & (df_modelos['meter']==meter)].iloc[0]['model']\n            \n            matrix=lag_feature(df2,[1,24],[\"air_temperature\",\"cloud_coverage\",\"dew_temperature\",\"precip_depth_1_hr\",\"sea_level_pressure\",\"wind_direction\",\"wind_speed\"])\n    \n            features = matrix.drop(columns=['row_id','building_id','meter','timestamp','Y_pred']).columns\n           \n            X_test=matrix[features]\n\n            Y_pred = model.predict(X_test)\n            \n            matrix['Y_pred'] =  Y_pred \n            \n            df['Y_pred'] = df.set_index('row_id')['Y_pred'].fillna(matrix.set_index('row_id')['Y_pred'])\n            \n          \n    return df                                                                          ","metadata":{"execution":{"iopub.status.busy":"2022-07-10T18:03:00.491952Z","iopub.execute_input":"2022-07-10T18:03:00.492903Z","iopub.status.idle":"2022-07-10T18:03:00.507139Z","shell.execute_reply.started":"2022-07-10T18:03:00.492851Z","shell.execute_reply":"2022-07-10T18:03:00.505711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test = predict_test(df_test, df_modelos)","metadata":{"execution":{"iopub.status.busy":"2022-07-10T18:03:00.509137Z","iopub.execute_input":"2022-07-10T18:03:00.509738Z","iopub.status.idle":"2022-07-10T19:43:12.564091Z","shell.execute_reply.started":"2022-07-10T18:03:00.509687Z","shell.execute_reply":"2022-07-10T19:43:12.56187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output = pd.DataFrame({'row_id': df_test['row_id'], 'meter_reading': df_test['Y_pred']})\noutput.to_csv('submission.csv', index=False)\nprint(\"Your submission was successfully saved!\")","metadata":{"execution":{"iopub.status.busy":"2022-07-10T19:43:12.567203Z","iopub.execute_input":"2022-07-10T19:43:12.567733Z","iopub.status.idle":"2022-07-10T19:44:48.98926Z","shell.execute_reply.started":"2022-07-10T19:43:12.567692Z","shell.execute_reply":"2022-07-10T19:44:48.987657Z"},"trusted":true},"execution_count":null,"outputs":[]}]}