{ "cells": [ { "cell_type": "code", "execution_count": 292, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Playing with the classic dataset, originally inspired by Andrey Lukyanenko's work at https://github.com/Erlemar/Erlemar.github.io/blob/master/Notebooks/Titanic.ipynb\n", "import os.path\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%reload_ext autoreload\n", "%autoreload 2\n", "%matplotlib inline\n", "import seaborn as sns\n", "sns.set_style('whitegrid')" ] }, { "cell_type": "code", "execution_count": 293, "metadata": { "collapsed": true }, "outputs": [], "source": [ "base_path = 'E:\\\\Projects\\\\titanic\\\\data'\n", "# Train / test data - start with data exploration, then circle back with train/test split\n", "df_train = pd.read_csv(os.path.join(base_path, 'train.csv'))\n", "# Kaggle test data\n", "df_test = pd.read_csv(os.path.join(base_path, 'test.csv'))" ] }, { "cell_type": "code", "execution_count": 294, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C
2313Heikkinen, Miss. Lainafemale26.000STON/O2. 31012827.9250NaNS
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01011380353.1000C123S
4503Allen, Mr. William Henrymale35.0003734508.0500NaNS
\n", "
" ], "text/plain": [ " PassengerId Survived Pclass \\\n", "0 1 0 3 \n", "1 2 1 1 \n", "2 3 1 3 \n", "3 4 1 1 \n", "4 5 0 3 \n", "\n", " Name Sex Age SibSp \\\n", "0 Braund, Mr. Owen Harris male 22.0 1 \n", "1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 \n", "2 Heikkinen, Miss. Laina female 26.0 0 \n", "3 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 \n", "4 Allen, Mr. William Henry male 35.0 0 \n", "\n", " Parch Ticket Fare Cabin Embarked \n", "0 0 A/5 21171 7.2500 NaN S \n", "1 0 PC 17599 71.2833 C85 C \n", "2 0 STON/O2. 3101282 7.9250 NaN S \n", "3 0 113803 53.1000 C123 S \n", "4 0 373450 8.0500 NaN S " ] }, "execution_count": 294, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_train.head()" ] }, { "cell_type": "code", "execution_count": 295, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([3, 1, 2], dtype=int64)" ] }, "execution_count": 295, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_train['Pclass'].unique()" ] }, { "cell_type": "code", "execution_count": 296, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Does the number of family members a passenger have affect survivability? \n", "# e.g., would assistance from parents, spouse, etc. help improve your chances?\n", "\n", "def family(df):\n", " df['Family'] = df['SibSp'] + df['Parch']\n", " return None\n", "\n", "def family2(sz):\n", " # Courtesy https://www.cdc.gov/mmwr/preview/mmwrhtml/mm4847a1.htm , average family size around this time is \n", " # 3.5 children --> 5.5 \n", " if sz == 1:\n", " return 'single'\n", " if sz < 5:\n", " return 'small'\n", " if sz > 6:\n", " return 'large'\n", " return 'medium'" ] }, { "cell_type": "code", "execution_count": 297, "metadata": { "collapsed": false }, "outputs": [], "source": [ "family(df_train)\n", "family(df_test)\n", "df_train['Family'] = df_train['Family'].apply(lambda x: family2(x))\n", "df_test['Family'] = df_test['Family'].apply(lambda x: family2(x))" ] }, { "cell_type": "code", "execution_count": 298, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "Pclass Family\n", "1 medium 0.500000\n", " single 0.728571\n", " small 0.584507\n", "2 medium 1.000000\n", " single 0.529412\n", " small 0.456376\n", "3 large 0.000000\n", " medium 0.137931\n", " single 0.350877\n", " small 0.242347\n", "Name: Survived, dtype: float64" ] }, "execution_count": 298, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_train['Family'].value_counts()\n", "df_train.groupby(['Pclass', 'Family'])['Survived'].mean()" ] }, { "cell_type": "code", "execution_count": 299, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 299, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure()\n", "df_train.pivot_table('PassengerId', 'Pclass', 'Survived', 'count').plot(kind='bar', stacked=True)" ] }, { "cell_type": "code", "execution_count": 300, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 Braund, Mr. Owen Harris\n", "1 Cumings, Mrs. John Bradley (Florence Briggs Th...\n", "2 Heikkinen, Miss. Laina\n", "3 Futrelle, Mrs. Jacques Heath (Lily May Peel)\n", "4 Allen, Mr. William Henry\n", "Name: Name, dtype: object" ] }, "execution_count": 300, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_train['Name'].head()" ] }, { "cell_type": "code", "execution_count": 301, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array(['Mr', 'Mrs', 'Miss', 'Master', 'Don', 'Rev', 'Dr', 'Mme', 'Ms',\n", " 'Major', 'Lady', 'Sir', 'Mlle', 'Col', 'Capt', 'Countess',\n", " 'Jonkheer'], dtype=object)" ] }, "execution_count": 301, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import re\n", "df_train['Title'] = df_train['Name'].apply(lambda x: (re.search(' ([a-zA-Z]+)\\.', x)).group(1))\n", "df_test['Title'] = df_test['Name'].apply(lambda x: (re.search(' ([a-zA-Z]+)\\.', x)).group(1))\n", "df_train['Title'].unique()" ] }, { "cell_type": "code", "execution_count": 302, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Have a look at rough social classes\n", "soclasses = {\n", " 'upper': ('Sir', 'Lady', 'Don', 'Countess', 'Jonkheer'), \n", " 'pro': ('Dr', 'Rev', 'Major', 'Col', 'Capt'), \n", " 'middle': ('Mr', 'Miss', 'Mrs', 'Master', 'Mlle', 'Ms', 'Mme')\n", "}\n", "for soclass in soclasses:\n", " df_train.loc[df_train['Title'].isin(soclasses[soclass]), 'SocialClass'] = soclass\n", " df_test.loc[df_test['Title'].isin(soclasses[soclass]), 'SocialClass'] = soclass\n", " \n", "df_train['SocialClass'].fillna('U', inplace=True)\n", "df_test['SocialClass'].fillna('U', inplace=True)" ] }, { "cell_type": "code", "execution_count": 303, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Fill in any missing ages with the median for the passenger class, sex, and social class\n", "def impute_age(df):\n", " df['Age'] = df.groupby(['Sex', 'Pclass', 'SocialClass'])['Age'].apply(lambda x: x.fillna(x.median()))\n", "\n", "impute_age(df_train)\n", "impute_age(df_test)" ] }, { "cell_type": "code", "execution_count": 304, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Fill in any missing ticket fares with the median for passenger class, sex, and age\n", "def impute_fare(df):\n", " df['Fare'] = df.groupby(['Sex', 'Pclass', 'Age'])['Fare'].apply(lambda x: x.fillna(x.median()))\n", "\n", "impute_fare(df_train)\n", "impute_fare(df_test)" ] }, { "cell_type": "code", "execution_count": 305, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
PassengerIdSurvivedPclassAgeSibSpParchFare
CabinNo
0442.5035970.3007192.63597127.1456830.5424460.36259019.110155
1377.2222220.7037041.55555627.3148150.4814810.59259362.023144
2560.6111110.8333331.00000042.7777780.4444440.11111150.349089
3466.4000000.5600001.00000037.7968000.6400000.92000096.852500
4396.3571430.7500001.17857136.3035710.3214290.32142959.593307
5563.4285710.6666671.00000039.5714290.3809520.33333365.937895
6410.0000000.7272731.09090932.1363640.3636360.636364156.446964
7549.0000000.6363641.00000033.2727270.7272730.818182104.447718
8437.6000000.7000001.10000036.7000000.5000000.00000088.854160
9345.8888890.3333331.00000039.0000000.4444440.22222287.845833
10483.7500000.7500001.00000033.7916670.6666670.750000112.423617
11414.4000000.8000001.30000040.9500000.2000000.00000073.920840
12363.5000000.0000001.00000033.5000000.0000000.50000028.725000
13488.7272730.6363641.36363637.1363640.3636360.27272757.465909
15890.0000001.0000001.00000026.0000000.0000000.00000030.000000
\n", "
" ], "text/plain": [ " PassengerId Survived Pclass Age SibSp Parch \\\n", "CabinNo \n", "0 442.503597 0.300719 2.635971 27.145683 0.542446 0.362590 \n", "1 377.222222 0.703704 1.555556 27.314815 0.481481 0.592593 \n", "2 560.611111 0.833333 1.000000 42.777778 0.444444 0.111111 \n", "3 466.400000 0.560000 1.000000 37.796800 0.640000 0.920000 \n", "4 396.357143 0.750000 1.178571 36.303571 0.321429 0.321429 \n", "5 563.428571 0.666667 1.000000 39.571429 0.380952 0.333333 \n", "6 410.000000 0.727273 1.090909 32.136364 0.363636 0.636364 \n", "7 549.000000 0.636364 1.000000 33.272727 0.727273 0.818182 \n", "8 437.600000 0.700000 1.100000 36.700000 0.500000 0.000000 \n", "9 345.888889 0.333333 1.000000 39.000000 0.444444 0.222222 \n", "10 483.750000 0.750000 1.000000 33.791667 0.666667 0.750000 \n", "11 414.400000 0.800000 1.300000 40.950000 0.200000 0.000000 \n", "12 363.500000 0.000000 1.000000 33.500000 0.000000 0.500000 \n", "13 488.727273 0.636364 1.363636 37.136364 0.363636 0.272727 \n", "15 890.000000 1.000000 1.000000 26.000000 0.000000 0.000000 \n", "\n", " Fare \n", "CabinNo \n", "0 19.110155 \n", "1 62.023144 \n", "2 50.349089 \n", "3 96.852500 \n", "4 59.593307 \n", "5 65.937895 \n", "6 156.446964 \n", "7 104.447718 \n", "8 88.854160 \n", "9 87.845833 \n", "10 112.423617 \n", "11 73.920840 \n", "12 28.725000 \n", "13 57.465909 \n", "15 30.000000 " ] }, "execution_count": 305, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Fill in missing Embarked info with 'U' (unknown)\n", "df_train['Embarked'].fillna('U', inplace=True)\n", "df_test['Embarked'].fillna('U', inplace=True)\n", "\n", "# Ditto Title...\n", "df_train['Title'].fillna('U', inplace=True)\n", "df_test['Title'].fillna('U', inplace=True)\n", "\n", "# ... and cabin info \n", "df_train['Cabin'].fillna('U0', inplace=True)\n", "df_test['Cabin'].fillna('U0', inplace=True)\n", "# Add a deck feature\n", "df_train['CabinDeck'] = df_train['Cabin'].map(lambda x: x[0])\n", "df_test['CabinDeck'] = df_test['Cabin'].map(lambda x: x[0])\n", "\n", "# Deck layouts look like cabin numbers might be interesting (low numbers are aft)\n", "def cabin_num(x):\n", " toks = x.split()\n", " try:\n", " val = int(toks[0][1:])\n", " except Exception as err:\n", " val = 0\n", " finally:\n", " return val\n", " \n", "# Try grouping in groups of 10\n", "def grpcabin(x):\n", " grp = 0\n", " for i in range(0, 1000, 10):\n", " if x > i:\n", " grp += 1\n", " else:\n", " return grp\n", " \n", "df_train['CabinNo'] = df_train['Cabin'].map(lambda x: cabin_num(x)).apply(grpcabin)\n", "df_test['CabinNo'] = df_test['Cabin'].map(lambda x: cabin_num(x)).apply(grpcabin)\n", "df_train.groupby(['CabinNo']).mean()" ] }, { "cell_type": "code", "execution_count": 306, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
PassengerIdSurvivedPclassAgeSibSpParchFareCabinNo
PassengerId1.000000-0.005007-0.0351440.040091-0.057527-0.0016520.0126580.029668
Survived-0.0050071.000000-0.338481-0.059662-0.0353220.0816290.2573070.243628
Pclass-0.035144-0.3384811.000000-0.4113960.0830810.018443-0.549500-0.603300
Age0.040091-0.059662-0.4113961.000000-0.249289-0.1749040.1220790.240026
SibSp-0.057527-0.0353220.083081-0.2492891.0000000.4148380.159651-0.035054
Parch-0.0016520.0816290.018443-0.1749040.4148381.0000000.2162250.007560
Fare0.0126580.257307-0.5495000.1220790.1596510.2162251.0000000.427849
CabinNo0.0296680.243628-0.6033000.240026-0.0350540.0075600.4278491.000000
\n", "
" ], "text/plain": [ " PassengerId Survived Pclass Age SibSp Parch \\\n", "PassengerId 1.000000 -0.005007 -0.035144 0.040091 -0.057527 -0.001652 \n", "Survived -0.005007 1.000000 -0.338481 -0.059662 -0.035322 0.081629 \n", "Pclass -0.035144 -0.338481 1.000000 -0.411396 0.083081 0.018443 \n", "Age 0.040091 -0.059662 -0.411396 1.000000 -0.249289 -0.174904 \n", "SibSp -0.057527 -0.035322 0.083081 -0.249289 1.000000 0.414838 \n", "Parch -0.001652 0.081629 0.018443 -0.174904 0.414838 1.000000 \n", "Fare 0.012658 0.257307 -0.549500 0.122079 0.159651 0.216225 \n", "CabinNo 0.029668 0.243628 -0.603300 0.240026 -0.035054 0.007560 \n", "\n", " Fare CabinNo \n", "PassengerId 0.012658 0.029668 \n", "Survived 0.257307 0.243628 \n", "Pclass -0.549500 -0.603300 \n", "Age 0.122079 0.240026 \n", "SibSp 0.159651 -0.035054 \n", "Parch 0.216225 0.007560 \n", "Fare 1.000000 0.427849 \n", "CabinNo 0.427849 1.000000 " ] }, "execution_count": 306, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_train.corr()" ] }, { "cell_type": "code", "execution_count": 307, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 307, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEjCAYAAAAomJYLAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzt3Xd8VFX+//HXpAEplBDAQu+CshgViCz4ENQNuBikJEEcpKqrqBQpIn0lhBpdVkFYpBOagAiKu1G+RFGqFEFaQomIkNCUCZCQzP39wS8jkQFDEu6dwPv5eMzjwcydzHkPhPnMOefec2yGYRiIiIj8gZfVAURExDOpQIiIiFsqECIi4pYKhIiIuKUCISIibvlYHcCj7PnY6gRUbd3P6ghX2LytToCPkW11BACyvYpZHQHDmWF1BGxWB/j/rP/NvCLp6NGCv8jNfObUb1/w9m6SehAiN+AJxUHEKioQIiLiloaYREQsYmTnfRjViiE+FQgREYsYly/l+bkqECIid5Kb6EFYQXMQIiLilnoQIiIWMbKzrI5wQyoQIiJWUYEQERF3jMvWXwB5I5qDEBERt/60QGzatImwsDDsdjt2u53IyEjmzZtnRrZC0bRp02seS0xMZPDgwRakERH5nZGdlefb1ZxOJ8OHDycqKgq73c7RPyz7MX36dCIiIujcuTPr1q3Ld748DTE1adKEuLg4ADIzMwkPDyciIoKSJUvmu2ERkTtePucgEhISyMzMZPHixezYsYPY2FimTp0KwP79+1m9ejVLly4FIDo6miZNmlCiRImbbuem5yAcDgdeXl7s27ePf//73wBcunSJcePGcc899/DGG2/gcDi4dOkSAwYMoHHjxgwePJiUlBQyMjLo0aMHrVu3ZvPmzcTFxeHt7U2lSpUYPXo0n376KevXr+fSpUukpKTQq1cv2rVrx65duxg1ahQBAQGULVuWYsWKERsby7x581i9ejU2m43WrVvTpUsXBg8ezLlz5zh37hwffvihK3dycjJDhgyhRIkSlChRglKlSt30X5aISGEynPm7DmLbtm00a9YMgIYNG7J7927XseTkZBo1akSxYlfWEatSpQr79++nYcOGN91OngrExo0bsdvt2Gw2fH19GTZsGAcPHmTChAlUqFCBadOmsXbtWp544glOnTrF7NmzOX36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l19+6fogMAyDc+fO8emnn5rSdmZmJmvWrGHBggX4+fnhcDj48ssvKV68uCnt53jjjTcYOHAg9957L/369WPz5s0MGDCA9957z9QcAOvXr6dr1654e3ub3vbVEhMTSUxMJCYmhm7dujFq1CjT2o6MjCQgIIAtW7Zgt9uBK705m83GokWLTMtRFKlAFIKxY8dy+PBhUlJSqFOnDuXLlzc9Q2hoKBMmTCA9PZ127drRunVr0z8YAd5//32GDRvGokWLaNy4Md9++61pbbdo0YK///3vTJw4kapVq9KzZ09L/g4aNGjA0qVLXfcbNmxIQkKCJd9cz549S7NmzahYsaLrIjUrPhRLly6Nn58f6enpVKlSJdfaULfaF198YVpbtxsViEJw9eJwzz77LEePHjV9cbjw8HDCw8NJTU1l7NixxMTEsHWr+Vt2lilThgcffJBFixbRrl07li9fblrbXbp0YfXq1fz888906NDB8lVcf/jhB0aMGMGpU6e45557GDVqlOkX7Zl1Wu+fueuuu1i2bBklSpRg0qRJOBwO09q+9957gSsnLyQmJpKZmXnNMXFPp7kWgjVr1jB79myCgoJ44YUX2Llzp+kZjh8/zvvvv0+vXr0oXrw4M2bMMD0DXLkobcuWLWRlZfH111/nWgLkVnvxxRdZtWoVdrud1atXs3v3biZMmMCBAwdMy3C1MWPGMH78eBITExk1apSpwyo5srKyWL16NStWrGDFihV8+OGHprb/wQcfADB69Ghq1KjBwIEDKV++PHFxcabmAHjllVf46quvSE5OJjk5mUOHDpmeoahRD6IQ5HxTzVnrxoolhF977TU6duzIggULTF3z549GjRrFoUOH+Mc//sF7773H66+/bnqGRo0a0ahRI3777Tc++eQTBg4cyMqVK03PUaxYMdecUJ06dSwZYho0aBCPP/4433//PeXLlzftVN8cGzdu5JVXXsHLy4u4uDjmzp3rmgcwm2EYTJw40ZK2iyoViEJg5eJwJ06c4K677mLChAmuaxByvrWbuShbzuJwcGU4Aa6c0WTFHgg5SpYsid1uN/0DafHixQD4+PgwcuRIHnnkEXbt2mVJ4S5evDgvvfQSR44cYezYsTz33HOmtn/1MJ/VQ3516tRh586d3Hfffa7HtB/EjalAFAIrF4ebNWsWb731FiNGjMj1uNmLsl0952Kz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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#print(df_train.columns)\n", "# So far the most interesting attributes for Survival are Fare, CabinNo, and Pclass\n", "features = [\"Fare\", \"CabinNo\", \"Pclass\"]\n", "plt.figure()\n", "sns.heatmap(df_train.corr(), center=0)" ] }, { "cell_type": "code", "execution_count": 308, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "PassengerId int64\n", "Survived int64\n", "Pclass int64\n", "Name object\n", "Sex object\n", "Age float64\n", "SibSp int64\n", "Parch int64\n", "Ticket object\n", "Fare float64\n", "Cabin object\n", "Embarked object\n", "Family object\n", "Title object\n", "SocialClass object\n", "CabinDeck object\n", "CabinNo int64\n", "dtype: object" ] }, "execution_count": 308, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Closer look at the columns\n", "df_train.dtypes" ] }, { "cell_type": "code", "execution_count": 309, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Ticket prefix might be interesting, ticket number maybe not so much\n", "tmp = df_train['Ticket'].str.split()\n", "df_train['TicketPrefix'] = tmp.apply(lambda x: x[0] + x[1] if len(x) == 3 else (x[0] if len(x) == 2 else 'U'))\n", "tmp = df_test['Ticket'].str.split()\n", "df_test['TicketPrefix'] = tmp.apply(lambda x: x[0] + x[1] if len(x) == 3 else (x[0] if len(x) == 2 else 'U'))" ] }, { "cell_type": "code", "execution_count": 310, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from sklearn.preprocessing import LabelEncoder, LabelBinarizer\n", "\n", "def onehot_column(df, col):\n", " enc = LabelBinarizer()\n", " arr = enc.fit_transform(df[col])\n", " df[col] = arr\n", " \n", "\n", "def encode_column(df, col):\n", " enc = LabelEncoder()\n", " arr = enc.fit_transform(df[col])\n", " df[col] = arr" ] }, { "cell_type": "code", "execution_count": 311, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# One hot encode categorical columns w/o ordinality\n", "for col in ['Sex', 'TicketPrefix', 'Embarked', 'Title']:\n", " onehot_column(df_train, col)\n", " onehot_column(df_test, col)\n", " \n", "# Label encode categorical columns with ordinality\n", "for col in ['CabinDeck', 'CabinNo', 'Family', 'SocialClass']:\n", " encode_column(df_train, col)\n", " encode_column(df_test, col)" ] }, { "cell_type": "code", "execution_count": 312, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
PassengerIdSurvivedPclassSexAgeSibSpParchFareEmbarkedFamilyTitleSocialClassCabinDeckCabinNoTicketPrefix
PassengerId1.000000-0.005007-0.0351440.0429390.040091-0.057527-0.0016520.012658-0.0012050.0692800.0390970.061248-0.0309390.029036-0.024342
Survived-0.0050071.000000-0.338481-0.543351-0.059662-0.0353220.0816290.2573070.168240-0.000495-0.0264560.002855-0.3011160.243581-0.037436
Pclass-0.035144-0.3384811.0000000.131900-0.4113960.0830810.018443-0.549500-0.2432920.014747-0.052496-0.1884780.746616-0.6038090.039243
Sex0.042939-0.5433510.1319001.0000000.101603-0.114631-0.245489-0.182333-0.0828530.1519120.0247280.0560260.123076-0.0991870.034990
Age0.040091-0.059662-0.4113960.1016031.000000-0.249289-0.1749040.1220790.0426760.1231100.1032080.184765-0.2928540.240570-0.021745
SibSp-0.057527-0.0353220.083081-0.114631-0.2492891.0000000.4148380.159651-0.059528-0.7172400.014507-0.0231710.041540-0.034931-0.022508
Parch-0.0016520.0816290.018443-0.245489-0.1749040.4148381.0000000.216225-0.011069-0.4275660.025731-0.059277-0.0325480.007763-0.022467
Fare0.0126580.257307-0.549500-0.1823330.1220790.1596510.2162251.0000000.269335-0.2089330.0261840.018150-0.5230130.428670-0.023068
Embarked-0.0012050.168240-0.243292-0.0828530.042676-0.059528-0.0110690.2693351.000000-0.002195-0.0161580.052302-0.2430170.159167-0.022864
Family0.069280-0.0004950.0147470.1519120.123110-0.717240-0.427566-0.208933-0.0021951.0000000.0164830.0217720.058118-0.0443990.023323
Title0.039097-0.026456-0.0524960.0247280.1032080.0145070.0257310.026184-0.0161580.0164831.0000000.159064-0.0779070.021410-0.001590
SocialClass0.0612480.002855-0.1884780.0560260.184765-0.023171-0.0592770.0181500.0523020.0217720.1590641.000000-0.1253160.051488-0.007303
CabinDeck-0.030939-0.3011160.7466160.123076-0.2928540.041540-0.032548-0.523013-0.2430170.058118-0.077907-0.1253161.000000-0.7875900.024762
CabinNo0.0290360.243581-0.603809-0.0991870.240570-0.0349310.0077630.4286700.159167-0.0443990.0214100.051488-0.7875901.000000-0.020222
TicketPrefix-0.024342-0.0374360.0392430.034990-0.021745-0.022508-0.022467-0.023068-0.0228640.023323-0.001590-0.0073030.024762-0.0202221.000000
\n", "
" ], "text/plain": [ " PassengerId Survived Pclass Sex Age SibSp \\\n", "PassengerId 1.000000 -0.005007 -0.035144 0.042939 0.040091 -0.057527 \n", "Survived -0.005007 1.000000 -0.338481 -0.543351 -0.059662 -0.035322 \n", "Pclass -0.035144 -0.338481 1.000000 0.131900 -0.411396 0.083081 \n", "Sex 0.042939 -0.543351 0.131900 1.000000 0.101603 -0.114631 \n", "Age 0.040091 -0.059662 -0.411396 0.101603 1.000000 -0.249289 \n", "SibSp -0.057527 -0.035322 0.083081 -0.114631 -0.249289 1.000000 \n", "Parch -0.001652 0.081629 0.018443 -0.245489 -0.174904 0.414838 \n", "Fare 0.012658 0.257307 -0.549500 -0.182333 0.122079 0.159651 \n", "Embarked -0.001205 0.168240 -0.243292 -0.082853 0.042676 -0.059528 \n", "Family 0.069280 -0.000495 0.014747 0.151912 0.123110 -0.717240 \n", "Title 0.039097 -0.026456 -0.052496 0.024728 0.103208 0.014507 \n", "SocialClass 0.061248 0.002855 -0.188478 0.056026 0.184765 -0.023171 \n", "CabinDeck -0.030939 -0.301116 0.746616 0.123076 -0.292854 0.041540 \n", "CabinNo 0.029036 0.243581 -0.603809 -0.099187 0.240570 -0.034931 \n", "TicketPrefix -0.024342 -0.037436 0.039243 0.034990 -0.021745 -0.022508 \n", "\n", " Parch Fare Embarked Family Title SocialClass \\\n", "PassengerId -0.001652 0.012658 -0.001205 0.069280 0.039097 0.061248 \n", "Survived 0.081629 0.257307 0.168240 -0.000495 -0.026456 0.002855 \n", "Pclass 0.018443 -0.549500 -0.243292 0.014747 -0.052496 -0.188478 \n", "Sex -0.245489 -0.182333 -0.082853 0.151912 0.024728 0.056026 \n", "Age -0.174904 0.122079 0.042676 0.123110 0.103208 0.184765 \n", "SibSp 0.414838 0.159651 -0.059528 -0.717240 0.014507 -0.023171 \n", "Parch 1.000000 0.216225 -0.011069 -0.427566 0.025731 -0.059277 \n", "Fare 0.216225 1.000000 0.269335 -0.208933 0.026184 0.018150 \n", "Embarked -0.011069 0.269335 1.000000 -0.002195 -0.016158 0.052302 \n", "Family -0.427566 -0.208933 -0.002195 1.000000 0.016483 0.021772 \n", "Title 0.025731 0.026184 -0.016158 0.016483 1.000000 0.159064 \n", "SocialClass -0.059277 0.018150 0.052302 0.021772 0.159064 1.000000 \n", "CabinDeck -0.032548 -0.523013 -0.243017 0.058118 -0.077907 -0.125316 \n", "CabinNo 0.007763 0.428670 0.159167 -0.044399 0.021410 0.051488 \n", "TicketPrefix -0.022467 -0.023068 -0.022864 0.023323 -0.001590 -0.007303 \n", "\n", " CabinDeck CabinNo TicketPrefix \n", "PassengerId -0.030939 0.029036 -0.024342 \n", "Survived -0.301116 0.243581 -0.037436 \n", "Pclass 0.746616 -0.603809 0.039243 \n", "Sex 0.123076 -0.099187 0.034990 \n", "Age -0.292854 0.240570 -0.021745 \n", "SibSp 0.041540 -0.034931 -0.022508 \n", "Parch -0.032548 0.007763 -0.022467 \n", "Fare -0.523013 0.428670 -0.023068 \n", "Embarked -0.243017 0.159167 -0.022864 \n", "Family 0.058118 -0.044399 0.023323 \n", "Title -0.077907 0.021410 -0.001590 \n", "SocialClass -0.125316 0.051488 -0.007303 \n", "CabinDeck 1.000000 -0.787590 0.024762 \n", "CabinNo -0.787590 1.000000 -0.020222 \n", "TicketPrefix 0.024762 -0.020222 1.000000 " ] }, "execution_count": 312, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# The originally interesting features were Fare, CabinNo, and Pclass - where are we now?\n", "plt.figure()\n", "sns.heatmap(df_train.corr(), center=0)\n", "df_train.corr()" ] }, { "cell_type": "code", "execution_count": 313, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Looks like Sex, Embarked, and CabinDeck can be added; maybe Age, SibSp, Parch, Title, and TicketPrefix\n", "features = ['Fare', 'CabinNo', 'Pclass', 'Sex', 'Embarked', 'CabinDeck', 'Age', 'SibSp', 'Parch', 'Title', 'TicketPrefix']" ] }, { "cell_type": "code", "execution_count": 314, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
FareCabinNoPclassSexEmbarkedCabinDeckAgeSibSpParchTitleTicketPrefix
count891.000000891.000000891.000000891.000000891.000000891.000000891.000000891.000000891.000000891.000000891.000000
mean32.2042081.2008982.3086420.6475870.1885526.71604929.0911000.5230080.3815940.0011220.002245
std49.6934292.8182870.8360710.4779900.3913722.46073913.2939421.1027430.8060570.0335010.047351
min0.0000000.0000001.0000000.0000000.0000000.0000000.4200000.0000000.0000000.0000000.000000
25%7.9104000.0000002.0000000.0000000.0000008.00000021.5000000.0000000.0000000.0000000.000000
50%14.4542000.0000003.0000001.0000000.0000008.00000026.0000000.0000000.0000000.0000000.000000
75%31.0000000.0000003.0000001.0000000.0000008.00000036.0000001.0000000.0000000.0000000.000000
max512.32920014.0000003.0000001.0000001.0000008.00000080.0000008.0000006.0000001.0000001.000000
\n", "
" ], "text/plain": [ " Fare CabinNo Pclass Sex Embarked CabinDeck \\\n", "count 891.000000 891.000000 891.000000 891.000000 891.000000 891.000000 \n", "mean 32.204208 1.200898 2.308642 0.647587 0.188552 6.716049 \n", "std 49.693429 2.818287 0.836071 0.477990 0.391372 2.460739 \n", "min 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 \n", "25% 7.910400 0.000000 2.000000 0.000000 0.000000 8.000000 \n", "50% 14.454200 0.000000 3.000000 1.000000 0.000000 8.000000 \n", "75% 31.000000 0.000000 3.000000 1.000000 0.000000 8.000000 \n", "max 512.329200 14.000000 3.000000 1.000000 1.000000 8.000000 \n", "\n", " Age SibSp Parch Title TicketPrefix \n", "count 891.000000 891.000000 891.000000 891.000000 891.000000 \n", "mean 29.091100 0.523008 0.381594 0.001122 0.002245 \n", "std 13.293942 1.102743 0.806057 0.033501 0.047351 \n", "min 0.420000 0.000000 0.000000 0.000000 0.000000 \n", "25% 21.500000 0.000000 0.000000 0.000000 0.000000 \n", "50% 26.000000 0.000000 0.000000 0.000000 0.000000 \n", "75% 36.000000 1.000000 0.000000 0.000000 0.000000 \n", "max 80.000000 8.000000 6.000000 1.000000 1.000000 " ] }, "execution_count": 314, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_train[features].describe()" ] }, { "cell_type": "code", "execution_count": 315, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 549\n", "1 342\n", "Name: Survived, dtype: int64" ] }, "execution_count": 315, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Let's scale Fare \n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.preprocessing import Imputer\n", "\n", "def scale_col(df, col):\n", " imp = Imputer(missing_values='NaN', strategy='mean', axis=0)\n", " df[col] = imp.fit_transform(df[[col]])\n", " scaler = StandardScaler()\n", " df[col] = scaler.fit_transform(df[[col]])\n", "\n", "scale_col(df_train, 'Fare')\n", "scale_col(df_test, 'Fare')\n", "df_train[features].describe()\n", "# How are we doing for class balance?\n", "df_train['Survived'].value_counts()" ] }, { "cell_type": "code", "execution_count": 316, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{0: 0.38383838383838387, 1: 0.6161616161616161}" ] }, "execution_count": 316, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Not bad but let's try balancing\n", "classes = df_train['Survived'].unique().tolist()\n", "weights = {\n", " k: 1 - len(df_train[df_train['Survived'] == k]) / len(df_train['Survived']) for k in classes\n", "}\n", "weights" ] }, { "cell_type": "code", "execution_count": 317, "metadata": {}, "outputs": [], "source": [ "# Try adding Euclidean distances from centroids \n", "from sklearn.cluster import KMeans\n", "train = df_train[features].copy()\n", "kmeans = KMeans().fit(train)\n", "\n", "def add_kmeans_features(df):\n", " train_dists = kmeans.transform(df[features])\n", " for col in range(train_dists.shape[1]):\n", " colname = 'dist{0}'.format(col)\n", " df.loc[:, colname] = train_dists[:,col]\n", " scale_col(df, colname)\n", " \n", "add_kmeans_features(df_train)\n", "add_kmeans_features(df_test)\n", "features.extend([col for col in train if col.startswith('dist')])" ] }, { "cell_type": "code", "execution_count": 318, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " PassengerId Survived Pclass \\\n", "0 1 0 3 \n", "1 2 1 1 \n", "2 3 1 3 \n", "3 4 1 1 \n", "4 5 0 3 \n", "\n", " Name Sex Age SibSp Parch \\\n", "0 Braund, Mr. Owen Harris 1 22.0 1 0 \n", "1 Cumings, Mrs. John Bradley (Florence Briggs Th... 0 38.0 1 0 \n", "2 Heikkinen, Miss. Laina 0 26.0 0 0 \n", "3 Futrelle, Mrs. Jacques Heath (Lily May Peel) 0 35.0 1 0 \n", "4 Allen, Mr. William Henry 1 35.0 0 0 \n", "\n", " Ticket Fare ... CabinNo TicketPrefix dist0 \\\n", "0 A/5 21171 -0.502445 ... 0 0 -0.598335 \n", "1 PC 17599 0.786845 ... 9 0 0.766014 \n", "2 STON/O2. 3101282 -0.488854 ... 0 0 -0.282673 \n", "3 113803 0.420730 ... 13 0 0.642272 \n", "4 373450 -0.486337 ... 0 0 0.415993 \n", "\n", " dist1 dist2 dist3 dist4 dist5 dist6 dist7 \n", "0 -0.925502 0.514910 -0.270365 0.535674 0.113658 -0.891430 0.326868 \n", "1 0.651874 -0.882697 0.118371 -0.687792 -1.746630 0.748394 -0.605323 \n", "2 -0.891656 0.140627 -0.756014 0.218261 -0.313025 -0.536712 -0.136768 \n", "3 0.676027 -0.454536 0.367183 -0.367780 -1.428689 0.677730 -0.109918 \n", "4 -0.004193 -0.691096 -0.969891 -0.494080 -0.827510 0.281679 -1.175283 \n", "\n", "[5 rows x 26 columns]\n" ] } ], "source": [ "print(df_train.head())" ] }, { "cell_type": "code", "execution_count": 319, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Fitting 5 folds for each of 15 candidates, totalling 75 fits\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "[Parallel(n_jobs=7)]: Done 36 tasks | elapsed: 16.5s\n", "[Parallel(n_jobs=7)]: Done 75 out of 75 | elapsed: 1.0min finished\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Metrics: Best score = 0.8013468013468014 using params = {'C': 10, 'kernel': 'rbf'}\n", "\n", "Fitting 5 folds for each of 1470 candidates, totalling 7350 fits\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "[Parallel(n_jobs=7)]: Done 36 tasks | elapsed: 8.3s\n", "[Parallel(n_jobs=7)]: Done 186 tasks | elapsed: 20.9s\n", "[Parallel(n_jobs=7)]: Done 436 tasks | elapsed: 42.6s\n", "[Parallel(n_jobs=7)]: Done 786 tasks | elapsed: 1.2min\n", "[Parallel(n_jobs=7)]: Done 1236 tasks | elapsed: 1.9min\n", "[Parallel(n_jobs=7)]: Done 1786 tasks | elapsed: 2.7min\n", "[Parallel(n_jobs=7)]: Done 2436 tasks | elapsed: 3.6min\n", "[Parallel(n_jobs=7)]: Done 3186 tasks | elapsed: 4.9min\n", "[Parallel(n_jobs=7)]: Done 4036 tasks | elapsed: 6.4min\n", "[Parallel(n_jobs=7)]: Done 4986 tasks | elapsed: 8.0min\n", "[Parallel(n_jobs=7)]: Done 6036 tasks | elapsed: 9.5min\n", "[Parallel(n_jobs=7)]: Done 7186 tasks | elapsed: 11.2min\n", "[Parallel(n_jobs=7)]: Done 7350 out of 7350 | elapsed: 11.4min finished\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Metrics: Best score = 0.8103254769921436 using params = {'min_samples_split': 0.1, 'class_weight': None, 'n_jobs': -1, 'verbose': True, 'criterion': 'entropy', 'max_features': None, 'oob_score': True, 'n_estimators': 50}\n", "Model and metadata saved to 'titanic_rf_1522592121.pkl'\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "[Parallel(n_jobs=-1)]: Done 34 tasks | elapsed: 0.0s\n", "[Parallel(n_jobs=-1)]: Done 50 out of 50 | elapsed: 0.0s finished\n" ] } ], "source": [ "from sklearn.externals import joblib\n", "import sklearn\n", "import multiprocessing as mp\n", "import sys\n", "import time\n", "import platform\n", "from sklearn.model_selection import GridSearchCV\n", "from sklearn.svm import SVC\n", "from sklearn.ensemble import RandomForestClassifier\n", "\n", "\n", "def persist_model(mdl, basename, **kwargs):\n", " version = sys.version_info\n", " metadata = {\n", " 'versions': {\n", " 'python': '{0}.{1}.{2}'.format(version.major, version.minor, version.micro),\n", " 'pandas': pd.__version__,\n", " 'sklearn': sklearn.__version__\n", " }\n", " }\n", " if kwargs is not None:\n", " metadata.update(**kwargs)\n", " outname = '{0}_{1}.pkl'.format(basename, int(time.time()))\n", " bndl = {\n", " 'model': mdl,\n", " 'metadata': metadata\n", " }\n", " joblib.dump(clf, outname)\n", " return outname\n", "\n", "\n", "def grid_search(clz, X, y, parameters=None):\n", " clf = GridSearchCV(estimator=clz, param_grid=parameters, verbose=1, n_jobs=mp.cpu_count() - 1, cv=5)\n", " clf.fit(X, y)\n", " return clf\n", "\n", "\n", "# We'll look at an SVC first, then use it as a benchmark of sorts for the Random Forest model.\n", "\n", "def find_svc(X, y):\n", " parameters = {'kernel':('linear', 'rbf', 'sigmoid'), 'C': [1, 10, 0.5, 0.75, 0.25]}\n", " return grid_search(SVC(), X, y, parameters)\n", "\n", "train = df_train.copy()\n", "clf = find_svc(train[features], train['Survived'])\n", "print('Metrics: Best score = {0} using params = {1}\\n'.format(clf.best_score_, clf.best_params_))\n", "\n", "\n", "def find_rf(X, y):\n", " parameters = {\n", " 'n_estimators': [10, 20, 50, 64, 100, 128, 256], \n", " 'criterion': ['gini', 'entropy'],\n", " 'max_features': ['sqrt', 'log2', None, 0.1, 0.25, 0.5, 0.75],\n", " 'min_samples_split': [0.1, 0.25, 0.5, 0.75, 1.0],\n", " 'verbose': [True],\n", " 'oob_score': [True],\n", " 'class_weight': [weights, \"balanced_subsample\", None],\n", " 'n_jobs': [-1]\n", " }\n", " return grid_search(RandomForestClassifier(), X, y, parameters)\n", "\n", "train = df_train.copy()\n", "clf2 = find_rf(train[features], train['Survived'])\n", "print('Metrics: Best score = {0} using params = {1}'.format(clf2.best_score_, clf2.best_params_))\n", "\n", " \n", "saved_model = persist_model(clf2, 'titanic_rf', features=features)\n", "print(\"Model and metadata saved to '{0}'\".format(saved_model))" ] }, { "cell_type": "code", "execution_count": 320, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[Parallel(n_jobs=8)]: Done 34 tasks | elapsed: 0.0s\n", "[Parallel(n_jobs=8)]: Done 50 out of 50 | elapsed: 0.0s finished\n" ] } ], "source": [ "# Ok let's do this\n", "submission_df = pd.DataFrame(\n", " {\n", " 'PassengerId': df_test['PassengerId'],\n", " 'Survived': clf2.predict(df_test[features])\n", " }\n", ")" ] }, { "cell_type": "code", "execution_count": 321, "metadata": {}, "outputs": [], "source": [ "submission = submission_df.to_csv(\n", " 'titanic.csv',\n", " index=False\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python [conda root]", "language": "python", "name": "conda-root-py" }, "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.5.4" } }, "nbformat": 4, "nbformat_minor": 2 }