{"cells":[{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"MAX_BOOST_ROUNDS = 7000\nEARLY_STOPPING = 200\nBATCH_SIZE = 50000\nFOLD_NUMBER = 0\n\nclass MonthTimeValidation(object):\n    def __init__(self, month_to_test_set=2, time_col='timestamp'):\n        self.month_to_test_set = month_to_test_set\n        self.time_col = time_col\n        \n    def split(self, df):\n        split_col = df[self.time_col].dt.month\n        split_col = split_col.reset_index(drop=True)\n        \n        for max_month in range(1,13-self.month_to_test_set):\n            train_idx = split_col[split_col <= max_month].index.tolist()\n            test_idx = split_col[(split_col > max_month) & (split_col <= max_month+self.month_to_test_set)].index.tolist()\n            yield train_idx, test_idx\n            \nimport numpy as np\n\n\ndef 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\n\n\nfrom sklearn.metrics import mean_squared_error\n\ndef LRMSE(y_true, y_pred):\n    return (mean_squared_error(y_true,y_pred))**(1/2)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import StratifiedKFold\n\ndef sort_X_by_Y(x_list, y_list):\n    return [x for _, x in sorted(zip(y_list,x_list), key=lambda pair: pair[0])]\n\nclass NaiveMeanModel(object):\n    def __init__(self, values_to_count_mean, target_variable_name, value_to_fillna=-1, out_of_fold_col_stratify='building_id'):\n        self.values_to_count_mean = values_to_count_mean\n        self.target_variable_name = target_variable_name\n        self.value_to_fillna = value_to_fillna\n        self.out_of_fold_col_stratify = out_of_fold_col_stratify\n        \n        self.counted_stats = None \n        \n    def fit(self, X, y=None):\n        if len(set(self.values_to_count_mean) & set(X.columns)) < len(self.values_to_count_mean):\n            raise ValueError('Columns to count stats not in df')\n            \n        self.counted_stats = X.groupby(self.values_to_count_mean)[self.target_variable_name].mean().reset_index()\n        \n    def predict(self, X):\n        if self.target_variable_name in X.columns:\n            prediction =  X.merge(self.counted_stats, on=self.values_to_count_mean, how='left')[self.target_variable_name+'_y']\n        else:\n            prediction =  X.merge(self.counted_stats, on=self.values_to_count_mean, how='left')[self.target_variable_name]\n            \n        print(str(prediction.isna().sum()) + ' Nan detected')\n        return prediction.fillna(self.value_to_fillna).reset_index(drop=True)\n    \n    def out_of_fold_predict(self, X):\n        kf_nmm = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n        \n        results_nmm = []\n        indexes_nmm = []\n        for train_idx_nmm, test_idx_nmm in kf_nmm.split(X, X['building_id']):\n            self.fit(X.iloc[train_idx_nmm])\n            results_nmm += list(self.predict(X.iloc[test_idx_nmm]))\n            indexes_nmm += list(test_idx_nmm)\n            \n        return sort_X_by_Y(results_nmm, indexes_nmm)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import lightgbm as lgb\nfrom tqdm import tqdm\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\ndef plotImp(model, col_names , num = 20):\n    feature_imp = pd.DataFrame({'Value':model.feature_importance(),'Feature':col_names})\n    plt.figure(figsize=(40, 20))\n    sns.set(font_scale = 5)\n    sns.barplot(x=\"Value\", y=\"Feature\", data=feature_imp.sort_values(by=\"Value\", ascending=False)[0:num])\n    \n    plt.title('LightGBM Features (avg over folds)')\n    plt.show()\n\nclass MyRegressor(object):\n    def __init__(self, ml_params, categoricals, nmm_params=None, cols_to_drop=[], tgt_variable='meter_reading', correct_site_0=False):\n        self.ml = None\n        self.ml_params = ml_params\n        \n        if nmm_params is not None:\n            self.naive_mean_model = NaiveMeanModel(**nmm_params)\n        else: \n            self.naive_mean_model = None\n        \n        self.tgt_variable = tgt_variable\n        self.categoricals = categoricals\n        self.cols_to_drop = cols_to_drop\n        self.correct_site_0 = correct_site_0\n        \n        self.predictors = None\n        \n    def fit(self, X, X_val=None, plot_feature_imp=True):\n        if self.correct_site_0:\n            X.loc[X['site_id']==0, self.tgt_variable] = X.loc[X['site_id']==0, self.tgt_variable] * 0.2931\n            \n        if self.naive_mean_model is not None:\n            X['stat'] = self.naive_mean_model.out_of_fold_predict(X)\n            self.naive_mean_model.fit(X)\n        \n        y = X[self.tgt_variable]\n        X = X.drop(columns=[self.tgt_variable] + self.cols_to_drop)\n        \n        col_names = X.columns\n        self.predictors = list(col_names)\n        \n        X = X[self.predictors].values.astype(np.float32)\n        X = lgb.Dataset(X, label=y,feature_name=self.predictors, categorical_feature=self.categoricals)    \n        \n        if X_val is not None:\n            if self.correct_site_0:\n                X_val.loc[X_val['site_id']==0, self.tgt_variable] = X_val.loc[X_val['site_id']==0, self.tgt_variable] * 0.2931\n                \n            if self.naive_mean_model is not None:    \n                X_val['stat'] = self.naive_mean_model.predict(X_val)\n            \n            y_val = X_val[self.tgt_variable]\n            X_val = X_val.drop(columns=[self.tgt_variable] + self.cols_to_drop)\n            \n            X_val = X_val[self.predictors].values.astype(np.float32)\n            X_val = lgb.Dataset(X_val, label=y_val, \n                                feature_name = self.predictors, categorical_feature=self.categoricals)\n            \n            self.ml = lgb.train(self.ml_params,\n                                X,\n                                num_boost_round=MAX_BOOST_ROUNDS,\n                                valid_sets=(X, X_val),\n                                early_stopping_rounds=EARLY_STOPPING,\n                                verbose_eval = 50)\n        else:\n            self.ml = lgb.train(self.ml_params,\n                                X,\n                                valid_sets=(X),\n                                num_boost_round=MAX_BOOST_ROUNDS,\n                                verbose_eval = 50)\n        if plot_feature_imp:\n            plotImp(self.ml, col_names)\n            \n        return self\n    \n    def predict(self, X):\n        if self.correct_site_0:\n            site_0_mask = np.array(X['site_id']==0)   \n            \n        if self.naive_mean_model is not None:\n            X['stat'] = self.naive_mean_model.predict(X)\n        \n        cols_to_drop = list(set(['row_id', self.tgt_variable] + self.cols_to_drop) & set(X.columns))\n        \n        batches = int(np.ceil(X.shape[0]/BATCH_SIZE))\n        \n        res=[]\n        for i in tqdm(range(batches)):\n            res.append(self.ml.predict( X.iloc[i*BATCH_SIZE:(i+1)*BATCH_SIZE].drop(columns=cols_to_drop)[self.predictors].values.astype(np.float32) ))\n            \n        res = np.concatenate(res)\n        \n        if self.correct_site_0:\n            res[site_0_mask] = res[site_0_mask] * 3.4118\n            \n        return res","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Main"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport gc\n\nfrom os import path\n\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Read data"},{"metadata":{"trusted":true},"cell_type":"code","source":"cat_columns = [\n    \"building_id\", \"meter\", \"site_id\", \"primary_use\", \"had_air_temperature\", \"had_cloud_coverage\",\n    \"had_dew_temperature\", \"had_precip_depth_1_hr\", \"had_sea_level_pressure\", \"had_wind_direction\",\n    \"had_wind_speed\", \"tm_day_of_week\", \"tm_hour_of_day\", \"d_n\"\n]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train = reduce_mem_usage(pd.read_parquet('/kaggle/input/baseline-preprocessing-leaks-train-fe/X_train.parquet.gzip'))\nX_test = reduce_mem_usage(pd.read_parquet('/kaggle/input/baseline-preprocessing-leaks-train-fe/X_test.parquet.gzip'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(X_train.columns)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(X_test.columns)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prepare Data"},{"metadata":{},"cell_type":"markdown","source":"## Validation"},{"metadata":{"trusted":true},"cell_type":"code","source":"def one_fold_predict(data, model, metric=LRMSE, target_var_name='meter_reading', test_to_predict=None):    \n    print('Starting Validation')\n    print('Fold {}'.format(FOLD_NUMBER))\n    \n    model.fit(data[data['k_folds'] != FOLD_NUMBER].reset_index(drop=True), data[data['k_folds'] == FOLD_NUMBER].reset_index(drop=True))\n    pred = model.predict(data[data['k_folds'] == FOLD_NUMBER].reset_index(drop=True))\n        \n    if test_to_predict is not None:\n        test_prediction = model.predict(test_to_predict)\n            \n    itter_metric = metric(data.loc[data['k_folds'] == FOLD_NUMBER, target_var_name], pred)\n    print('Fold metric: '+str(itter_metric))\n    \n    gc.collect()\n     \n    if test_to_predict is not None:\n        return itter_metric, test_prediction\n    else:\n        return itter_metric","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"boost_model = MyRegressor(ml_params={\n            \"objective\": \"regression\",\n            \"boosting\": \"gbdt\",\n            \"num_leaves\": 145,\n            \"learning_rate\": 0.05,\n            \"feature_fraction\": 0.85,\n            \"reg_lambda\": 1,\n            \"metric\": \"rmse\",\n            'seed':42,\n    \n            'bagging_seed': 42,\n            'bagging_fraction': 0.8,\n            'bagging_freq': 5,\n            'max_depth': 13,\n            'subsample_freq': 5,\n            'subsample': 0.8\n            }, categoricals=cat_columns, cols_to_drop=['k_folds','index'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"rf_res, X_test['meter_reading'] = one_fold_predict(X_train, boost_model, test_to_predict=X_test)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"gc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Predict"},{"metadata":{"trusted":false},"cell_type":"code","source":"X_test.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"X_test[['row_id','meter_reading']].to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.6"}},"nbformat":4,"nbformat_minor":1}