{"cells":[{"metadata":{"_uuid":"bc5b2734c00697336eecee60cf238bd50a1d3070"},"cell_type":"markdown","source":"# Keras Tensorflow DNN Approach"},{"metadata":{"_kg_hide-input":true,"_uuid":"7c2a2d316dba1e9991d64239efbd8a3223121c84","trusted":true},"cell_type":"code","source":"# Import necessary everyday os libs\nimport gc\nimport sys\nfrom time import time\n\n# Import the usual suspects\nimport numpy as np\nimport pandas as pd","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d36c37f23687bf6e4960b9746e8fcc3979e6edee"},"cell_type":"markdown","source":"### Useful functions for community"},{"metadata":{"_uuid":"1fdf37704af1b4d12bad3252572c241972888efe","trusted":true},"cell_type":"code","source":"# Universal pandas dataframe memory footprint reducer for those dealing with big data but not that big that require spark\ndef df_footprint_reduce(df, skip_obj=False, skip_int=False, skip_float=False, print_comparison=True):\n    '''\n    :param df              : Pandas Dataframe to shrink in memory footprint size\n    :param skip_obj        : If not desired string columns can be skipped during shrink operation\n    :param skip_int        : If not desired integer columns can be skipped during shrink operation\n    :param skip_float      : If not desired float columns can be skipped during shrink operation\n    :param print_comparison: Beware! Printing comparison needs calculation of each columns datasize\n                             so if you need speed turn this off. It's just here to show you info                            \n    :return                : Pandas Dataframe of exactly the same data and dtypes but in less memory footprint    \n    '''\n    if print_comparison:\n        print(f\"Dataframe size before shrinking column types into smallest possible: {round((sys.getsizeof(df)/1024/1024),4)} MB\")\n    for column in df.columns:\n        if (skip_obj is False) and (str(df[column].dtype)[:6] == 'object'):\n            num_unique_values = len(df[column].unique())\n            num_total_values = len(df[column])\n            if num_unique_values / num_total_values < 0.5:\n                df.loc[:,column] = df[column].astype('category')\n            else:\n                df.loc[:,column] = df[column]\n        elif (skip_int is False) and (str(df[column].dtype)[:3] == 'int'):\n            if df[column].min() > np.iinfo(np.int8).min and df[column].max() < np.iinfo(np.int8).max:\n                df[column] = df[column].astype(np.int8)\n            elif df[column].min() > np.iinfo(np.int16).min and df[column].max() < np.iinfo(np.int16).max:\n                df[column] = df[column].astype(np.int16)\n            elif df[column].min() > np.iinfo(np.int32).min and df[column].max() < np.iinfo(np.int32).max:\n                df[column] = df[column].astype(np.int32)\n        elif (skip_float is False) and (str(df[column].dtype)[:5] == 'float'):\n            if df[column].min() > np.finfo(np.float16).min and df[column].max() < np.finfo(np.float16).max:\n                df[column] = df[column].astype(np.float16)\n            elif df[column].min() > np.finfo(np.float32).min and df[column].max() < np.finfo(np.float32).max:\n                df[column] = df[column].astype(np.float32)\n    if print_comparison:\n        print(f\"Dataframe size after shrinking column types into smallest possible: {round((sys.getsizeof(df)/1024/1024),4)} MB\")\n    return df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e9aba5bc151434e954627191f1163bc757f74256","trusted":true},"cell_type":"code","source":"# Universal pandas dataframe null/nan cleaner\ndef df_null_cleaner(df, fill_with=None, drop_na=False, axis=0):\n    '''\n    Very good information on dealing with missing values of dataframes can be found at \n    http://pandas.pydata.org/pandas-docs/stable/missing_data.html\n    \n    :param df        : Pandas Dataframe to clean from missing values \n    :param fill_with : Fill missing values with a value of users choice\n    :param drop_na   : Drop either axis=0 for rows containing missing fields\n                       or axis=1 to drop columns having missing fields default rows                   \n    :return          : Pandas Dataframe cleaned from missing values \n    '''\n    df[(df == np.NINF)] = np.NaN\n    df[(df == np.Inf)] = np.NaN\n    if drop_na:\n        df.dropna(axis=axis,inplace=True)\n    if ~fill_with:\n        df.fillna(fill_with, inplace=True)\n    return df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b1df154cb3cafaf7eb72075a94865de7d21e8aee"},"cell_type":"markdown","source":"### Feature Engineering"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"def feature_engineering(df,is_train=True):\n    if is_train:          \n        df = df[df['maxPlace'] > 1].copy()\n\n    target = 'winPlacePerc'\n    print('Grouping similar match types together')\n    df.loc[(df['matchType'] == 'solo'), 'matchType'] = 1\n    df.loc[(df['matchType'] == 'normal-solo'), 'matchType'] = 1\n    df.loc[(df['matchType'] == 'solo-fpp'), 'matchType'] = 1\n    df.loc[(df['matchType'] == 'normal-solo-fpp'), 'matchType'] = 1\n\n    df.loc[(df['matchType'] == 'duo'), 'matchType'] = 2\n    df.loc[(df['matchType'] == 'normal-duo'), 'matchType'] = 2\n    df.loc[(df['matchType'] == 'duo-fpp'), 'matchType'] = 2    \n    df.loc[(df['matchType'] == 'normal-duo-fpp'), 'matchType'] = 2\n\n    df.loc[(df['matchType'] == 'squad'), 'matchType'] = 3\n    df.loc[(df['matchType'] == 'normal-squad'), 'matchType'] = 3    \n    df.loc[(df['matchType'] == 'squad-fpp'), 'matchType'] = 3\n    df.loc[(df['matchType'] == 'normal-squad-fpp'), 'matchType'] = 3\n    \n    df.loc[(df['matchType'] == 'flaretpp'), 'matchType'] = 0\n    df.loc[(df['matchType'] == 'flarefpp'), 'matchType'] = 0\n    df.loc[(df['matchType'] == 'crashtpp'), 'matchType'] = 0\n    df.loc[(df['matchType'] == 'crashfpp'), 'matchType'] = 0\n    df.loc[(df['rankPoints'] < 0), 'rankPoints'] = 0\n    \n    print('Adding new features using existing ones')\n    df['headshotrate'] = df['kills']/df['headshotKills']\n    df['killStreakrate'] = df['killStreaks']/df['kills']\n    df['healthitems'] = df['heals'] + df['boosts']\n    df['totalDistance'] = df['rideDistance'] + df[\"walkDistance\"] + df[\"swimDistance\"]\n    df['killPlace_over_maxPlace'] = df['killPlace'] / df['maxPlace']\n    df['headshotKills_over_kills'] = df['headshotKills'] / df['kills']\n    df['distance_over_weapons'] = df['totalDistance'] / df['weaponsAcquired']\n    df['walkDistance_over_heals'] = df['walkDistance'] / df['heals']\n    df['walkDistance_over_kills'] = df['walkDistance'] / df['kills']\n    df['killsPerWalkDistance'] = df['kills'] / df['walkDistance']\n    df['skill'] = df['headshotKills'] + df['roadKills']\n    \n    # Clean null values from dataframe\n    df = df_null_cleaner(df,fill_with=0)\n\n    features = list(df.columns)\n    features.remove(\"Id\")\n    features.remove(\"matchId\")\n    features.remove(\"groupId\")\n    features.remove(\"matchType\")\n    features.remove(\"maxPlace\")\n    \n    y = pd.DataFrame()\n    if is_train: \n        print('Preparing target variable')\n        y = df.groupby(['matchId','groupId'])[target].agg('mean')\n        gc.collect()\n        features.remove(target)\n        \n    print('Aggregating means')   \n    agg = df.groupby(['matchId','groupId'])[features].agg('mean')\n    gc.collect()\n    agg_rank = agg.groupby('matchId')[features].rank(pct=True).reset_index()\n    gc.collect()\n    \n    if is_train: \n        X = agg.reset_index()[['matchId','groupId']]\n    else: \n        X = df[['matchId','groupId']]\n\n    X = X.merge(agg.reset_index(), suffixes=[\"\", \"\"], how='left', on=['matchId', 'groupId'])\n    X = X.merge(agg_rank, suffixes=[\"_mean\", \"_mean_rank\"], how='left', on=['matchId', 'groupId'])\n    del agg, agg_rank\n    gc.collect()\n    \n    print('Aggregating maxes')\n    agg = df.groupby(['matchId','groupId'])[features].agg('max')\n    gc.collect()\n    agg_rank = agg.groupby('matchId')[features].rank(pct=True).reset_index()\n    gc.collect()\n    X = X.merge(agg.reset_index(), suffixes=[\"\", \"\"], how='left', on=['matchId', 'groupId'])\n    X = X.merge(agg_rank, suffixes=[\"_max\", \"_max_rank\"], how='left', on=['matchId', 'groupId'])\n    del agg, agg_rank\n    gc.collect()\n    \n    print('Aggregating mins')  \n    agg = df.groupby(['matchId','groupId'])[features].agg('min')\n    gc.collect()\n    agg_rank = agg.groupby('matchId')[features].rank(pct=True).reset_index()\n    gc.collect()\n    X = X.merge(agg.reset_index(), suffixes=[\"\", \"\"], how='left', on=['matchId', 'groupId'])\n    X = X.merge(agg_rank, suffixes=[\"_min\", \"_min_rank\"], how='left', on=['matchId', 'groupId'])\n    del agg, agg_rank\n    gc.collect()\n    \n    print('Aggregating group sizes')\n    agg = df.groupby(['matchId','groupId']).size().reset_index(name='group_size')\n    gc.collect()\n    X = X.merge(agg, how='left', on=['matchId', 'groupId'])\n    print('Aggregating match means')\n    agg = df.groupby(['matchId'])[features].agg('mean').reset_index()\n    gc.collect()\n    X = X.merge(agg, suffixes=[\"\", \"_match_mean\"], how='left', on=['matchId'])\n    print('Aggregating match sizes')\n    agg = df.groupby(['matchId']).size().reset_index(name='match_size')\n    gc.collect()\n    X = X.merge(agg, how='left', on=['matchId'])\n    del df, agg\n    gc.collect()\n\n    X.drop(columns = ['matchId', \n                      'groupId'\n                     ], axis=1, inplace=True)  \n    gc.collect()\n    if is_train:\n        return X, y\n    \n    return X","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"acaeafd9712a8b5946ca3bfc3d1ef2893b1d932e"},"cell_type":"markdown","source":"### Load dataset files"},{"metadata":{"_uuid":"38de01e68ad32007b2bac8c56262abddff5a6e20","trusted":true},"cell_type":"code","source":"X_train = pd.read_csv('../input/train_V2.csv', engine='c')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8c846d045dab5175a97f986386e49c6732ca92b1","trusted":true},"cell_type":"code","source":"X_train = df_footprint_reduce(X_train, skip_obj=True)  # Reduce memory footprint inorder to fit in memory of Kaggle Docker image\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"10342c72924553bfb9d1b1d0f725f568fab1f57a","trusted":true},"cell_type":"code","source":"X_train, y_train = feature_engineering(X_train, True)\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bdb60c79b454933645e22723fc4d5ea12876b0b1","trusted":true},"cell_type":"code","source":"X_train = df_footprint_reduce(X_train, skip_obj=True) # Reduce memory footprint again after feature generation\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0cad0417be2fb5e00890ceda174a7185bfb66cb6"},"cell_type":"code","source":"from sklearn import preprocessing\nscaler = preprocessing.MinMaxScaler(feature_range=(-1, 1), copy=False).fit(X_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f8dcbf7b8884560103b7324f536007221c288ee2"},"cell_type":"code","source":"X_train = scaler.transform(X_train)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7dc38d2a385ef7a6ed3b3c81b2458d40a0ee2654"},"cell_type":"markdown","source":"### Model Training"},{"metadata":{"_uuid":"cc454bf3ec6c5b51d587cae4613f6db03639f3d6","trusted":true},"cell_type":"code","source":"# Import the real deal\nfrom keras.models import Sequential\nfrom keras.layers import Dense\nfrom keras import backend","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"763ca434994a43c216925bd169e595552f71dfdd"},"cell_type":"code","source":"swish = lambda x: x*backend.sigmoid(x)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"80937f125d09cf50c76bfae76bfe8fd72a011466","scrolled":true,"trusted":true},"cell_type":"code","source":"# create model\nmodel = Sequential()\nmodel.add(Dense(X_train.shape[1], input_dim=X_train.shape[1], kernel_initializer='normal', activation = swish))\nmodel.add(Dense(round((X_train.shape[1]/3)*2), kernel_initializer='normal', activation = swish))\n\n# output Layer\nmodel.add(Dense(1, kernel_initializer='normal'))\n\n# Compile the network :\nmodel.compile(loss='mae', optimizer='adam', metrics=['mae'])\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1350a31ef54319cfd731eae3d9773a77b8236a6e"},"cell_type":"code","source":"seed = 13\nnp.random.seed(seed)\nfrom tensorflow import set_random_seed\nset_random_seed(seed)","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true,"_uuid":"30887fbe12e88b4dd92d3b10a1983e1fe9ca9452"},"cell_type":"code","source":"import time\ntimeout = time.time() + 120\nwhile True:\n    model.fit(x=X_train, y=y_train, batch_size=96,\n                epochs=1, verbose=0,\n                validation_split=0.2, shuffle=True)\n    if time.time() > timeout:\n        break","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"64d3df607437644eaa6f662023ed9c34acfa488c","trusted":true},"cell_type":"code","source":"# Clean memory and load test set\ndel X_train, y_train\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1d17412eedf1fb70949f5748869a88103ff9a290"},"cell_type":"markdown","source":"### Model Prediction "},{"metadata":{"_uuid":"6af69ac8e410d04e7b3c2d10215240b0b5340404","trusted":true},"cell_type":"code","source":"test_x = pd.read_csv('../input/test_V2.csv', engine='c')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6af69ac8e410d04e7b3c2d10215240b0b5340404","trusted":true},"cell_type":"code","source":"test_x = df_footprint_reduce(test_x, skip_obj=True)\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6af69ac8e410d04e7b3c2d10215240b0b5340404","trusted":true},"cell_type":"code","source":"test_x = feature_engineering(test_x, False)\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d4b172683e85ae266eba0774e333b1116a9992cc"},"cell_type":"code","source":"test_x = scaler.transform(test_x)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6af69ac8e410d04e7b3c2d10215240b0b5340404","trusted":true},"cell_type":"code","source":"%%time\npred_test = model.predict(test_x)\ndel test_x\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ac73a39852e2525dd814cc6e778bec3662e8c824","trusted":true},"cell_type":"code","source":"test_set = pd.read_csv('../input/test_V2.csv', engine='c')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"92b2322f47c3f74e004e4c83413e2b6784682645"},"cell_type":"markdown","source":"### Prepare for submission "},{"metadata":{"_uuid":"b1fa4f2e37a750b551390f081815ef250f383793","trusted":true},"cell_type":"code","source":"submission = pd.read_csv(\"../input/sample_submission_V2.csv\")\nsubmission['winPlacePerc'] = pred_test\nsubmission.loc[submission.winPlacePerc < 0, \"winPlacePerc\"] = 0\nsubmission.loc[submission.winPlacePerc > 1, \"winPlacePerc\"] = 1\nsubmission = submission.merge(test_set[[\"Id\", \"matchId\", \"groupId\", \"maxPlace\", \"numGroups\"]], on=\"Id\", how=\"left\")\nsubmission_group = submission.groupby([\"matchId\", \"groupId\"]).first().reset_index()\nsubmission_group[\"rank\"] = submission_group.groupby([\"matchId\"])[\"winPlacePerc\"].rank()\nsubmission_group = submission_group.merge(\n    submission_group.groupby(\"matchId\")[\"rank\"].max().to_frame(\"max_rank\").reset_index(), \n    on=\"matchId\", how=\"left\")\nsubmission_group[\"adjusted_perc\"] = (submission_group[\"rank\"] - 1) / (submission_group[\"numGroups\"] - 1)\nsubmission = submission.merge(submission_group[[\"adjusted_perc\", \"matchId\", \"groupId\"]], on=[\"matchId\", \"groupId\"], how=\"left\")\nsubmission[\"winPlacePerc\"] = submission[\"adjusted_perc\"]\nsubmission.loc[submission.maxPlace == 0, \"winPlacePerc\"] = 0\nsubmission.loc[submission.maxPlace == 1, \"winPlacePerc\"] = 1\nsubset = submission.loc[submission.maxPlace > 1]\ngap = 1.0 / (subset.maxPlace.values - 1)\nnew_perc = np.around(subset.winPlacePerc.values / gap) * gap\nsubmission.loc[submission.maxPlace > 1, \"winPlacePerc\"] = new_perc\nsubmission.loc[(submission.maxPlace > 1) & (submission.numGroups == 1), \"winPlacePerc\"] = 0\nassert submission[\"winPlacePerc\"].isnull().sum() == 0\nsubmission[[\"Id\", \"winPlacePerc\"]].to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fd57cc46b626cc88bc84f8490555d5d5f57f1cbe"},"cell_type":"markdown","source":"##### Credits for work at post processing section goes to:\n###### https://www.kaggle.com/anycode/simple-nn-baseline-4\n###### https://www.kaggle.com/ceshine/a-simple-post-processing-trick-lb-0237-0204"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}