{"cells":[{"metadata":{},"cell_type":"markdown","source":"Full credit to cHa0s and anyone else for the half/half code template. For this kernal I am mostly interested in some basic feature engineering over the top of this. Unfortunately none of them improved things, but wanted to share some of the things that were tried. Let me know if you have any thoughts! "},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n%matplotlib inline\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport lightgbm as lgb\nimport random\nimport gc\n\nfrom sklearn.preprocessing import LabelEncoder\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n        \npath_data = \"/kaggle/input/ashrae-energy-prediction/\"\npath_train = path_data + \"train.csv\"\npath_test = path_data + \"test.csv\"\npath_building = path_data + \"building_metadata.csv\"\npath_weather_train = path_data + \"weather_train.csv\"\npath_weather_test = path_data + \"weather_test.csv\"\n\nplt.style.use(\"seaborn\")\nsns.set(font_scale=1)\n\nmyfavouritenumber = 0\nseed = myfavouritenumber\nrandom.seed(seed)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## Memory optimization\n\n# Original code from https://www.kaggle.com/gemartin/load-data-reduce-memory-usage by @gemartin\n# Modified to support timestamp type, categorical type\n# Modified to add option to use float16\n\nfrom pandas.api.types import is_datetime64_any_dtype as is_datetime\nfrom pandas.api.types import is_categorical_dtype\n\ndef reduce_mem_usage(df, use_float16=False):\n    \"\"\"\n    Iterate through all the columns of a dataframe and modify the data type to reduce memory usage.        \n    \"\"\"\n    \n    start_mem = df.memory_usage().sum() / 1024**2\n    print(\"Memory usage of dataframe is {:.2f} MB\".format(start_mem))\n    \n    for col in df.columns:\n        if is_datetime(df[col]) or is_categorical_dtype(df[col]):\n            continue\n        col_type = df[col].dtype\n        \n        if col_type != object:\n            c_min = df[col].min()\n            c_max = df[col].max()\n            if str(col_type)[:3] == \"int\":\n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                    df[col] = df[col].astype(np.int32)\n                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                    df[col] = df[col].astype(np.int64)  \n            else:\n                if use_float16 and c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n                    df[col] = df[col].astype(np.float16)\n                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n                    df[col] = df[col].astype(np.float32)\n                else:\n                    df[col] = df[col].astype(np.float64)\n        else:\n            df[col] = df[col].astype(\"category\")\n\n    end_mem = df.memory_usage().sum() / 1024**2\n    print(\"Memory usage after optimization is: {:.2f} MB\".format(end_mem))\n    print(\"Decreased by {:.1f}%\".format(100 * (start_mem - end_mem) / start_mem))\n    \n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = pd.read_csv(path_train)\ndf_train = reduce_mem_usage(df_train, use_float16=True)\ndf_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"building = pd.read_csv(path_building)\nbuilding = reduce_mem_usage(building, use_float16=True)\nbuilding.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"le = LabelEncoder()\nbuilding.primary_use = le.fit_transform(building.primary_use)\nweather_train = pd.read_csv(path_weather_train)\nweather_train = reduce_mem_usage(weather_train, use_float16=True)\nbuilding.head()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nweather_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#weather forecast test:\n#what is the expected max temperature for today?\n# weather_train.timestamp = pd.to_datetime(weather_train.timestamp, format=\"%Y-%m-%d %H:%M:%S\")\n# weather_train['day'] = weather_train['timestamp'].dt.day\n# weather_train[\"month\"] = weather_train.timestamp.dt.month\n# weather_forecast_df = weather_train.groupby(['site_id','day'])['air_temperature','cloud_coverage','dew_temperature','precip_depth_1_hr','sea_level_pressure','wind_direction','wind_speed'].max()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#weather_forecast_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"raw","source":"Merge features with data"},{"metadata":{"trusted":true},"cell_type":"code","source":"#education holidays, e.g. spring break. Some sites may not be in USA but lets see how this goes.\nedu_holidays = ['2019-10-07','2018-10-08','2017-10-09','2016-10-10','2015-10-12',\n'2019-10-08','2018-10-09','2017-10-10','2016-10-11','2015-10-13',\n'2019-10-09','2018-10-10','2017-10-11','2016-10-12','2015-10-14',\n'2019-10-10','2018-10-11','2017-10-12','2016-10-13','2015-10-15',\n'2019-10-11','2018-10-12','2017-10-13','2016-10-14','2015-10-16',\n'2019-10-12','2018-10-13','2017-10-14','2016-10-15','2015-10-17',\n'2019-10-13','2018-10-14','2017-10-15','2016-10-16','2015-10-18',\n'2019-10-14','2018-10-15','2017-10-16','2016-10-17','2015-10-19',\n'2019-12-20','2018-12-21','2017-12-22','2016-12-23','2015-12-25',\n'2019-12-21','2018-12-22','2017-12-23','2016-12-24','2015-12-26',\n'2019-12-22','2018-12-23','2017-12-24','2016-12-25','2015-12-27',\n'2019-12-23','2018-12-24','2017-12-25','2016-12-26','2015-12-28',\n'2019-12-24','2018-12-25','2017-12-26','2016-12-27','2015-12-29',\n'2019-12-25','2018-12-26','2017-12-27','2016-12-28','2015-12-30',\n'2019-12-26','2018-12-27','2017-12-28','2016-12-29','2015-12-31',\n'2019-12-27','2018-12-28','2017-12-29','2016-12-30','2016-01-01',\n'2019-12-28','2018-12-29','2017-12-30','2016-12-31','2016-01-02',\n'2019-12-29','2018-12-30','2017-12-31','2017-01-01','2016-01-03',\n'2019-12-30','2018-12-31','2018-01-01','2017-01-02','2016-01-04',\n'2019-12-31','2019-01-01','2018-01-02','2017-01-03','2016-01-05',\n'2020-01-01','2019-01-02','2018-01-03','2017-01-04','2016-01-06',\n'2020-02-17','2019-02-18','2018-02-19','2017-02-20','2016-02-22',\n'2020-02-18','2019-02-19','2018-02-20','2017-02-21','2016-02-23',\n'2020-02-19','2019-02-20','2018-02-21','2017-02-22','2016-02-24',\n'2020-02-20','2019-02-21','2018-02-22','2017-02-23','2016-02-25',\n'2020-04-20','2019-04-22','2018-04-23','2017-04-24','2016-04-25',\n'2020-04-21','2019-04-23','2018-04-24','2017-04-25','2016-04-26',\n'2020-04-22','2019-04-24','2018-04-25','2017-04-26','2016-04-27',\n'2020-04-23','2019-04-25','2018-04-26','2017-04-27','2016-04-28'\n]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"holidays = ['2016-01-01', '2016-01-18', '2016-02-15', '2016-05-30', '2016-07-04',\n                '2016-09-05', '2016-10-10', '2016-11-11', '2016-11-24', '2016-12-26',\n                '2017-01-01', '2017-01-16', '2017-02-20', '2017-05-29', '2017-07-04',\n                '2017-09-04', '2017-10-09', '2017-11-10', '2017-11-23', '2017-12-25',\n                '2018-01-01', '2018-01-15', '2018-02-19', '2018-05-28', '2018-07-04',\n                '2018-09-03', '2018-10-08', '2018-11-12', '2018-11-22', '2018-12-25',\n                '2019-01-01']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"edu_holidays_total = list(set(edu_holidays + holidays))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"edu_holidays_total#","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def prepare_data(X, building_data, weather_data, test=False):\n    \"\"\"\n    Preparing final dataset with all features.\n    \"\"\"\n    \n    X = X.merge(building_data, on=\"building_id\", how=\"left\")\n    X = X.merge(weather_data, on=[\"site_id\", \"timestamp\"], how=\"left\")\n    \n    X.timestamp = pd.to_datetime(X.timestamp, format=\"%Y-%m-%d %H:%M:%S\")\n    X.square_feet = np.log1p(X.square_feet)\n    \n    if not test:\n        X.sort_values(\"timestamp\", inplace=True)\n        X.reset_index(drop=True, inplace=True)\n    \n    gc.collect()\n    \n#     holidays = [\"2016-01-01\", \"2016-01-18\", \"2016-02-15\", \"2016-05-30\", \"2016-07-04\",\n#                 \"2016-09-05\", \"2016-10-10\", \"2016-11-11\", \"2016-11-24\", \"2016-12-26\",\n#                 \"2017-01-01\", \"2017-01-16\", \"2017-02-20\", \"2017-05-29\", \"2017-07-04\",\n#                 \"2017-09-04\", \"2017-10-09\", \"2017-11-10\", \"2017-11-23\", \"2017-12-25\",\n#                 \"2018-01-01\", \"2018-01-15\", \"2018-02-19\", \"2018-05-28\", \"2018-07-04\",\n#                 \"2018-09-03\", \"2018-10-08\", \"2018-11-12\", \"2018-11-22\", \"2018-12-25\",\n#                 \"2019-01-01\"]\n    \n\n    \n    X[\"hour\"] = X.timestamp.dt.hour\n    X[\"weekday\"] = X.timestamp.dt.weekday\n    X[\"is_holiday\"] = np.where(X.primary_use == 0,(X.timestamp.dt.date.astype(\"str\").isin(edu_holidays_total)).astype(int),(X.timestamp.dt.date.astype(\"str\").isin(holidays)).astype(int))\n    \n    #Other features\n    #edu_holidays_total = list(set(edu_holidays + holidays))\n    #X[\"is_holiday_edu\"] = (X.timestamp.dt.date.astype(\"str\").isin(edu_holidays_total)).astype(int)\n    \n    \n    X[\"month\"] = X.timestamp.dt.month\n    X['year'] = X.timestamp.dt.year\n        #building age\n    X['building_age'] = X['year'] - X['year_built']\n    \n    #square feet to number of floors\n    X['square_feet_to_floor_count'] = np.where(X['floor_count']!= 0, X['square_feet'] / X['floor_count'], X['square_feet'])\n    \n    #Business hours\n    X['is_wider_bus_hours'] = np.where((X[\"hour\"]>=7)&(X[\"hour\"]<=19),1,0)\n#     X['is_core_bus_hours'] = np.where((X[\"hour\"]>=9)&(X[\"hour\"]<=17),1,0)\n    #Weekend\n    X['is_weekend'] = np.where((X[\"weekday\"]>=1)&(X[\"weekday\"]<=5),0,1)\n    #Season of year\n    X['season'] = (np.where(X[\"month\"].isin([12,1,2]),1,\n                   np.where(X[\"month\"].isin([3,4,5]),2,         \n                   np.where(X[\"month\"].isin([6,7,8]),3,          \n                   np.where(X[\"month\"].isin([9,10,11]),4,0)))))\n    #Business Quarter\n#     X['business_quarter'] = (np.where(X[\"month\"].isin([1,2,3]),1,\n#                    np.where(X[\"month\"].isin([4,5,6]),2,         \n#                    np.where(X[\"month\"].isin([7,8,9]),3,          \n#                    np.where(X[\"month\"].isin([10,11,12]),4,0)))))\n    #Daylight Savings\n    X['daylight_savings'] = (np.where(X[\"month\"].isin([3,4,5,6,7,8,9,10]),1,0))\n    #Lunch breaks\n#     X['lunch_break'] = (np.where(X[\"hour\"].isin([12]),1,0))  \n\n    X['air_to_dew_temperature'] = X['air_temperature'] / X['dew_temperature']\n    \n    X = reduce_mem_usage(X, use_float16=True)\n    \n    drop_features = [\"timestamp\", \"sea_level_pressure\", \"wind_direction\", \"wind_speed\", 'year']\n\n    X.drop(drop_features, axis=1, inplace=True)\n\n    if test:\n        row_ids = X.row_id\n        X.drop(\"row_id\", axis=1, inplace=True)\n        return X, row_ids\n    else:\n        y = np.log1p(X.meter_reading)\n        #X.drop(\"meter_reading\", axis=1, inplace=True)\n        return X, y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train, y_train = prepare_data(df_train, building, weather_train)\ndel df_train, weather_train\n\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train.groupby('month')['building_id'].count()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Target Encoding\ndf_group = X_train.groupby('building_id')['meter_reading']\nbuilding_mean = df_group.mean().astype(np.float16)\nbuilding_median = df_group.median().astype(np.float16)\nbuilding_min = df_group.min().astype(np.float16)\nbuilding_max = df_group.max().astype(np.float16)\nbuilding_std = df_group.std().astype(np.float16)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Target Encoding Weather\nweather_group = X_train.groupby('site_id')['air_temperature']\nweather_mean = weather_group.mean().astype(np.float16)\nweather_median = weather_group.median().astype(np.float16)\nweather_min = weather_group.min().astype(np.float16)\nweather_max = weather_group.max().astype(np.float16)\nweather_std = weather_group.std().astype(np.float16)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"building_mean.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n\ndef target_encoding(df):\n    df['building_mean'] = df['building_id'].map(building_mean)\n    df['building_median'] = df['building_id'].map(building_median)\n    df['building_min'] = df['building_id'].map(building_min)\n    df['building_max'] = df['building_id'].map(building_max)\n    df['building_range'] = df['building_max'] - df['building_min']\n    df['building_std'] = df['building_id'].map(building_std)\n    #efficiency per sqft\n    df['efficiency_per_sqft'] = df['square_feet'] / df['building_median']\n    df['weather_mean'] = df['site_id'].map(weather_mean)\n    df['weather_median'] = df['site_id'].map(weather_median)\n    df['weather_min'] = df['site_id'].map(weather_min)\n    df['weather_max'] = df['site_id'].map(weather_max)\n    df['weather_range'] = df['weather_max'] - df['weather_min']\n    df['weather_std'] = df['site_id'].map(weather_std)\n    #outliers\n    df['is_weather_outlier_2sd'] = (np.where(df['air_temperature'] > (df['weather_mean'] + 2 * df['weather_std']),1,\n                                        np.where(df['air_temperature'] < (df['weather_mean'] - 2 * df['weather_std']),1,0)))\n    df['is_weather_outlier_3sd'] = (np.where(df['air_temperature'] > (df['weather_mean'] + 3 * df['weather_std']),1,\n                                        np.where(df['air_temperature'] < (df['weather_mean'] - 3 * df['weather_std']),1,0)))     \n    df = reduce_mem_usage(df, use_float16=True)\n    return df\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train = target_encoding(X_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train.groupby('is_weather_outlier_2sd')['building_id'].count()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"building_std.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"                               ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train = X_train.drop(\"meter_reading\", axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_half_1 = X_train[:int(X_train.shape[0] / 2)]\nX_half_2 = X_train[int(X_train.shape[0] / 2):]\n\ny_half_1 = y_train[:int(X_train.shape[0] / 2)]\ny_half_2 = y_train[int(X_train.shape[0] / 2):]\n\ncategorical_features = ([\"building_id\", \"site_id\", \"meter\", \"primary_use\", \"hour\", \"weekday\",'is_wider_bus_hours',\n                         'is_weekend','season','daylight_savings','month'])\n\nd_half_1 = lgb.Dataset(X_half_1, label=y_half_1, categorical_feature=categorical_features, free_raw_data=False)\nd_half_2 = lgb.Dataset(X_half_2, label=y_half_2, categorical_feature=categorical_features, free_raw_data=False)\n\ndel X_half_1, X_half_2, y_half_1, y_half_2\n\nwatchlist_1 = [d_half_1, d_half_2]\nwatchlist_2 = [d_half_2, d_half_1]\n\nparams = {\n    \"objective\": \"regression\",\n    \"boosting\": \"gbdt\",\n    \"num_leaves\": 40,\n    \"learning_rate\": 0.05,\n    \"feature_fraction\": 0.85,\n    \"reg_lambda\": 2,\n    \"metric\": \"rmse\"\n}\n\nprint(\"Building model with first half and validating on second half:\")\nmodel_half_1 = lgb.train(params, train_set=d_half_1, num_boost_round=1000, valid_sets=watchlist_1, verbose_eval=200, early_stopping_rounds=200)\n\nprint(\"Building model with second half and validating on first half:\")\nmodel_half_2 = lgb.train(params, train_set=d_half_2, num_boost_round=1000, valid_sets=watchlist_2, verbose_eval=200, early_stopping_rounds=200)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"** Feature Importance **\n\nPlotting the feature importance from LGBM."},{"metadata":{"trusted":true},"cell_type":"code","source":"df_fimp_1 = pd.DataFrame()\ndf_fimp_1[\"feature\"] = X_train.columns.values\ndf_fimp_1[\"importance\"] = model_half_1.feature_importance()\ndf_fimp_1[\"half\"] = 1\n\ndf_fimp_2 = pd.DataFrame()\ndf_fimp_2[\"feature\"] = X_train.columns.values\ndf_fimp_2[\"importance\"] = model_half_2.feature_importance()\ndf_fimp_2[\"half\"] = 2\n\ndf_fimp = pd.concat([df_fimp_1, df_fimp_2], axis=0)\n\nplt.figure(figsize=(14, 7))\nsns.barplot(x=\"importance\", y=\"feature\", data=df_fimp.sort_values(by=\"importance\", ascending=False))\nplt.title(\"LightGBM Feature Importance\")\nplt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Preparing test data \n\nPreparing test data with same features as train data."},{"metadata":{"trusted":true},"cell_type":"code","source":"del X_train, d_half_1, d_half_2\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# import gc\n# import os\n# import random\n\n# import lightgbm as lgb\n# import numpy as np\n# import pandas as pd\n# import seaborn as sns\n\n# from matplotlib import pyplot as plt\n# from sklearn.metrics import mean_squared_error\n# from sklearn.preprocessing import LabelEncoder\n\ndf_test = pd.read_csv(path_test)\nweather_test = pd.read_csv(path_weather_test)\n\ndf_test = reduce_mem_usage(df_test)\nweather_test = reduce_mem_usage(weather_test)\n\nX_test, row_ids = prepare_data(df_test, building, weather_test, test=True)\n\nX_test = target_encoding(X_test)\nX_test = reduce_mem_usage(X_test)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del df_test, building, weather_test\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del df_group,building_mean,building_median,building_min,building_max,building_std\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nmodels = [model_half_1,model_half_2]\n\nfrom tqdm import tqdm\ni=0\npred=[]\nstep_size = 50000\nfor j in tqdm(range(int(np.ceil(X_test.shape[0]/50000)))):\n    pred.append(np.expm1(sum([model.predict(X_test.iloc[i:i+step_size], num_iteration=model.best_iteration) for model in models])/2))\n    i+=step_size\n\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n\npred = np.concatenate(pred)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# pred = np.expm1(model_half_1.predict(X_test, num_iteration=model_half_1.best_iteration)) / 2\n\ndel model_half_1\ngc.collect()\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# pred += np.expm1(model_half_2.predict(X_test, num_iteration=model_half_2.best_iteration)) / 2\n    \ndel model_half_2\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = pd.DataFrame({\"row_id\": row_ids, \"meter_reading\": np.clip(pred, 0, a_max=None)})\nsubmission.to_csv(\"submission.csv\", index=False)\nprint(\"DONE\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_pickle('GEPIII_V2_FE_20191117.pkl')","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}