{"cells":[{"metadata":{},"cell_type":"markdown","source":"# 1. 머리말 Introduction\n건물 효율을 향상시켜 비용과 배출량을 줄이기 위해 상당한 투자가 이루어지고 있다. \n문제는 개선책이 효과가 있는가 하는 것이다.\n\n이번 커널에서는 냉수, 전기, 온수, 증기계량기 등의 분야에서 계측된 건물 에너지 사용의 정확한 모델을 개발하게 된다. \n데이터는 3년 동안 1,000개 이상의 건물에서 나왔다. 이러한 에너지 절약형 투자에 대한 더 나은 추정치로, 대규모 투자자와 금융 기관들은 건물 효율성의 진보를 가능하게 하기 위해 이 분야에 더 많은 투자를 할 것이다.\n\n![](https://storage.googleapis.com/kaggle-competitions/kaggle/9994/logos/thumb76_76.png?t=2019-10-08-17-08-54)\n\n**호스트 정보**\n1894년에 설립된 ASHRAE는 난방, 환기, 냉방, 그리고 그들의 제휴분야의 예술과 과학을 발전시키는 역할을 한다. ASHRAE 회원들은 전 세계의 빌딩 시스템 설계와 산업 공정 전문가들을 대표한다. 132개국에서 54,000명 이상의 회원이 활동하고 있는 ASHRAE는 연구, 표준 작성, 출판 및 지속적인 교육을 지원하며, 현재 미래의 건설 환경을 형성하고 있다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## 1-1. 제시된 과제\n-> 테스트 세트의 각 ID에 대해 대상 변수를 예측해야 한다. \n파일에는 header를 포함한다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# 2. 패키지 불러오기","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import KFold\nimport matplotlib.pyplot as plt\nimport lightgbm as lgb\nimport datetime\nimport sys\nimport os\nimport gc #Garbage Collector\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport time\nimport warnings\n\nwarnings.filterwarnings(\"ignore\")\ngc.enable()\ndevice_id = 0  # cpu -> -1, gpu -> 0","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 2-2.Version","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print('pandas: {}'.format(pd.__version__))\nprint('numpy: {}'.format(np.__version__))\nprint('Python: {}'.format(sys.version))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 3.데이터 로드","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\nprint(os.listdir(\"../input/ashrae-energy-prediction/\"))\nDATA_PATH = \"../input/ashrae-energy-prediction/\"\n\n# 데이터 불러오기\n\ntrain_data = pd.read_csv(DATA_PATH +'train.csv')\nbuilding = pd.read_csv(DATA_PATH +'building_metadata.csv')\nweather_train = pd.read_csv(DATA_PATH +'weather_train.csv')\ntrain_data = train_data.merge(building, on='building_id', how='left')\ntrain_data = train_data.merge(weather_train, on=['site_id', 'timestamp'], how='left')\n\ntest_data = pd.read_csv(DATA_PATH +'test.csv')\nweather_test = pd.read_csv(DATA_PATH +'weather_test.csv')\ntest_data = test_data.merge(building, on='building_id', how='left')\ntest_data = test_data.merge(weather_test, on=['site_id', 'timestamp'], how='left')\n\nprint (\"끝!\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> 데이터 형태 및 컬럼 확인","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**Weather**\n* time of day\n* holiday\n* weekend\n* cloud_coverage + lags\n* dew_temperature + lags\n* precip_depth + lags\n* sea_level_pressure + lags\n* wind_direction + lags\n* wind_speed + lags\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"weather_train.keys(),weather_train.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Train**\n* max, mean, min, std of the specific building historically\n* number of meters\n* number of buildings at a siteid","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data.keys(),train_data.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Buildings**\n* primary_use\n* square_feet\n* year_built\n* floor_count (may be too sparse to use)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"building.keys(),building.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> 결측치 확인","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> 다운사이징","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#Based on this great kernel https://www.kaggle.com/arjanso/reducing-dataframe-memory-size-by-65\ndef reduce_mem_usage(df):\n    start_mem_usg = df.memory_usage().sum() / 1024**2 \n    print(\"Memory usage of properties dataframe is :\",start_mem_usg,\" MB\")\n    NAlist = [] # Keeps track of columns that have missing values filled in. \n    for col in df.columns:\n        if df[col].dtype != object:  # Exclude strings            \n            # Print current column type\n            print(\"******************************\")\n            print(\"Column: \",col)\n            print(\"dtype before: \",df[col].dtype)            \n            # make variables for Int, max and min\n            IsInt = False\n            mx = df[col].max()\n            mn = df[col].min()\n            print(\"min for this col: \",mn)\n            print(\"max for this col: \",mx)\n            # Integer does not support NA, therefore, NA needs to be filled\n            if not np.isfinite(df[col]).all(): \n                NAlist.append(col)\n                df[col].fillna(mn-1,inplace=True)  \n                   \n            # test if column can be converted to an integer\n            asint = df[col].fillna(0).astype(np.int64)\n            result = (df[col] - asint)\n            result = result.sum()\n            if result > -0.01 and result < 0.01:\n                IsInt = True            \n            # Make Integer/unsigned Integer datatypes\n            if IsInt:\n                if mn >= 0:\n                    if mx < 255:\n                        df[col] = df[col].astype(np.uint8)\n                    elif mx < 65535:\n                        df[col] = df[col].astype(np.uint16)\n                    elif mx < 4294967295:\n                        df[col] = df[col].astype(np.uint32)\n                    else:\n                        df[col] = df[col].astype(np.uint64)\n                else:\n                    if mn > np.iinfo(np.int8).min and mx < np.iinfo(np.int8).max:\n                        df[col] = df[col].astype(np.int8)\n                    elif mn > np.iinfo(np.int16).min and mx < np.iinfo(np.int16).max:\n                        df[col] = df[col].astype(np.int16)\n                    elif mn > np.iinfo(np.int32).min and mx < np.iinfo(np.int32).max:\n                        df[col] = df[col].astype(np.int32)\n                    elif mn > np.iinfo(np.int64).min and mx < np.iinfo(np.int64).max:\n                        df[col] = df[col].astype(np.int64)    \n            # Make float datatypes 32 bit\n            else:\n                df[col] = df[col].astype(np.float32)\n            \n            # Print new column type\n            print(\"dtype after: \",df[col].dtype)\n            print(\"******************************\")\n    # Print final result\n    print(\"___MEMORY USAGE AFTER COMPLETION:___\")\n    mem_usg = df.memory_usage().sum() / 1024**2 \n    print(\"Memory usage is: \",mem_usg,\" MB\")\n    print(\"This is \",100*mem_usg/start_mem_usg,\"% of the initial size\")\n    return df, NAlist","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"#44% 감소\ntrain, _ = reduce_mem_usage(train_data)\ntest, _ = reduce_mem_usage(test_data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del building, weather_train, weather_test\ndel train_data\ndel test_data\ngc.collect() ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_columns = train.columns.tolist() #list 배열로 변경","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 3-1.데이터 확인","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head(2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test.head(2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.describe()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.dtypes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"for c in train_columns:\n    print(train[c].value_counts())\n    print()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for c in test.columns:\n    print(test[c].value_counts())\n    print()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 4.Feature preprocessing by sklearn pipeline","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.base import BaseEstimator, TransformerMixin\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.preprocessing import MinMaxScaler, OrdinalEncoder, QuantileTransformer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DateFeatureExtractor(BaseEstimator, TransformerMixin):\n    def __init__(self):\n        pass\n    \n    def fit(self, X, y=None):\n        return self\n    \n    def transform(self, df, y=None):\n        # df = df.copy()\n        df[\"timestamp\"] = pd.to_datetime(df[\"timestamp\"])\n        df[\"hour\"] = df[\"timestamp\"].dt.hour\n        df[\"day\"] = df[\"timestamp\"].dt.day\n        df[\"weekday\"] = df[\"timestamp\"].dt.weekday\n        df[\"month\"] = df[\"timestamp\"].dt.month\n        return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"minmax_features = [\n    \"year_built\",\n    \"hour\",\n    \"day\",\n    \"weekday\",\n    \"month\",\n]\n\nminmax_transformer = make_pipeline(\n    MinMaxScaler(),\n)\n\nnumeric_features = [\n    \"square_feet\",\n    \"air_temperature\",\n    \"cloud_coverage\",\n    \"dew_temperature\",\n    \"floor_count\",\n]\n\nnumeric_transformer = make_pipeline(\n    QuantileTransformer(\n        n_quantiles=100,\n        output_distribution=\"normal\",\n        random_state=0,\n    ),\n)\n\ncategorical_features = [\n    \"primary_use\",\n    \"meter\",\n    \"building_id\",\n]\n\ncategorical_transformer = make_pipeline(\n    OrdinalEncoder(),\n)\n\npreprocessor = make_pipeline(\n    DateFeatureExtractor(),\n    ColumnTransformer(\n        transformers=[\n            (\"numeric\", numeric_transformer, numeric_features),\n            (\"minmax\", minmax_transformer, minmax_features),\n            (\"categorical\", categorical_transformer, categorical_features),\n        ]\n    ),\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preprocessed_train = preprocessor.fit_transform(train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preprocessed_train[:5, :]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"target = np.log1p(train[[\"meter_reading\"]].values)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"target[:5, :]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del train\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 5. Chainer regressor model\n오픈소스 신경망 프레임워크 - Preferred Networks(일본) ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import chainer\nimport chainer.functions as F\nimport chainer.links as L","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"chainer.print_runtime_info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MLP(chainer.Chain):\n\n    def __init__(self, n_units=10, n_out=10):\n        super(MLP, self).__init__()\n        with self.init_scope():\n            # embed_id\n            self.embed_primary_use = L.EmbedID(16, 2)\n            self.embed_meter = L.EmbedID(4, 2)\n            self.embed_building_id = L.EmbedID(1449, 6)\n            # the size of the inputs to each layer will be inferred\n            self.l1 = L.Linear(None, n_units)  # n_in -> n_units\n            self.l2 = L.Linear(None, n_units)  # n_units -> n_units\n            self.l3 = L.Linear(None, n_out)  # n_units -> n_out\n\n    def forward(self, numeric_x, categorical_x):\n        # embed layers\n        e1 = self.embed_primary_use(categorical_x[:, 0])\n        e2 = self.embed_meter(categorical_x[:, 1])\n        e3 = self.embed_building_id(categorical_x[:, 2])\n        \n        # concat all inputs\n        x = F.concat((numeric_x, e1, e2, e3), axis=1)\n        \n        # main layers\n        h = F.dropout(F.relu(self.l1(x)), ratio=.1)\n        h = F.dropout(F.relu(self.l2(h)), ratio=.1)\n        return self.l3(h)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_and_validate(\n    model,\n    optimizer,\n    train,\n    validation,\n    n_epoch,\n    batchsize,\n    device,\n):\n    # 1. If the device is gpu(>=0), send model to the gpu.\n    if device >= 0:\n        model.to_gpu(device)\n\n    # 2. Setup optimizer\n    optimizer.setup(model)\n\n    # 3. Create iterator from datast\n    train_iter = chainer.iterators.SerialIterator(train, batchsize)\n    validation_iter = chainer.iterators.SerialIterator(\n        validation, batchsize, repeat=False, shuffle=False\n    )\n\n    # 4. Create Updater/Trainer\n    updater = chainer.training.StandardUpdater(train_iter, optimizer, device=device)\n    trainer = chainer.training.Trainer(updater, (n_epoch, 'epoch'), out='out')\n\n    # 5. Extend functionalities of trainer\n    trainer.extend(chainer.training.extensions.LogReport())\n    trainer.extend(\n        chainer.training.extensions.Evaluator(\n            validation_iter, model, device=device\n        ), name='val'\n    )\n    trainer.extend(\n        chainer.training.extensions.PrintReport(\n            ['epoch', 'main/loss', 'val/main/loss', 'elapsed_time']\n        )\n    )\n    trainer.extend(\n        chainer.training.extensions.PlotReport(\n            ['main/loss', 'val/main/loss'], x_key='epoch', file_name='loss.png'\n        )\n    )\n\n    # 6. Start training\n    trainer.run()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preprocessed_train = preprocessed_train[:1000]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 6.KFold : 교차검증\n모든 데이터가 최소 1회 TestSet으로 쓰이도록 합니다 ->모델검증","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import KFold\n\nbatchsize = 512\nn_epoch = 20\nn_splits = 5\nseed = 666\n\nkf = KFold(n_splits=n_splits, shuffle=True, random_state=seed)\n\nmodels = []\nfor fold_n, (train_index, valid_index) in enumerate(kf.split(preprocessed_train)):\n    gc.collect()\n    \n    print()\n    print('Fold:', fold_n)\n    X_train, X_valid = preprocessed_train[train_index, :], preprocessed_train[valid_index, :]\n    y_train, y_valid = target[train_index], target[valid_index]\n    \n    model = MLP(64, 1)\n    regresser = L.Classifier(model, lossfun=F.mean_squared_error, accfun=F.mean_squared_error)\n    optimizer = chainer.optimizers.Adam()\n    \n    train_and_validate(\n        regresser,\n        optimizer,\n        chainer.datasets.TupleDataset(\n            X_train[:, :len(numeric_features) + len(minmax_features)].astype(\"f\"),\n            X_train[:, len(numeric_features) + len(minmax_features):].astype(\"i\"),\n            y_train,\n        ),\n        chainer.datasets.TupleDataset(\n            X_valid[:, :len(numeric_features) + len(minmax_features)].astype(\"f\"),\n            X_valid[:, len(numeric_features) + len(minmax_features):].astype(\"i\"),\n            y_valid,\n        ),\n        n_epoch,\n        batchsize,\n        device_id,\n    )\n    \n    models.append(model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del X_train, X_valid, y_train, y_valid, preprocessed_train, target\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Important Features**","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"for model in models:\n    lgb.plot_importance(model)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 7.Submission","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"test[\"meter_reading\"] = 0.0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tqdm import tqdm\n\nif device_id >= 0:\n    import cupy as cp\n\nstep_size = 50000\n\ni = 0\nres = []\nfor j in tqdm(range(int(np.ceil(test.shape[0] / 50000)))):\n    gc.collect()\n    batch = test[train_columns].iloc[i : i + step_size]\n    preprocessed_batch = preprocessor.transform(batch)\n    \n    device = chainer.get_device(device_id)\n    preprocessed_batch = device.send(preprocessed_batch)\n    \n    predictions = []\n    with chainer.using_config('train', False):\n        for model in models:\n            ndarray = model(\n                preprocessed_batch[:, :len(numeric_features) + len(minmax_features)].astype(\"f\"),\n                preprocessed_batch[:, len(numeric_features) + len(minmax_features):].astype(\"i\"),\n            )\n            ndarray.to_cpu()\n            predictions.append(ndarray.array)\n        \n    res.append(np.expm1(sum(predictions) / n_splits))\n    i += step_size","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"res = np.concatenate(res)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = pd.read_csv('/kaggle/input/ashrae-energy-prediction/sample_submission.csv')\nsubmission['meter_reading'] = res\nsubmission.loc[submission['meter_reading'] < 0, 'meter_reading'] = 0\nsubmission.to_csv('submission.csv', index=False)\nsubmission","execution_count":null,"outputs":[]},{"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":4}