{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Team ASYC notebook"},{"metadata":{},"cell_type":"markdown","source":"*First we installed the necessary libraries:*"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport gc\n\nimport matplotlib.pyplot as plt # matplotlib and seaborn for plotting\nimport matplotlib.patches as patches\nimport seaborn as sns\n\nfrom plotly import tools, subplots\nimport plotly.offline as py\npy.init_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nimport plotly.express as px\npd.set_option('max_columns', 150)\npy.init_notebook_mode(connected=True)\nfrom plotly.offline import init_notebook_mode, iplot\ninit_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nimport os,random, math, psutil, pickle\n\nfrom time import time\nimport datetime\npd.set_option('display.max_columns',100)\npd.set_option('display.float_format', lambda x: '%.5f' % x)\n\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split,KFold\nfrom sklearn import metrics\nfrom sklearn.metrics import mean_squared_error\nimport lightgbm as lgb\n\nroot = '../input/ashrae-energy-prediction'\nprint(os.listdir(root))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Then we upload the dataframes. \nWe parse the datetime data and use specific dtypes for the building and weather dataframe. \nAlso for the test dataframe we select to read especific columns."},{"metadata":{"_cell_guid":"","_uuid":"","trusted":true},"cell_type":"code","source":"train = pd.read_csv(root + \"/train.csv\", parse_dates=['timestamp'])\n\nweather_train = pd.read_csv(root+\"/weather_train.csv\",parse_dates=['timestamp'])\n\ntest_cols_to_read = ['building_id','meter','timestamp']\ntest = pd.read_csv(root+\"/test.csv\",parse_dates=['timestamp'],usecols=test_cols_to_read)\n\nweather_test = pd.read_csv(root + \"/weather_test.csv\", parse_dates=['timestamp'])\n\nbuilding_meta = pd.read_csv(root + \"/building_metadata.csv\")\n\nsample_submission = pd.read_csv(root + \"/sample_submission.csv\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now we take a look of the size of the tables:"},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Size of train data', train.shape)\nprint('Size of weather_train data', weather_train.shape)\nprint('Size of weather_test data', weather_test.shape)\nprint('Size of building_meta data', building_meta.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Timestamps Adjustments"},{"metadata":{"trusted":true},"cell_type":"code","source":"weather = pd.concat([weather_train,weather_test],ignore_index=True)\nweather_key = ['site_id', 'timestamp']\ntemp_skeleton = weather[weather_key + ['air_temperature']].drop_duplicates(subset=weather_key).sort_values(by=weather_key).copy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_to_plot = temp_skeleton.copy()\ndata_to_plot[\"hour\"] = data_to_plot[\"timestamp\"].dt.hour\ncount = 1\nplt.figure(figsize=(25, 15))\nfor site_id, data_by_site in data_to_plot.groupby('site_id'):\n    by_site_by_hour = data_by_site.groupby('hour').mean()\n    ax = plt.subplot(4, 4, count)\n    plt.plot(by_site_by_hour.index,by_site_by_hour['air_temperature'],'xb-')\n    ax.set_title('site: '+str(site_id))\n    count += 1\nplt.tight_layout()\nplt.show()\ndel data_to_plot","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* We calculate ranks of hourly temperatures within date/site_id chunks.\n* Then create a dataframe of site_ids (0-16) x mean hour rank of temperature within day (0-23).\n* And we subtract the columnID of temperature peak by 14, getting the timestamp alignment gap.\n* Finally we do a function to align the timestamps."},{"metadata":{"trusted":true},"cell_type":"code","source":"temp_skeleton['temp_rank'] = temp_skeleton.groupby(['site_id', temp_skeleton.timestamp.dt.date])['air_temperature'].rank('average')\n\ndf_2d = temp_skeleton.groupby(['site_id', temp_skeleton.timestamp.dt.hour])['temp_rank'].mean().unstack(level=1)\n\nsite_ids_offsets = pd.Series(df_2d.values.argmax(axis=1) - 14)\nsite_ids_offsets.index.name = 'site_id'\n\ndef timestamp_align(df):\n    df['offset'] = df.site_id.map(site_ids_offsets)\n    df['timestamp_aligned'] = (df.timestamp - pd.to_timedelta(df.offset, unit='H'))\n    df['timestamp'] = df['timestamp_aligned']\n    del df['timestamp_aligned']\n    return df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We reduce the memory size. \nFunction to reduce the DF size:"},{"metadata":{"trusted":true},"cell_type":"code","source":"def reduce_mem_usage(df, verbose=True):\n    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']\n    start_mem = df.memory_usage().sum() / 1024**2    \n    for col in df.columns:\n        col_type = df[col].dtypes\n        if col_type in numerics:\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    end_mem = df.memory_usage().sum() / 1024**2\n    if verbose: print('Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction)'.format(end_mem, 100 * (start_mem - end_mem) / start_mem))\n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"building_site_dict = dict(zip(building_meta['building_id'], building_meta['site_id']))\nsite_meter_raw = train[['building_id', 'meter', 'timestamp', 'meter_reading']].copy()\nsite_meter_raw['site_id'] = site_meter_raw.building_id.map(building_site_dict)\ndel site_meter_raw['building_id']\nsite_meter_to_plot = site_meter_raw.copy()\nsite_meter_to_plot[\"hour\"] = site_meter_to_plot[\"timestamp\"].dt.hour\nelec_to_plot = site_meter_to_plot[site_meter_to_plot.meter == 0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"count = 1\nplt.figure(figsize=(25, 50))\nfor site_id, data_by_site in elec_to_plot.groupby('site_id'):\n    by_site_by_hour = data_by_site.groupby('hour').mean()\n    ax = plt.subplot(15, 4, count)\n    plt.plot(by_site_by_hour.index,by_site_by_hour['meter_reading'],'xb-')\n    ax.set_title('site: '+str(site_id))\n    count += 1\nplt.tight_layout()\nplt.show()\ndel elec_to_plot, site_meter_to_plot, building_site_dict, site_meter_raw","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Reducing memory:**"},{"metadata":{"trusted":true},"cell_type":"code","source":"train = reduce_mem_usage(train)\ntest = reduce_mem_usage(test)\nweather_train = reduce_mem_usage(weather_train)\nweather_test = reduce_mem_usage(weather_test)\nbuilding_meta = reduce_mem_usage(building_meta)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train = timestamp_align(weather_train)\nweather_test = timestamp_align(weather_test)\ndel weather","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We review the dataframes:"},{"metadata":{"trusted":true},"cell_type":"code","source":"print('train info',train.info())\nprint('-------------------')\nprint('weather_train info', weather_train.info())\nprint('-------------------')\nprint('test info', test.info()) \nprint('-------------------')\nprint('weather_test info', weather_test.info())\nprint('-------------------')\nprint('building info', building_meta.info())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Exploratory Data Analysis\n## Looking for missing values\n\nWe see the basic statistical measures of the dataframes:"},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.describe(include='all')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Data contains records from 1st Jan to 31st Dec of 2016.\n* Data has information about 1448 buildings.\n* Data has 4 meter types.\n* Some extremely high values in meter reading which can be explored further."},{"metadata":{"trusted":true},"cell_type":"code","source":"test.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test.describe(include='all')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Time period in **test data** is 2017 and 2018\n* We see that the test data points are a bit more than the double of the train data points..."},{"metadata":{},"cell_type":"markdown","source":"We check for missing values on the test and train dataframes:"},{"metadata":{"trusted":true},"cell_type":"code","source":"missing_train_test = pd.DataFrame(train.isna().sum()/len(train),columns=[\"Missing_Pct_Train\"])\nmissing_train_test[\"Missing_Pct_Test\"] = test.isna().sum()/len(test)\nmissing_train_test","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"No Missing values in train/test datasets"},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta.describe(include='all')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"*For the building metadata we see:*\n* There are only 16 different primary uses and Education is the most frecuent with 549 apperances. \n* For the square feet the maximum is 875000 and the minimum is 283.\n* For the year built there is a range between 1900 till 2017. \n* For the floor count the average and median coincide in 3 floors; we see that the maximum floor count is 26.\n* And that there are some missing values for the year_built and floor_count columns."},{"metadata":{},"cell_type":"markdown","source":"We divide the number of missing values by the overall number of values to see which columns have missing values:"},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta.isna().sum()/len(building_meta)*100","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train.describe()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_test.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_test.describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* We see that almost all columns have missing values on the weather's datasets.\n* For the columns cloud_coverage and precip_depth_1_hr we see a lot of values = 0.\n\nWe divide the number of missing values by the overall number of values to compare the number of missing values in Weather_Train and Weather_Test:"},{"metadata":{"trusted":true},"cell_type":"code","source":"missing_weather = pd.DataFrame(weather_train.isna().sum()/len(weather_train)*100,columns=[\"Weather_Train_Missing_Pct\"]) \nmissing_weather[\"Weather_Test_Missing_Pct\"] = weather_test.isna().sum()/len(weather_test)*100 \nmissing_weather","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* **precip_depth_1_hr variable** and **cloud_coverage variable** have similar number of missing values in both train and test weather data.\n* site_id and timestamp do not have missing values.\n* Other variables have some missing values."},{"metadata":{},"cell_type":"markdown","source":"### Calculating Min_value and Max_value of the columns in Weather_train:"},{"metadata":{"trusted":true},"cell_type":"code","source":"cols = ['air_temperature','cloud_coverage','dew_temperature','precip_depth_1_hr','sea_level_pressure','wind_direction','wind_speed']\nfor col in cols:\n    print (\" Minimum Value of {} column is {}\".format(col,weather_train[col].min()))\n    print (\" Maximum Value of {} column is {}\".format(col,weather_train[col].max()))\n    print (\"----------------------------------------------------------------------\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train['timestamp'].describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> This data is from 31st Dec 2015 to 31st Dec 2016, similar to the timestamp of the training data"},{"metadata":{"trusted":true},"cell_type":"code","source":"#creating a distplot of columns air_temperature,cloud_coverage,dew_temperature,precip_depth_1_hr,sea_level_pressure,wind_speed\ncols = ['air_temperature','cloud_coverage','dew_temperature','precip_depth_1_hr','sea_level_pressure','wind_speed']\nfor ind,col in enumerate(weather_train[cols]):\n    plt.figure(ind)\n    sns.distplot(weather_train[col].dropna())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Cloud_Coverage takes distinct values unlike these other variables.\n* Dew Temperature looks like a Negatively skewed distribution.\n* Lot of 0 values in precip_depth_1_hr variable.\n* Distribution of sea_level_pressure looks like a normal distribution.\n* Wind_Speed distribution looks like positively skewed."},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_test['timestamp'].describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> The time duration is similar to the test dataset."},{"metadata":{},"cell_type":"markdown","source":"# Dealing with missing values "},{"metadata":{},"cell_type":"markdown","source":"**Before we start filling missing values, we drop floor_count column as it has more than 75% missing values.** \n> It will manipulate the training data into a different direction if we impute it.<br /> \n> Also,year_built also has a large number of missing columns, but we leave it for now."},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta.drop('floor_count',axis=1,inplace=True)\nbuilding_meta.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### We fill out the missing values in the weather columns both in train and test\n\nAs we read so many popular tutorials and suggestion, there are few main solutions to fill in the missing values.\n1. Just ignore the data row \n2. Back-fill or forward-fill to propagate next or previous values respectively\n3. Replace with some constant value outside fixed value range-999,-1 etc.\n4. Replace with mean or median value. \n\n> Most of tutorials implement the way 'the daily mean of each site per month'. It had been proven the most logical and proven method so far.<br /> \n> We will fill with the mean of the filler object created by grouping site_id, day and month if daily means per month / site_id is not available.\n--Ref2 and Ref3 <br />"},{"metadata":{},"cell_type":"markdown","source":"First, we do for the **building part**:"},{"metadata":{"trusted":true},"cell_type":"code","source":"# since NA values only present in building age fillna can be used\nbuilding_meta.fillna(round(building_meta.year_built.mean(),0),\n                inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta.head()\nbuilding_meta.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We had quite a deal of missing values in the training and testing dataset, except site_id and time_stamp. "},{"metadata":{},"cell_type":"markdown","source":"First We deal with wheather_train"},{"metadata":{"trusted":true},"cell_type":"code","source":"# add month, day of week, day of month and hour \nweather_train['month'] = weather_train['timestamp'].dt.month.astype(np.int8)\nweather_train['day_of_week'] = weather_train['timestamp'].dt.dayofweek.astype(np.int8)\nweather_train['day_of_month']= weather_train['timestamp'].dt.day.astype(np.int8)\nweather_train['hour'] = weather_train['timestamp'].dt.hour\n\n# add is weekend column\nweather_train['is_weekend'] = weather_train.day_of_week.apply(lambda x: 1 if x>=5 else 0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def convert_season(month):\n    if (month <= 2) | (month == 12):\n        return 0\n    # as winter\n    elif month <= 5:\n        return 1\n    # as spring\n    elif month <= 8:\n        return 2\n    # as summer\n    elif month <= 11:\n        return 3\n    # as fall","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train['season'] = weather_train.month.apply(convert_season)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Reset Index for Update for training \nweather_train = weather_train.set_index(\n    ['site_id','day_of_month','month'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Air temperature**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of daily means per site id \nair_temperature_filler = pd.DataFrame(weather_train\n                                      .groupby(['site_id','day_of_month','month'])\n                                      ['air_temperature'].mean(),\n                                      columns=[\"air_temperature\"])\nair_temperature_filler.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of air_temperatures to fill\ntemporary_df = pd.DataFrame({'air_temperature' : weather_train.air_temperature})\n\n# update NA air_temperature values\ntemporary_df.update(air_temperature_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_train[\"air_temperature\"] = temporary_df[\"air_temperature\"]\n\ndel temporary_df, air_temperature_filler\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Cloud Coverage**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of daily means per site id\ncloud_coverage_filler = pd.DataFrame(weather_train\n                                     .groupby(['site_id','day_of_month','month'])\n                                     ['cloud_coverage'].mean(),\n                                     columns = ['cloud_coverage'])\ncloud_coverage_filler.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Because cloud_coverage takes discrete values and still have some NA value, I will fill it again with rounded mean"},{"metadata":{"trusted":true},"cell_type":"code","source":"round(cloud_coverage_filler.cloud_coverage.mean(),0)\ncloud_coverage_filler.fillna(round(cloud_coverage_filler.cloud_coverage.mean(),0), \n                             inplace=True)\n\n# create dataframe of cloud_coverages to fill\ntemporary_df = pd.DataFrame({'cloud_coverage' : weather_train.cloud_coverage})\n\n# update NA cloud_coverage values\ntemporary_df.update(cloud_coverage_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_train[\"cloud_coverage\"] = temporary_df[\"cloud_coverage\"]\n\ndel temporary_df, cloud_coverage_filler\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Dew Temperature**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of daily means per site id\ndew_temperature_filler = pd.DataFrame(weather_train\n                                      .groupby(['site_id','day_of_month','month'])\n                                      ['dew_temperature'].mean(),\n                                      columns=[\"dew_temperature\"])\ndew_temperature_filler.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of dew_temperatures to fill\ntemporary_df = pd.DataFrame({'dew_temperature' : weather_train.dew_temperature})\n\n# update NA dew_temperature values\ntemporary_df.update(dew_temperature_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_train[\"dew_temperature\"] = temporary_df[\"dew_temperature\"]\n\ndel temporary_df, dew_temperature_filler\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Precip Depth 1 Hour**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of daily means per site id\nprecip_depth_filler = pd.DataFrame(weather_train\n                                   .groupby(['site_id','day_of_month','month'])\n                                   ['precip_depth_1_hr'].mean(),\n                                   columns=['precip_depth_1_hr'])\nprecip_depth_filler.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As cloud_coverage, I fill NA values of the filler with the rounded mean since the discrete values and still got some NA"},{"metadata":{"trusted":true},"cell_type":"code","source":"round(precip_depth_filler['precip_depth_1_hr'].mean(),0)\nprecip_depth_filler.fillna(round(precip_depth_filler['precip_depth_1_hr'].mean(),0)\n                           , inplace=True)\n\n# create dataframe of precip_depth_1_hr to fill\ntemporary_df = pd.DataFrame({'precip_depth_1_hr' : weather_train.precip_depth_1_hr})\n\n# update NA precip_depth_1_hr values\ntemporary_df.update(precip_depth_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_train[\"precip_depth_1_hr\"] = temporary_df[\"precip_depth_1_hr\"]\n\ndel precip_depth_filler, temporary_df\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Sea Level Pressure**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of daily means per site id\nsea_level_filler = pd.DataFrame(weather_train\n                                .groupby(['site_id','day_of_month','month'])\n                                ['sea_level_pressure'].mean(),\n                                columns=['sea_level_pressure'])\nsea_level_filler.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We did the same as with cloud_coverage:"},{"metadata":{"trusted":true},"cell_type":"code","source":"mean_sea_level_pressure = round(\n    sea_level_filler\n    ['sea_level_pressure']\n    .astype(float)\n    .mean(),2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sea_level_filler.fillna(mean_sea_level_pressure, inplace=True)\n\n# create dataframe of sea_level_pressure to fill\ntemporary_df = pd.DataFrame({'sea_level_pressure' : weather_train.sea_level_pressure})\n\n# update NA sea_level_pressure values\ntemporary_df.update(sea_level_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_train[\"sea_level_pressure\"] = temporary_df[\"sea_level_pressure\"]\n\ndel sea_level_filler, temporary_df\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Wind Direction**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of daily means per site id\nwind_direction_filler = pd.DataFrame(weather_train\n                                     .groupby(['site_id','day_of_month','month'])\n                                     ['wind_direction'].mean(),\n                                     columns=['wind_direction'])\nwind_direction_filler.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of wind_direction to fill\ntemporary_df = pd.DataFrame({'wind_direction' : weather_train.wind_direction})\n\n# update NA wind_direction values\ntemporary_df.update(wind_direction_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_train[\"wind_direction\"] = temporary_df[\"wind_direction\"]\n\ndel temporary_df, wind_direction_filler\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Wind Speed**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of daily means per site id\nwind_speed_filler = pd.DataFrame(weather_train\n                                 .groupby(['site_id','day_of_month','month'])\n                                 ['wind_speed'].mean(),\n                                 columns=['wind_speed'])\nwind_speed_filler.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# create dataframe of wind_speed to fill\ntemporary_df = pd.DataFrame({'wind_speed' : weather_train.wind_speed})\n\n# update NA wind_speed values\ntemporary_df.update(wind_speed_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_train[\"wind_speed\"] = temporary_df[\"wind_speed\"]\n\ndel temporary_df, wind_speed_filler\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# check if NA values left\nweather_train.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We reset indexes to transfrom weather dataframe to original form:"},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train = weather_train.reset_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train.drop('day_of_month',axis=1,inplace=True)\nweather_train.drop('month',axis=1,inplace=True)\nweather_train.drop('day_of_week',axis=1,inplace=True)\nweather_train.drop('hour',axis=1,inplace=True)\nweather_train.drop('is_weekend',axis=1,inplace=True)\nweather_train.drop('season',axis=1,inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train.sample(5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":" Repeat again for wheather_test"},{"metadata":{"trusted":true},"cell_type":"code","source":"# add month, day of week, day of month and hour \nweather_test['month'] = weather_test['timestamp'].dt.month.astype(np.int8)\nweather_test['day_of_week'] = weather_test['timestamp'].dt.dayofweek.astype(np.int8)\nweather_test['day_of_month']= weather_test['timestamp'].dt.day.astype(np.int8)\nweather_test['hour'] = weather_test['timestamp'].dt.hour\n\n# add is weekend column\nweather_test['is_weekend'] = weather_test.day_of_week.apply(lambda x: 1 if x>=5 else 0)\n\nweather_test['season'] = weather_test.month.apply(convert_season)\n\n#Reset Index for Update for training \nweather_test = weather_test.set_index(\n    ['site_id','day_of_month','month'])\n\n#Air temperature\n\n\n# create dataframe of daily means per site id \nair_temperature_filler = pd.DataFrame(weather_test\n                                      .groupby(['site_id','day_of_month','month'])\n                                      ['air_temperature'].mean(),\n                                      columns=[\"air_temperature\"])\nair_temperature_filler.isna().sum()\n\n# create dataframe of air_temperatures to fill\ntemporary_df = pd.DataFrame({'air_temperature' : weather_test.air_temperature})\n\n# update NA air_temperature values\ntemporary_df.update(air_temperature_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_test[\"air_temperature\"] = temporary_df[\"air_temperature\"]\n\ndel temporary_df, air_temperature_filler\ngc.collect()\n\n#Cloud Coverage\n\n# create dataframe of daily means per site id\ncloud_coverage_filler = pd.DataFrame(weather_test\n                                     .groupby(['site_id','day_of_month','month'])\n                                     ['cloud_coverage'].mean(),\n                                     columns = ['cloud_coverage'])\ncloud_coverage_filler.isna().sum()\n\n#Because cloud_coverage takes discrete values and still have some NA value, I will fill it again with rounded mean\n\nround(cloud_coverage_filler.cloud_coverage.mean(),0)\ncloud_coverage_filler.fillna(round(cloud_coverage_filler.cloud_coverage.mean(),0), \n                             inplace=True)\n\n# create dataframe of cloud_coverages to fill\ntemporary_df = pd.DataFrame({'cloud_coverage' : weather_test.cloud_coverage})\n\n# update NA cloud_coverage values\ntemporary_df.update(cloud_coverage_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_test[\"cloud_coverage\"] = temporary_df[\"cloud_coverage\"]\n\ndel temporary_df, cloud_coverage_filler\ngc.collect()\n\n#Dew Temperature\n\n# create dataframe of daily means per site id\ndew_temperature_filler = pd.DataFrame(weather_test\n                                      .groupby(['site_id','day_of_month','month'])\n                                      ['dew_temperature'].mean(),\n                                      columns=[\"dew_temperature\"])\ndew_temperature_filler.isna().sum()\n\n# create dataframe of dew_temperatures to fill\ntemporary_df = pd.DataFrame({'dew_temperature' : weather_test.dew_temperature})\n\n# update NA dew_temperature values\ntemporary_df.update(dew_temperature_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_test[\"dew_temperature\"] = temporary_df[\"dew_temperature\"]\n\ndel temporary_df, dew_temperature_filler\ngc.collect()\n\n#Precip Depth 1 Hour\n\n# create dataframe of daily means per site id\nprecip_depth_filler = pd.DataFrame(weather_test\n                                   .groupby(['site_id','day_of_month','month'])\n                                   ['precip_depth_1_hr'].mean(),\n                                   columns=['precip_depth_1_hr'])\nprecip_depth_filler.isna().sum()\n\n#As cloud_coverage, I fill NA values of the filler with the rounded mean since the discrete values and still got some NA\n\n\nround(precip_depth_filler['precip_depth_1_hr'].mean(),0)\nprecip_depth_filler.fillna(round(precip_depth_filler['precip_depth_1_hr'].mean(),0)\n                           , inplace=True)\n\n# create dataframe of precip_depth_1_hr to fill\ntemporary_df = pd.DataFrame({'precip_depth_1_hr' : weather_test.precip_depth_1_hr})\n\n# update NA precip_depth_1_hr values\ntemporary_df.update(precip_depth_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_test[\"precip_depth_1_hr\"] = temporary_df[\"precip_depth_1_hr\"]\n\ndel precip_depth_filler, temporary_df\ngc.collect()\n\n#Sea Level Pressure\n\n# create dataframe of daily means per site id\nsea_level_filler = pd.DataFrame(weather_test\n                                .groupby(['site_id','day_of_month','month'])\n                                ['sea_level_pressure'].mean(),\n                                columns=['sea_level_pressure'])\nsea_level_filler.isna().sum()\n\n#We did the same as with cloud_coverage:\n\nmean_sea_level_pressure = round(\n    sea_level_filler\n    ['sea_level_pressure']\n    .astype(float)\n    .mean(),2)\n\nsea_level_filler.fillna(mean_sea_level_pressure, inplace=True)\n\n# create dataframe of sea_level_pressure to fill\ntemporary_df = pd.DataFrame({'sea_level_pressure' : weather_test.sea_level_pressure})\n\n# update NA sea_level_pressure values\ntemporary_df.update(sea_level_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_test[\"sea_level_pressure\"] = temporary_df[\"sea_level_pressure\"]\n\ndel sea_level_filler, temporary_df\ngc.collect()\n\n#Wind Direction\n\n# create dataframe of daily means per site id\nwind_direction_filler = pd.DataFrame(weather_test\n                                     .groupby(['site_id','day_of_month','month'])\n                                     ['wind_direction'].mean(),\n                                     columns=['wind_direction'])\nwind_direction_filler.isna().sum()\n\n# create dataframe of wind_direction to fill\ntemporary_df = pd.DataFrame({'wind_direction' : weather_test.wind_direction})\n\n# update NA wind_direction values\ntemporary_df.update(wind_direction_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_test[\"wind_direction\"] = temporary_df[\"wind_direction\"]\n\ndel temporary_df, wind_direction_filler\ngc.collect()\n\n#Wind Speed\n\n\n# create dataframe of daily means per site id\nwind_speed_filler = pd.DataFrame(weather_test\n                                 .groupby(['site_id','day_of_month','month'])\n                                 ['wind_speed'].mean(),\n                                 columns=['wind_speed'])\nwind_speed_filler.isna().sum()\n\n# create dataframe of wind_speed to fill\ntemporary_df = pd.DataFrame({'wind_speed' : weather_test.wind_speed})\n\n# update NA wind_speed values\ntemporary_df.update(wind_speed_filler, overwrite=False)\n\n# update in the weather train dataset\nweather_test[\"wind_speed\"] = temporary_df[\"wind_speed\"]\n\ndel temporary_df, wind_speed_filler\ngc.collect()\n\n# check if NA values left\nweather_test.isna().sum()\n\n#We reset indexes to transfrom weather dataframe to original form:\n\nweather_test = weather_test.reset_index()\n\nweather_test.drop('day_of_month',axis=1,inplace=True)\nweather_test.drop('month',axis=1,inplace=True)\nweather_test.drop('day_of_week',axis=1,inplace=True)\nweather_test.drop('hour',axis=1,inplace=True)\nweather_test.drop('is_weekend',axis=1,inplace=True)\nweather_test.drop('season',axis=1,inplace=True)\n\nweather_test.sample(5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## We merge train data (train, building, weather) into 1 dataframe:"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total = pd.merge(train,building_meta,how='left',on='building_id')\ntrain_total = pd.merge(train_total,weather_train,how='left',on=[\"site_id\", \"timestamp\"])\ntrain_total.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total.sample(5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## We merge test data (train, building, weather) into 1 dataframe:"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_total = pd.merge(test,building_meta,how='left',on='building_id')\ntest_total = pd.merge(test_total,weather_test,how='left',on=[\"site_id\", \"timestamp\"])\n\ntest_total.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_total.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Looking for unique values"},{"metadata":{"trusted":true},"cell_type":"code","source":"def feat_value_count(df,colname):\n    \"\"\"value count of each feature\n    \n    Args\n    df: data frame.\n    colname: string. Name of to be valued column\n    \n    Returns\n    df_count: data frame.\n    \"\"\"\n    df_count = df[colname].value_counts().to_frame().reset_index()\n    df_count = df_count.rename(columns={'index':colname+'_values',colname:'counts'})\n    return df_count\n\nfeat_value_count(train,'building_id')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"A total of 1449 buildings are in **train data**. Building 1298,1249 has the most records and building 403 has the least records."},{"metadata":{"trusted":true},"cell_type":"code","source":"feat_value_count(test,'building_id')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"A total of 1449 buildings are in **test data**. Buildings 1258,1241,1331,1301... have the most records and building 0,666,667,668,669... have the least records. Many buildings have same amout of records. Maybe make sense to check the distribution."},{"metadata":{"trusted":true},"cell_type":"code","source":"len(set(train.building_id) & set(test.building_id))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We use the function **set()** and the command **&** so that we identify the intersection between the train and the test dataframes. We need to predict all 1449 building meter readings. All buildings that need to be predicted appear in train data."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total['meter'].replace({0:\"Electricity\",1:\"ChilledWater\",2:\"Steam\",3:\"HotWater\"},inplace=True)\ntest_total['meter'].replace({0:\"Electricity\",1:\"ChilledWater\",2:\"Steam\",3:\"HotWater\"},inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"feat_value_count(train_total,'meter')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.countplot(train_total['meter'])\nplt.title(\"Distribution of Meter Id Code\")\nplt.xlabel(\"Meter Id Code\")\nplt.ylabel(\"Frequency\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Not every building has all meter types. Electricity has the most records."},{"metadata":{"trusted":true},"cell_type":"code","source":"feat_value_count(weather_train,'site_id')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are 15 locations according to the weather data"},{"metadata":{"trusted":true},"cell_type":"code","source":"feat_value_count(building_meta,'primary_use')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(8,6))\nbuilding_meta['primary_use'].value_counts().sort_values().plot(kind='bar')\nplt.title(\"Count of Primary_Use Variable in the Metadata table\")\nplt.xlabel(\"Primary Use\")\nplt.ylabel(\"Count\")\nplt.xticks(rotation=90)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* There are 15 primary use of buildings. \n* Most buildings are for education, the least is for religious worship. \n* Education, Office, Entertainment/Public Assembly, Public Services, Lodging/Residential form the bulk of Primary Use. \n* Education and office occupies 57% of all buildings."},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta['primary_use'].value_counts(normalize=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> Since there are a lot of categories which are a minor percentage of the whole, it makes sense to combine them.\n\nWe therefore combine all categories with minor percentage:"},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta['primary_use'].replace({\"Healthcare\":\"Other\",\"Parking\":\"Other\",\"Warehouse/storage\":\"Other\",\"Manufacturing/industrial\":\"Other\",\n                                \"Retail\":\"Other\",\"Services\":\"Other\",\"Technology/science\":\"Other\",\"Food sales and service\":\"Other\",\n                                \"Utility\":\"Other\",\"Religious worship\":\"Other\"},inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"feat_value_count(building_meta,'site_id')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.countplot(building_meta['site_id'])\nplt.title(\"Count of Site_id in the Metadata table\")\nplt.xlabel(\"Site_Id\")\nplt.ylabel(\"Count\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Out of 1449 buildings and 15 sites, site 3 has most buildings."},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta['square_feet'].describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**We created distplot of Distribution of Square Feet variable of Metadata Table**"},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.distplot(building_meta['square_feet'])\nplt.title(\"Distribution of Square Feet variable of Metadata Table\")\nplt.xlabel(\"Area in Square Feet\")\nplt.ylabel(\"Frequency\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Looks like a normal distribution distribution."},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta['square_feet'] = np.log1p(building_meta['square_feet'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta.groupby('primary_use')['square_feet'].agg(['mean','median','count']).sort_values(by='count')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We obtain the mean, median, count of grouped by columns primary_use, square_feet:\n* Others (Parking) has the highest average although the count is less.\n* Education has the highest count as can be seen in the countplot above."},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta['year_built'].value_counts().sort_values().plot(kind='bar',figsize=(15,6))\nplt.xlabel(\"Year Built\")\nplt.ylabel(\"Count\")\nplt.title(\"Distribution of Year Built Variable\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"building_meta.groupby('primary_use')['square_feet'].agg(['count','mean','median']).sort_values(by='count')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cols = ['site_id','primary_use','building_id','year_built']\nfor col in cols:\n    print (\"Number of Unique Values in the {} column are:\".format(col),building_meta[col].nunique())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Now we take a single building 1258 to analyze the meter variable (our target):"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_one_building = train_total[train_total.building_id == 1258]\ndf_one_building.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.lineplot(x='timestamp',y='meter_reading',data=df_one_building[train_total.meter == 'Electricity']).set_title('electricity of building 1258')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"With a Electricity lineplot we see that **in spring**, less electricity is used."},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.lineplot(x='timestamp',y='meter_reading',data=df_one_building[train_total.meter == 'ChilledWater']).set_title('chilledwater of building 1258')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"With a Chilled water lineplot we see that **in summer**, more chilled water is used."},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.lineplot(x='timestamp',y='meter_reading',data=df_one_building[train_total.meter == 'Steam']).set_title('steam of building 1258')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In winter, more steam is used for heating."},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.lineplot(x='timestamp',y='meter_reading',data=df_one_building[train_total.meter == 'HotWater']).set_title('hotwater of building 1258')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In summmer there is very low consumption of hot water, but in winter very high consumption."},{"metadata":{"trusted":true},"cell_type":"code","source":"df_lots_building = train_total[train_total['building_id'].isin([1258,1298,1249])]\nmeasures = ['Electricity', 'ChilledWater', 'Steam', 'HotWater']\nfor i in measures:\n    f, ax = plt.subplots(figsize=(15, 6))\n    sns.lineplot(x='timestamp',y='meter_reading', hue = 'building_id',legend='brief',\n             data=df_lots_building[df_lots_building.meter == i]);\n#del df_lots_building\n#gc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In Multiple buildings the patterns of energy consumption is quite consistent. Building 1258 has the highest consumption."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total.groupby('meter')['meter_reading'].agg(['min','max','mean','median','count','std'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We can see that Steam meter has some values that are very high maximum values, we have to explore further. \nMinimum value for all 4 types of meter is 0."},{"metadata":{"trusted":true},"cell_type":"code","source":"for df in [train_total, test_total]:\n    df['Month'] = df['timestamp'].dt.month.astype(\"uint8\")\n    df['DayOfMonth'] = df['timestamp'].dt.day.astype(\"uint8\")\n    df['DayOfWeek'] = df['timestamp'].dt.dayofweek.astype(\"uint8\")\n    df['Hour'] = df['timestamp'].dt.hour.astype(\"uint8\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Meter_reading is grouped by meter and month. Max, mean, median, count and std are calculated:"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total.groupby(['meter','Month'])['meter_reading'].agg(['max','mean','median','count','std'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* We can see that only Steam meter has very high meter_reading values as compared to other types of meters.\n* We can see that the average electricity meter_reading does not vary much across the months.\n* Average Hot Water meter_reading is relatively less from April to October Months.\n* Average Steam meter_reading is way higher from March to June as compared to the other months."},{"metadata":{},"cell_type":"markdown","source":"### Meter_reading is grouped by meter and dayofweek. Max, mean, median, count and std are calculated:"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total.groupby(['meter','DayOfWeek'])['meter_reading'].agg(['max','mean','median','count','std'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Average meter_reading of Steam type of meter is higher as compared to the other meter types."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total['meter_reading'].describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**We create a distplot Distribution of Log of Meter Reading Variable:**"},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.distplot(np.log1p(train_total['meter_reading']),kde=False)\nplt.title(\"Distribution of Log of Meter Reading Variable\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Lot of 0 values as can be seen from the distribution"},{"metadata":{},"cell_type":"markdown","source":"### Converting the dependent variable to logarithmic scale:"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total['meter_reading'] = np.log1p(train_total['meter_reading'])\nsns.distplot(train_total[train_total['meter'] == \"Electricity\"]['meter_reading'],kde=False)\nplt.title(\"Distribution of Meter Reading per MeterID code: Electricity\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.distplot(train_total[train_total['meter'] == \"ChilledWater\"]['meter_reading'],kde=False)\nplt.title(\"Distribution of Meter Reading per MeterID code: Chilledwater\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.distplot(train_total[train_total['meter'] == \"Steam\"]['meter_reading'],kde=False)\nplt.title(\"Distribution of Meter Reading per MeterID code: Steam\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.distplot(train_total[train_total['meter'] == \"HotWater\"]['meter_reading'],kde=False)\nplt.title(\"Distribution of Meter Reading per MeterID code: Hotwater\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> There is some discrepancy in the meter_readings for different ste_id's and buildings. It makes sense to delete them. Ref1"},{"metadata":{"trusted":true},"cell_type":"code","source":"idx_to_drop = list((train_total[(train_total['site_id'] == 0) & (train_total['timestamp'] < \"2016-05-21 00:00:00\")]).index)\ntrain_total.drop(idx_to_drop,axis='rows',inplace=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Method Kfold and LightGBM"},{"metadata":{},"cell_type":"markdown","source":"GBM stands for **Gradient Boosting Machine**. It is an ensamble model of decision trees that works on reducing the residual errors. The most time-consuming part is to find the best split points. \n\nLightGBM contains the techniques of **Gradient-based One-Side Sampling** and **Exclusive Feature Bundling** to deal with large number of data instances and large number of features respectively.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"def label_encoder(df, categorical_columns=None):\n    \"\"\"Encode categorical values as integers (0,1,2,3...) with pandas.factorize. \"\"\"\n    # if categorical_colunms are not given than treat object as categorical features\n    if not categorical_columns:\n        categorical_columns = [col for col in df.columns if df[col].dtype == 'object']\n    for col in categorical_columns:\n        df[col], uniques = pd.factorize(df[col])\n    return df, categorical_columns;","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total,colname = label_encoder(train_total, categorical_columns=['primary_use'])\ntest_total,colname = label_encoder(test_total, categorical_columns=['primary_use']);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Then we set a parameter:"},{"metadata":{"trusted":true},"cell_type":"code","source":"params = {'objective':'regression',\n          'boosting_type':'gbdt',\n          'metric':'rmse',\n          'learning_rate':0.1,\n          'num_leaves': 2**8,\n          'max_depth':-1,\n          'colsample_bytree':0.5,\n          'feature_fraction':0.7,\n          'subsample_freq':1,\n          'subsample':0.7,\n          'verbose':-1,\n          'num_threads':8,\n          'seed': 47,} ;\ncategory_cols = ['building_id', 'site_id', 'primary_use'];","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#%% create feature: age\ntrain_total['age'] = train_total['year_built'].max() - train_total['year_built'] + 1\ntest_total['age'] = test_total['year_built'].max() - test_total['year_built'] + 1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Label encoding: dealing with categorical variables."},{"metadata":{"trusted":true},"cell_type":"code","source":"le = LabelEncoder()\ntrain_total['primary_use'] = train_total['primary_use'].astype(str)\ntrain_total['primary_use'] = le.fit_transform(train_total['primary_use']).astype(np.int8)\n\ntest_total['primary_use'] = test_total['primary_use'].astype(str)\ntest_total['primary_use'] = le.fit_transform(test_total['primary_use']).astype(np.int8)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#%% divide time into columns of month,weekofyear,dayofyear... and log squarefeet in both training and testing data\n\ntrain_total['month_datetime'] = train_total['timestamp'].dt.month.astype(np.int8)\ntrain_total['weekofyear_datetime'] = train_total['timestamp'].dt.weekofyear.astype(np.int8)\ntrain_total['dayofyear_datetime'] = train_total['timestamp'].dt.dayofyear.astype(np.int16)\n    \ntrain_total['hour_datetime'] =train_total['timestamp'].dt.hour.astype(np.int8)  \ntrain_total['day_week'] = train_total['timestamp'].dt.dayofweek.astype(np.int8)\ntrain_total['day_month_datetime'] = train_total['timestamp'].dt.day.astype(np.int8)\ntrain_total['week_month_datetime'] = train_total['timestamp'].dt.day/7\ntrain_total['week_month_datetime'] = train_total['week_month_datetime'].apply(lambda x: math.ceil(x)).astype(np.int8)\n    \ntrain_total['year_built'] = train_total['year_built']-1900\ntrain_total['square_feet'] = np.log(train_total['square_feet'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_total['month_datetime'] = test_total['timestamp'].dt.month.astype(np.int8)\ntest_total['weekofyear_datetime'] = test_total['timestamp'].dt.weekofyear.astype(np.int8)\ntest_total['dayofyear_datetime'] = test_total['timestamp'].dt.dayofyear.astype(np.int16)\n    \ntest_total['hour_datetime'] = test_total['timestamp'].dt.hour.astype(np.int8)\ntest_total['day_week'] = test_total['timestamp'].dt.dayofweek.astype(np.int8)\ntest_total['day_month_datetime'] = test_total['timestamp'].dt.day.astype(np.int8)\ntest_total['week_month_datetime'] = test_total['timestamp'].dt.day/7\ntest_total['week_month_datetime'] = test_total['week_month_datetime'].apply(lambda x: math.ceil(x)).astype(np.int8)\n    \ntest_total['year_built'] = test_total['year_built']-1900\ntest_total['square_feet'] = np.log(test_total['square_feet'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total['meter']= le.fit_transform(train_total['meter']).astype(np.int8)\ntest_total['meter']= le.fit_transform(test_total['meter']).astype(np.int8)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#%% drop columns\n\nfrom tqdm import tqdm\ndrop_cols = [ \"sea_level_pressure\", \"wind_speed\",\"timestamp\"]\ntarget = np.log1p(train_total[\"meter_reading\"])  \ntrain_df = train_total.drop(drop_cols, axis=1)\ncategoricals = [\"site_id\", \"building_id\", \"primary_use\",  \"meter\",  \"wind_direction\"]\nnumericals = [\"square_feet\", \"year_built\", \"air_temperature\", \"cloud_coverage\",\n              \"dew_temperature\", 'precip_depth_1_hr']\nfeat_cols = categoricals + numericals","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#%% modeling\nfrom sklearn.model_selection import KFold, StratifiedKFold\nparams = {\n            'boosting_type': 'gbdt',\n            'objective': 'regression',\n            'metric': {'rmse'},\n            'subsample_freq': 1,\n            'learning_rate': 0.3,\n            'bagging_freq': 5,\n            'num_leaves': 330,\n            'feature_fraction': 0.9,\n            'lambda_l1': 1,  \n            'lambda_l2': 1\n            }\n\nfolds = 5\nseed = 666\nshuffle = False\nkf = KFold(n_splits=folds, shuffle=shuffle, random_state=seed)\n \nmodels = []\nfor train_index, val_index in kf.split(train_total[feat_cols], train_total['building_id']):\n    train_X = train_total[feat_cols].iloc[train_index]\n    val_X = train_total[feat_cols].iloc[val_index]\n    train_y = target.iloc[train_index]\n    val_y = target.iloc[val_index]\n    lgb_train = lgb.Dataset(train_X, train_y, categorical_feature=categoricals)\n    lgb_eval = lgb.Dataset(val_X, val_y, categorical_feature=categoricals)\n    gbm = lgb.train(params,\n                lgb_train,\n                num_boost_round=500,\n                valid_sets=(lgb_train, lgb_eval),\n                early_stopping_rounds=50,\n                verbose_eval = 50)\n    models.append(gbm)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#%%see which variables are the most relevant\nfeature_imp = pd.DataFrame(sorted(zip(gbm.feature_importance(), gbm.feature_name()),reverse = True), columns=['Value','Feature'])\nplt.figure(figsize=(10, 5))\nsns.barplot(x=\"Value\", y=\"Feature\", data=feature_imp.sort_values(by=\"Value\", ascending=False))\nplt.title('LightGBM FEATURES')\nplt.tight_layout()\nplt.show();","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_total = test_total[feat_cols]\ni=0\nres=[]\nstep_size = 50000\nfor j in tqdm(range(int(np.ceil(test_total.shape[0]/50000)))):\n    res.append(np.expm1(sum([model.predict(test_total.iloc[i:i+step_size]) for model in models])/folds))\n    i+=step_size \n\n#%% remove the columns that cannot be calculated in the test data and rerun the last step. DataFrame.dtypes for data must be int, float or bool.\n\nres = np.concatenate(res)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#%% submission. all the input array dimensions for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 100000 and the array at index 416 has size 97600\nsample_submission = pd.read_csv(root + \"/sample_submission.csv\")\nsample_submission['meter_reading'] = res\nsample_submission.loc[sample_submission['meter_reading']<0, 'meter_reading'] = 0\nsample_submission.to_csv('submission.csv', index=False)\n\n#%%\n#submission.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.chdir(r'/kaggle/working')\n#df_name.to_csv(r'df_name.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import FileLink\nFileLink(r'submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_total.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# Scores results\n[![Captura%20de%20Pantalla%202020-01-20%20a%20la%28s%29%2017.32.21.png](attachment:Captura%20de%20Pantalla%202020-01-20%20a%20la%28s%29%2017.32.21.png)](http://)","attachments":{"Captura%20de%20Pantalla%202020-01-20%20a%20la%28s%29%2017.32.21.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAvgAAADcCAYAAAAFgNXqAAABfGlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGAqSSwoyGFhYGDIzSspCnJ3UoiIjFJgv8PAzcDDIMRgxSCemFxc4BgQ4MOAE3y7xsAIoi/rgsxK8/x506a1fP4WNq+ZclYlOrj1gQF3SmpxMgMDIweQnZxSnJwLZOcA2TrJBUUlQPYMIFu3vKQAxD4BZIsUAR0IZN8BsdMh7A8gdhKYzcQCVhMS5AxkSwDZAkkQtgaInQ5hW4DYyRmJKUC2B8guiBvAgNPDRcHcwFLXkYC7SQa5OaUwO0ChxZOaFxoMcgcQyzB4MLgwKDCYMxgwWDLoMjiWpFaUgBQ65xdUFmWmZ5QoOAJDNlXBOT+3oLQktUhHwTMvWU9HwcjA0ACkDhRnEKM/B4FNZxQ7jxDLX8jAYKnMwMDcgxBLmsbAsH0PA4PEKYSYyjwGBn5rBoZt5woSixLhDmf8xkKIX5xmbARh8zgxMLDe+///sxoDA/skBoa/E////73o//+/i4H2A+PsQA4AJHdp4IxrEg8AAAGdaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA1LjQuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjc2MDwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4yMjA8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KJq1bxAAAQABJREFUeAHtnQWcXNXZ/5+4u7u7u5CQQNAADe5W2iItpbR9gbb/wosXKMVK30IJLgkBGgIJcTfi7u7u7v/7PcuZzM7O7s5KZGZ/z3525so55577vXfm/s5znnMm16nATCYCIiACIiACIiACIiACIpAQBHInxFnoJERABERABERABERABERABBwBCXzdCCIgAiIgAiIgAiIgAiKQQAQk8BPoYupUREAEREAEREAEREAEREACX/eACIiACIiACIiACIiACCQQAQn8BLqYOhUREAEREAEREAEREAERkMDXPSACIiACIiACIiACIiACCURAAj+BLqZORQREQAREQAREQAREQAQk8HUPiIAIiIAIiIAIiIAIiEACEZDAT6CLqVMRAREQAREQAREQAREQAQl83QMiIAIiIAIiIAIiIAIikEAEJPAT6GLqVERABERABERABERABERAAl/3gAiIgAiIgAiIgAiIgAgkEAEJ/AS6mDoVERABERABERABERABEZDA1z0gAiIgAiIgAiIgAiIgAglEQAI/gS6mTkUEREAEREAEREAEREAEJPB1D4iACIiACIiACIiACIhAAhGQwE+gi6lTEQEREAEREAEREAEREIG8WUVw7Ngx27Ztm+3evduKFStm5cuXtwIFCsRc7MaNG61w4cJWsmTJmPOklfD48eM2Y8YMq1u3rpUpUyatpGnuy65y0jxINu88efKkrV271ipUqGCFChVKUfrBgwdt69atoe1wh1GePHlC287FQnawzo4yzsW565giIAIikCgEjh49ajzTveXOndtKlSrltIHfltr7zJkz3a7WrVunluScbEfb7Nixw3jG8LzkP1euXOekLoly0KzcJ+EM0DsFCxZ0ujN8u1/2mgddit7Jjnssnu6HLAn8nTt32rBhw2zv3r1WvHhx954vXz7r2bOnE5keclrvEydOtAYNGmSbwD98+LDNmTPHihYtmiWBn13lpHXu2b0Pgc/1uPrqq6MKfMQ9+734P3TokKtCzZo17eKLL7a8ebN0O2T6dDLDeuHCha4hWadOHXfczJSR6QorowiIgAiIQAoCaAGeMZFWunRpu+qqq0LPnsj9rC9YsMBtzg6Bv2vXLldeo0aNMq0DeJ5OmzbN6Ynw+vK8vOiiiwytI8scgazcJ+FHHDJkiKEBevToEb45tIzzmfvxyiuvdAI/K/dYPN4PWVJ0U6ZMcaLwrrvuch9cWmU//PCDjR8/3m688cYQ5LO5gLD/5S9/aXgOsmLZ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ZdGN6Hs80ksfbT8eDM4rIwI6WjnRtlE2XV/Rrkl63DgvuGaUFV/adE/SiqbVTv5ox6e+8Eut5cv+7L5elCkTAREQARE4twToteb5lNazk2cUFqk9eG7wzEztuRJ+ZjxDcOqRNq1nWVrPSsqjjFg0RvixOUe812kdNzx9oi7Hoh+zooPQKVg0fRjJNLvuh/Tul8jjsp7R+yFbBH60imibCGSWQLjAz2wZyicCIiACIiACIiACOZVA1vrTcio1nfcZJYBHJqd7LM4oYBUuAiIgAiIgAiKQ0ATkwU/oy6uTEwEREAEREAEREAERyGkE5MHPaVdc5ysCIiACIiACIiACIpDQBCTwE/ry6uREQAREQAREQAREQARyGgEJ/Jx2xXW+IiACIiACIiACIiACCU1AAj+hL69OTgREQAREQAREQAREIKcRkMDPaVdc5ysCIiACIiACIiACIpDQBCTwE/ry6uREQAREQAREQAREQARyGgEJ/Jx2xXW+IiACIiACIiACIiACCU0g746dOxP6BHVyIiACIiACIiACIiACIpCTCOiHrnLS1da5ioAIiIAIiIAIiIAIJDwBhegk/CXWCYqACIiACIiACIiACOQkAhL4Oelq61xFQAREQAREQAREQAQSnoAEfsJfYp2gCIiACIiACIiACIhATiIggZ+TrrbOVQREQAREQAREQAREIOEJSOAn/CXWCYqACIiACIiACIiACOQkAhL4Oelq61xFQAREQAREQAREQAQSnoAEfsJfYp2gCIiACIiACIiACIhATiIggZ+TrrbOVQREQAREQAREQAREIOEJSOAn/CXWCYqACIiACIiACIiACOQkAhL4Oelq61xFQAREQAREQAREQAQSnoAEfsJfYp2gCIiACIiACIiACIhATiIggZ+TrrbOVQREQAREQAREQAREIOEJSOAn/CXWCYqACIiACIiACIiACOQkAhL4Oelq61xFQAREQAREQAREQAQSnkDec3WGOw4etUHLtlr7KiWtYdmi2VKNfUeO2y1fz7Tbm1WxO5tXyVKZH89eb18u2Gj9bmptRfOfM0xZOgdlFgEREAEREIFEJbBs2TLbsWOHNWnSxIoVKxbzaS5atMj27NljNWvWtIoVKybLt3PnTlu4cKEdOXLEGjRoYFWrVk22P3xl//79Nn/+fMuTJ4+1a9cufJeWzzGBjN4bq1ev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9ptpyx7p7rNGfc8T6c6PmkobRUAEREAEREAEREAEzjcCuYJYeu/ozVTd8LQjStOKv89owYhqqpXRMsmH8PUNhowcl14DHzLj83FuhOH4gbt492fOnGm33nqrT+LqyRiBaNODhhL9tEDvAgI/Mi09B3369LGrr7462SxAkfnTW2d6TExTW6ZHSvtFQAREQAREQAREIHEJZNqD75FEilW/PSvvsXqxI4+R2XyUEy12nmky8dgzLz6NB6bzDB90Sz4aFLEyoOERmZZGA4N8Cc0JHxRM2Rk1CfuMElN6ERABERABERABEUg8Aln24CcekuRnxLSVTLGJEVrjp+RMnirza/ywF40HwnSy0kDJfA2UUwREQAREQAREQAREIJEISOAn0tXUuYiACIiACIiACIiACOR4ApmeRSfHkxMAERABERABERABERABETgPCUjgn4cXRVUSAREQAREQAREQAREQgcwSkMDPLDnlEwEREAEREAEREAEREIHzkIAE/nl4UVQlERABERABERABERABEcgsAQn8zJJTPhEQAREQAREQAREQARE4DwlI4J+HF0VVEgEREAEREAEREAEREIHMEpDAzyw55RMBERABERABERABERCB85CABP55eFFUJREQAREQAREQAREQARHILAEJ/MySUz4REAEREAEREAEREAEROA8JSOCfhxdFVRIBERABERABERABERCBzBKQwM8sOeUTAREQAREQAREQAREQgfOQgAT+eXhRVCUREAEREAEREAEREAERyCwBCfzMklM+ERABERABERABERABETgPCeTNSp3mzZtnJUqUsOrVq4eKOX78uM2YMcMKFy5szZo1C233C+Q5cOCAXw2916pVyypUqBBaT21hypQpVr9+fStVqlTUJLt377bFixdb+/btLXdutV+iQtJGERABERABERABERCBhCWQJYH/73//2y644AK74447HKBTp07ZG2+8YWPHjrVXX301KjTyrFu3zjUMwhPcf//96Qp8yn/++eftqaeesnbt2oVnDy2vXr3aXnjhBfvmm28sf/78oe1aEAEREAEREAEREAEREIGcQCBLAj8S0Pvvv+/E/bPPPmsNGjSI3B1av/XWW0ONgtBGLYiACIiACIiACIiACIiACGSZQLYJfDzmAwYMsD/96U/WqlWrTFfs0KFDrpzp06dbgQIFXKjN1VdfbXny5Ila5sqVK23gwIFG6E/dunWtbdu2UdNpowiIgAiIgAiIgAiIgAjkBALZEqQ+atQo++ijj+yRRx5xITuZBXfixAl7+eWXbejQodalSxcXw//5559b7969oxa5ZcsW16DYtm2bXX/99bZr1y4XIhQ1sTaKgAiIgAiIgAiIgAiIQA4gkGUP/o8//mjEvVepUsV69OgREzI8/QzE9Uas/EsvvWTz5893299++22rUaOG212nTh0j5Oe6666zcuXK+SzunYZA6dKl7cknn3Tx9ldeeaU9/fTTycpOlkErIiACIiACIiACIiACIpDgBLIs8BH3nTp1ssmTJ1u/fv2M+Pr0rFGjRtahQ4dQMj8Ydvny5VatWrWQuCdB69atXboVK1akEPjLli1zg219fhIy+Da88eAy60UEREAEREAEREAEREAEcgiBLAt8BPgTTzxhhOm89dZbbnBtejH4THPZs2fPFIiJv2d6zXAj9r5QoULGvkhjW7i4Z3/BggUjk2ldBERABERABERABERABHIMgSzH4CPWEeGXXnqpXXTRRfa3v/3Ntm/fnimADJJdsmSJ7d+/P5R/7dq1TtzXrl07tM0v1KtXzw2uZfpMb3PmzPGLehcBERABERABERABERCBHEcgywI/nNhDDz3kYuKJp+cHrzJqTZs2tbJly9rrr79uhOssXLjQXnvtNdcrQOhOpDEQd9GiRcZA3I0bN9rEiRNt9OjRkcm0LgIiIAIiIAIiIAIiIAI5hkC2CnxCaZgmEy/8Z599lmGIRYsWdT9ktW/fPvv973/vQn9KlizpBtFGmyazSZMm9uijj9qQIUPsgQcesDfffNPuueced9xcuXJl+PjKIAIiIAIiIAIiIAIiIALxTiBXEN5yOr7lPDob4utz587t5sJPr1qcwp49e9yv40rYp0dL+0VABERABERABERABBKZwHkr8BMZus5NBERABERABERABERABM4UgWwN0TlTlVS5IiACIiACIiACIiACIiACsRGQwI+Nk1KJgAiIgAiIgAiIgAiIQFwQkMCPi8ukSoqACIiACIiACIiACIhAbAQk8GPjpFQiIAIiIAIiIAIiIAIiEBcEJPDj4jKpkiIgAiIgAiIgAiIgAiIQGwEJ/Ng4KZUIiIAIiIAIiIAIiIAIxAUBCfy4uEyqpAiIgAiIgAiIgAiIgAjERkACPzZOSiUCIiACIiACIiACIiACcUFAAj8uLpMqKQIiIAIiIAIiIAIiIAKxEZDAj42TUomACIiACIiACIiACIhAXBCQwI+Ly6RKioAIiIAIiIAIiIAIiEBsBCTwY+OkVCIgAiIgAiIgAiIgAiIQFwQk8OPiMqmSIiACIiACIiACIiACIhAbAQn82DgplQiIgAiIgAiIgAiIgAjEBYG8O3bujIuKqpIiIAIiIAIiIAIiIAIiIALpE8h1KrD0kymFCIiACIiACIiACIiACIhAPBBQiE48XCXVUQREQAREQAREQAREQARiJCCBHyMoJRMBERABERABERABERCBeCAggR8PV0l1FAEREAEREAEREAEREIEYCUjgxwhKyURABERABERABERABEQgHghI4MfDVVIdRUAEREAEREAEREAERCBGAhL4MYJSMhEQAREQAREQAREQARGIBwIS+PFwlVRHERABERABERABERABEYiRgAR+jKCUTAREQAREQAREQAREQATigYAEfjxcJdVRBERABERABERABERABGIkIIEfIyglEwEREAEREAEREAEREIF4ICCBHw9XSXUUAREQAREQAREQAREQgRgJSODHCErJREAEREAEREAEREAERCAeCEjgx8NVUh1FQAREQAREQAREQAREIEYCEvgxglIyERABERABERABERABEYgHAnkzW8kl2w/YlA27Us3esGxRa1+lZKr742HHzE177PHhi+3vlzayVpWKx0OVVUcREAEREAERyBEEli1bZjt27LAmTZpYsWLFYj7nRYsW2Z49e6xmzZpWsWJFl2/btm22YsWKqGVUq1bNqlSpEtq3f/9+W7JkiW3dutWVUa9ePcubN9NyKlSuFrKPQEbvjdWrVxt5ihQpYg0bNrTSpUunqMzOnTtt4cKFduTIEWvQoIFVrVo1RRruK9Js377datWqZU2bNk2R5mxtyPQd2Xf+Rnt6zNJU6/nzVtXOusBHkD8/brk9fkEd61g1642LiWt32ciV223C2p0S+Kleae0QAREQAREQgbNH4MCBA/bxxx/b4MGD3UFfeeUVa9SoUUwVWLdunT3++OMu7cMPPxwS+AsWLLB//OMfUcu455577MYbb3T7Vq5caU899ZRrIPjEzZo1s7/85S9WtGhRv0nv54hARu+NU6dO2Ycffmj9+/dPVuOnn37a2rRpE9o2e/Zs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sI0bN1qZMmWsXbt2VqlSpawUmem8Bw8eNH4euGTJkq6M1atX29q1a+3CCy/MdJlnOuOpU6esX79+ds0111jhwoWzdLjXJ6+y1yavtM37j1jtUoXttcsb21X1y2epzKxkPhmcG78i/OX8jbZy10HrVrOM/bFTbbuyXrmsFKu8IiACIiACIiACIiAC6RDIUojO0KFDrWDBgtarVy+rVauWff/993bkyJF0Dnlmdq9atcqmT58eKvzYsWNGA+R8tz179tjJkyezVM3P526wPwxdaP/bvb5N/VUX69Wwgl39xTRbuuPcnf+vvptnNDp+17GWDburgzUqW9R6fj7Vxq7ekaVzVWYREAEREAEREAEREIG0CWTag3/8+HErUqSI89rjfS5durTNnj3bduzYYZUrV0521M2bN9vWrVstV65ctmnTJqtatarVrFnT5syZY4cOHbIGDRpYlSpVXB688IsWLbItW7a4XgH2FS1a1O2bNGmSVatWzdasWWMnTpxw+SpWrGgbNmxweShr5MiRIa89HvLFixc7T36FChVcehokGA2ClStXWr58+axOnTqh47udP70gvKkL5WMNGza06tWru+XwfdSP+iPWmzdv7vbTq0H5NDRq1KhhtWvXdtujvWzfvt2mTZvm+NStW9fxYdvChQtD50K+WbNmuR4KGlPhNmzFducZ/2Xram5zq0rFrVrxQnYkCJHBpm/c47zpeNJbVChur17WyMoVyW/DVmyzMat3WrH8eez7pVvt8jrl7OH2NaxM4fwuHwNk3/hxlc3dss+61yxt/9utvhUJ0pJvVDBo9kQwaHbw8m0296Gulju4tt5mb95rH8xaZ7Me7GotKxZ3my+qVcby5clld/53tq37Qw/rt2CTvTN9jc/i3m9uUskebFvDxe33alDBPp273pX78iUNbdK6XfbxnPXWvkpJ+1OXulY+qD+WVh3TOjeXWS8iIAIiIAIiIAIikIAEMu3Bz5s3r11++eWh0JLdu3c7sV6iRIkUmPbt22c//vijEUaDQCas57vvvrNixYo5wTpo0CCjwYBoHjFihAv5QXSTj32+V2DFihU2ceJE15hAqFMGAppjIvR5p0GQJ08eV4f169e7shDEiG0EMkYjY/jw4a4u5cuXt2HDhjlx7naGvZB+3rx5rjFCo2XIkCHGeWJTp051ApyGCo0SejNoyGA0CFin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vf/++/boo4+Gijp58qQNHjzY1WvYsGF24403pvDy46l/9dVXQ3m0IAIiIAIiIAIiIAIiIALxTiDLMfgHDx60kSNH2gMPPOC84ePGjUvGZNWqVW69e/fuljt3bieyu3TpYk899ZSVL18+WdqMruD9b968uV1yySU2Z86cZNkXLFjgegoee+wx27x5s9HQkImACIiACIiACIiACIhAohPIssCfMmWKY9SpUycXdoO3PNy8h/4///mP7dixI7SLePvwOPzQjkws7Ny5M0WozejRo61Ro0Yurp8QHnoZZCIgAiIgAiIgAiIgAiKQ6ASyHKIzYsQIu/DCC61w4cLWtWtXF47DYNp69eo5dqVLl3beekJoCJlBbHfu3NmuvPLKFDHzTzzxhPPyh0Nfv369C8cJ38YA2QIFCriY/FmzZhli/o477gglOXz4sBFj/5vf/MZt69Gjh3366af285//3I0B8AkZ2PuHP/zBr7r3u+66y1q1apVsm1ZEQAREQAREQAREQAREIF4IZEngb9u2zebOnevCc7Zu3WpFixZ1nvSxY8eGBD4g8Na3bt3aCJthth0G3PL/5ptvWqVKlUKsiNEn7CbcInsE2Ne7d+/wJHbttdfa9ddfH9o2depUt0xjgnrVrVvXDh06ZDNnznRx/z4hYwUI7wm3rIYNhZelZREQAREQAREQAREQARE42wSSq+kMHt3H27/77rvGvzdE+b333ptMrDM7DvHy/N988832yCOP2NChQ106n+/yyy93nnm/zjuNAmbRCbenn37aefUR7/fff7/rPWB2Hm+MCcAivfOjRo1KJvDLlCljPXv29Nn0LgIiIAIiIAIiIAIiIAJxTyBLAp8wGKa7vPPOO0MgmEXnj3/8oxE6g+eeKTL37t1rDz/8cCgN01kirhmgmxmjscA/3n8891988YXROCAciDh/PPU0INq0aRMqfvLkyfbOO++4gbeRU2OGEmlBBERABERABERABERABOKcQKYH2RJnz49XEeKCsPb/9evXd/PI4y3HqlSp4jz1n3/+ua1bt85WrlzpQmyIf+/QoUOW8TH9JfPrM989Nn78ePfOeABfJ96ZxQdjik5vzKu/aNGiZP+rV6/2u/UuAiIgAiIgAiIgAiIgAnFHINMefMJz8IQzU02kMaj1//7v/5zXnmVCbEjvRTix74TPhHvYI8sIX4/88avwffQGEPLz8ccfW69evdyUnRyzYMGC4cmsSJEixvScNDx8WA4NlMcffzxZuiZNmthLL72UbJtWREAEREAEREAEREAERCBeCOQKfmn21NmqLB5zDhf5i7Nn6/g6jgiIgAiIgAiIgAiIgAgkOoGzKvATHabOTwREQAREQAREQAREQATONYFMx+Cf64rr+CIgAiIgAiIgAiIgAiIgAikJSOCnZKItIiACIiACIiACIiACIhC3BCTw4/bSqeIiIAIiIAIiIAIiIAIikJKABH5KJtoiAiIgAiIgAiIgAiIgAnFLQAI/bi+dKi4CIiACIiACIiACIiACKQlI4Kdkoi0iIAIiIAIiIAIiIAIiELcEJPDj9tKp4iIgAiIgAiIgAiIgAiKQkoAEfkom2iICIiACIiACIiACIiACcUtAAj9uL50qLgIiIAIiIAIiIAIiIAIpCUjgp2SiLSIgAiIgAiIgAiIgAiIQtwQk8OP20qniIiACIiACIiACIiACIpCSgAR+SibaIgIiIAIiIAIiIAIiIAJxS+D/A96jFB0SJXVLAAAAAElFTkSuQmCC"}}},{"metadata":{},"cell_type":"markdown","source":"![Captura%20de%20Pantalla%202020-01-20%20a%20la%28s%29%2019.03.53.png](attachment:Captura%20de%20Pantalla%202020-01-20%20a%20la%28s%29%2019.03.53.png)","attachments":{"Captura%20de%20Pantalla%202020-01-20%20a%20la%28s%29%2019.03.53.png":{"image/png":"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vWI6jz/+eOCZ5dl83/veF9NjA3UAzzTtG55vBDlOja9+9auhf//+8diO8qcuBXVrwP/Rj37UIj2DLZVOa1xjS6WJkO4oL7KWYmI6tUeARkprNeZb4xl46KGHwpgxYxTUtVeUzFGVBP7rv/4rei5oLPXo0SNGMn3ve98L++yzTxg4cGCVqbhbRyHw8ssvRzH9mc98Jhx++OGBhvmnPvWp8Kc//Sl89KMfjZd5++23B+o+2k54tubOnRs+/OEPhxtvvDE2yv/hH/4h8D9vlC88Zh1BTOevy88SaAsC//u//xvrZJ5FnqFbbrklUHefeOKJ8RkszMOtt94axfRPf/rT2BFG2+of//Efw3333Rc7S++4444ops8555zNHJ2PPfZYFNMI+L322is+35/4xCdi59GFF15YeKq6/t5ugnr+/Pnht7/9bQxzGTVqVDjiiCMaGpI///nPY1jAqaee2gCXCpQeFF7MyZ566qlw+eWXx0qa9WeddVZDKBFp0AM6a9aswA0lhIjeFyrum2++OfTt2zeccsopYb/99ovJ/fKXv2x0TkLK//znPwfCuwhRoqBNmjQp7lsu74XpvPHGG7EwkYfx48fHl8pBBx0U06Hnht78s88+O9x///0NYewnnXRS9P6m6yxc3nTTTeGBBx6IBZOws3e+850NPT2l8v3aa6+FH/zgB+HjH/94bLSTJuen14kwI64vb/QYz5w5M78qfv72t78dunXrFnumLrroosgG1txDuPCAwR2PxKGHHrrZ8a6QQFsQWLp0aTzN1ltvXdXp0rN4xhlnBDxQPC+EE5533nnhsssuC4888kgUCm9729ui94T96Z1NzwCNQsKndtppp8DzSa/tscce21CnpeePlwp1D/bggw8GXlSkg8fm0UcfDc8991ysEz/2sY/F3lzCZq+88sp4fsIi8V5TD6aGZLm6qPDCCVO/5pprwj333BOWLFkSe4nf/e53h2222SbuSvqci3zR8OVayTe9yieccELcp1x9Vng+v3cuAninp02bFv7jP/4jimmu/h3veEd8fnimeN8WM54dPJBEfeD1OP3008PQoUPjrpXKPzuVex/mj+eZ5F1Hu4J3WHrmK71/edfS4ORZKBbB1pRnsNj1d+R11DPHHXdcQ1uAqAXaepSHZNdee214+9vf3tCQp87GW0sdVMyoZ6kr/+3f/q3Y5riu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"}}},{"metadata":{},"cell_type":"markdown","source":"# Lessons learned and outlook\n**IN GENERAL:**\n1. We found ‘modin’ library can help accelerate pandas even on the laptop and so we tried to install it in windows. We learned that:\n    * Pip install “modin[dask]” is ran in the command line, therefore, the code should be put in the command in terminal instead of interpreter.\n    * If still get error when using modin to read data, it’s because Windows doesn’t support Ray which is the dependency of modin. To use it, we have to install WSL. But it would easier for laptops using Linux or Mac.\n    * We didn’t use it in the end because we don’t want to install more applications.\n2.\tDataFrame.dtypes for data must be int, float or bool.\n3.\tDifference between statistics modeling (e.g. linear regression) and machine learning:\n    * Statistical modeling is more about finding relationships between variables and the significance of those relationships. Test data is not necessary but we analyze confidential intervals, p value, test value to access the model’s accuracy.\n    * Machine learning is more about prediction results, we don’t care much if the model is interpretable. Test data is normally needed to validate results’ accuracy.\n4.\tEven though in machine learning, we don’t care much about the independency/collinearity problems, but we still should ensure that the training data is as clean as possible, therefore, we should still drop the useless columns, which also reduce the data size and increase the speed.\n5. The cells took to much time to execute, this was very annoying. It felt like a waste of time.\n6. It was initially difficult to understand the different data sets and the connections between them. It took us some time to get the hang of it.\n7. We encountered many unknown methods, so we had to research what each method does in order to use it properly.\n\n**FOR THE MISSING VALUES:**\n\nAfter tried several different solutions without efficiency, we saw a tutorial indicating a really simple but useful action before start looking for proper ML. This tutorial mentioned that it's better **to calculate a ''common-sense'' baseline**. This baseline is defined in how a person who has knowledge in that field would solve the problem without using any data science tricks. Alternatively, it can be a dummy or simple algorithm, consisting of few lines of code, to use as a baseline metric.\nBaseline metrics can be different in regression and classification problems. For a regression problem, it can be a central tendency measure as the result for all predictions, such as the mean or the median. Since this is a regression problem and competition's results will be evaluated for root mean squared logarithmic error. Baseline metrics are important in a way that, if a ML model cannot beat the simple and intuitive prediction of a person's or an algorithm's guess, the original problem needs reconsideration or training data needs reframing.\ne.g.The baseline guess is a score of 4.38\nBaseline Performance on the valid set: RMSE = 2.1070\nHowever, when we try linear regression, RMSE of the linear regression model is: 1.9895562449483846 without too much difference. Then why we are going to use such ML for prediction? By doing so, it's really easy to do the benchmark even if we don't start with any complicated statistics.\n"},{"metadata":{},"cell_type":"markdown","source":"# References\n\nRef1: **As per the discussion in the following thread, https://www.kaggle.com/c/ashrae-energy-prediction/discussion/117083, there is some discrepancy in the meter_readings for different ste_id's and buildings. It makes sense to delete them**\n\nRef2: https://www.kaggle.com/aitude/ashrae-kfold-lightgbm-without-leak-1-08\n\nRef3: https://www.kaggle.com/cereniyim/save-the-energy-for-the-future-2-fe-lightgbm\n\nRef4: https://www.kaggle.com/nz0722/aligned-timestamp-lgbm-by-meter-type\n\nOthers:\n\nhttps://www.kaggle.com/migglu/odyssey-towards-a-sustainable-built-environment#Modeling-and-prediction\nRandom forest: https://www.kaggle.com/holoong9291/ashrae-great-energy-predict\nhttps://www.kaggle.com/aldrinl/eda-rf-ashrae-great-energy-predictor\nLightgbm https://www.kaggle.com/kaushal2896/ashrae-eda-fe-lightgbm-1-12\nLightgbm: https://www.kaggle.com/isaienkov/lightgbm-fe-1-19\nKfold lightgbm: https://www.kaggle.com/aitude/ashrae-kfold-lightgbm-without-leak-1-08\nStratified lightgb,: https://www.kaggle.com/roydatascience/ashrae-energy-prediction-using-stratified-kfold\nhttps://www.kaggle.com/cereniyim/save-the-energy-for-the-future-3-predictions\nhttps://www.kaggle.com/cereniyim/save-the-energy-for-the-future-2-fe-lightgbm#-4.-Compare-Several-Machine-Learning-Models-\n\nhttps://www.kaggle.com/jaseziv83/a-deep-dive-eda-into-all-variables\nhttps://www.kaggle.com/ishaan45/pandas-profiling-missing-value-imputation\nhttps://www.kaggle.com/caesarlupum/ashrae-start-here-a-gentle-introduction#14.-Handling-missing-values\nhttps://www.kaggle.com/kaushal2896/ashrae-eda-fe-lightgbm-1-12\nhttps://www.kaggle.com/aitude/ashrae-missing-weather-data-handling\nhttps://www.kaggle.com/vikassingh1996/ashrae-great-energy-insightful-eda-fe-lgbm\nhttps://www.kaggle.com/cereniyim/save-the-energy-for-the-future-2-fe-lightgbm\nhttps://www.kaggle.com/drcapa/ashrae-feature-engineering-merge-data\n\n\nhttps://www.youtube.com/watch?v=ErDgauqnTHk - Gopal Prasad Malakar\nhttps://www.youtube.com/watch?v=l3OmtvcaTmM&list=PL1UM2yYgxPh-2kKL53wCsBQP5MoCBvH1z&index=5 Ligdi Gonzalez\nhttps://www.youtube.com/watch?v=F7xj8H_p288&list=PL1UM2yYgxPh-2kKL53wCsBQP5MoCBvH1z&index=6 - Ligdi Gonzalez\nhttps://www.microsoft.com/en-us/research/wp-content/uploads/2017/11/lightgbm.pdf"},{"metadata":{},"cell_type":"markdown","source":"## Previous Code\n\nfor df in [train, test]:\n    df['air_temperature'] = df['air_temperature'].astype('float16')\n    df['cloud_coverage'] = df['cloud_coverage'].astype(\"float16\")\n    df['dew_temperature'] = df['dew_temperature'].astype('float16')\n    df['precip_depth_1_hr'] = df['precip_depth_1_hr'].astype('float32')\n    df['sea_level_pressure'] = df['sea_level_pressure'].astype('float32')\n    df['wind_direction'] = df['wind_direction'].astype('float32')\n    df['wind_speed'] = df['wind_speed'].astype('float16')\n    df['square_feet'] = df['square_feet'].astype(\"float32\")\n    df['building_id'] = df['building_id'].astype(\"int16\")\n    \ntrain.drop('timestamp',axis=1,inplace=True)\ntest.drop('timestamp',axis=1,inplace=True)\n\ntrain['number_unique_meter_per_building']\ntrain['mean_meter_reading_per_building']\ntrain['median_meter_reading_per_building']\ntrain['std_meter_reading_per_building']\n\ntrain['mean_meter_reading_on_year_built']\ntrain['median_meter_reading_on_year_built']\ntrain['std_meter_reading_on_year_built']\n\ntrain['mean_meter_reading_per_meter']\ntrain['median_meter_reading_per_meter']\ntrain['std_meter_reading_per_meter']\n\ntrain['mean_meter_reading_per_primary_usage']\ntrain['median_meter_reading_per_primary_usage']\ntrain['std_meter_reading_per_primary_usage']\n\ntrain['mean_meter_reading_per_site_id']\ntrain['median_meter_reading_per_site_id']\ntrain['std_meter_reading_per_site_id']\n\nThen again but with the test dataset.\n\nle = LabelEncoder()\n\ntrain['meter']= le.fit_transform(train['meter']).astype(\"uint8\")\ntest['meter']= le.fit_transform(test['meter']).astype(\"uint8\")\ntrain['primary_use']= le.fit_transform(train['primary_use']).astype(\"uint8\")\ntest['primary_use']= le.fit_transform(test['primary_use']).astype(\"uint8\")\n\nCheck the correlation between the variables and eliminate the one's that have high correlation.Threshold for removing correlated variables:\nthreshold = 0.9\n\nAbsolute value correlation matrix\ncorr_matrix = train.corr().abs()\ncorr_matrix.head()\n\nUpper triangle of correlations\nupper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))\nupper.head()\n\nSelect columns with correlations above threshold\nto_drop = [column for column in upper.columns if any(upper[column] > threshold)]\n\nprint('There are %d columns to remove.' % (len(to_drop)))\nprint (\"Following columns can be dropped {}\".format(to_drop))\n\ntrain.drop(to_drop,axis=1,inplace=True)\ntest.drop(to_drop,axis=1,inplace=True)\n\ny = train['meter_reading']\ntrain.drop('meter_reading',axis=1,inplace=True)\n\ncategorical_cols = ['building_id','Month','meter','Hour','primary_use','DayOfWeek','DayOfMonth']\n\n%%time\nx_train,x_test,y_train,y_test = train_test_split(train,y,test_size=0.25,random_state=42)\nprint (x_train.shape)\nprint (y_train.shape)\nprint (x_test.shape)\nprint (y_test.shape)\n\nlgb_train = lgb.Dataset(x_train, y_train,categorical_feature=categorical_cols)\nlgb_test = lgb.Dataset(x_test, y_test,categorical_feature=categorical_cols)\ndel x_train, x_test , y_train, y_test\n\nparams = {'feature_fraction': 0.75,\n          'bagging_fraction': 0.75,\n          'objective': 'regression',\n          'max_depth': -1,\n          'learning_rate': 0.15,\n          \"boosting_type\": \"gbdt\",\n          \"bagging_seed\": 11,\n          \"metric\": 'rmse',\n          \"verbosity\": -1,\n          'reg_alpha': 0.5,\n          'reg_lambda': 0.5,\n          'random_state': 47\n         }\n\nreg = lgb.train(params, lgb_train, num_boost_round=3000, valid_sets=[lgb_train, lgb_test], early_stopping_rounds=100, verbose_eval = 100)\n\ndel lgb_train,lgb_test\n\nser = pd.DataFrame(reg.feature_importance(),train.columns,columns=['Importance']).sort_values(by='Importance')\nser['Importance'].plot(kind='bar',figsize=(10,6))\n\ndel train\n\n%%time\npredictions = []\nstep = 50000\nfor i in range(0, len(test), step):\n    predictions.extend(np.expm1(reg.predict(test.iloc[i: min(i+step, len(test)), :], num_iteration=reg.best_iteration)))\n    \n%%time\nSubmission['meter_reading'] = predictions\nSubmission['meter_reading'].clip(lower=0,upper=None,inplace=True)\nSubmission.to_csv(\"Twentysix.csv\",index=None)"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":1}