Kaggle, Python

Kaggle: PUBG Swag (Parte 1)

Battlegrounds es un videojuego de acción en el cual hasta 100 jugadores pelean en una Batalla Real (Battle Royale), un tipo de combate a muerte (Deathmatch) en cual hay enfrentamientos para ser el último con vida. Los jugadores pueden ingresar a la partida en solitario, o con un pequeño equipo compuesto por el propio jugador y una persona más (formando un Duo) o por tres personas además del propio jugador (formando un Squad). En cualquier caso, la última persona o equipo con vida gana la partida.

Qué es PUBG? https://www.youtube.com/watch?v=BRqdgBppd5g

Kaggle creó una competencia para predecir los posibles ganadores de una partida de acuerdo a diferentes variables, este post tratará principalmente del análisis previo de los datos y la creación de un dataset limpio.

Kaggle Description https://www.kaggle.com/c/pubg-finish-placement-prediction

In a PUBG game, up to 100 players start in each match (matchId). Players can be on teams (groupId) which get ranked at the end of the game (winPlacePerc) based on how many other teams are still alive when they are eliminated. In game, players can pick up different munitions, revive downed-but-not-out (knocked) teammates, drive vehicles, swim, run, shoot, and experience all of the consequences — such as falling too far or running themselves over and eliminating themselves.

You are provided with a large number of anonymized PUBG game stats, formatted so that each row contains one player’s post-game stats. The data comes from matches of all types: solos, duos, squads, and custom; there is no guarantee of there being 100 players per match, nor at most 4 player per group.

You must create a model which predicts players’ finishing placement based on their final stats, on a scale from 1 (first place) to 0 (last place).

File descriptions
train.csv – the training set
test.csv – the test set
sample_submission.csv – a sample submission file in the correct format

Data fields
DBNOs – Number of enemy players knocked.
assists – Number of enemy players this player damaged that were killed by teammates.
boosts – Number of boost items used.
damageDealt – Total damage dealt. Note: Self inflicted damage is subtracted.
headshotKills – Number of enemy players killed with headshots.
heals – Number of healing items used.
killPlace – Ranking in match of number of enemy players killed.
killPoints – Kills-based external ranking of player. (Think of this as an Elo ranking where only kills matter.)
killStreaks – Max number of enemy players killed in a short amount of time.
kills – Number of enemy players killed.
longestKill – Longest distance between player and player killed at time of death. This may be misleading, as downing a player and driving away may lead to a large longestKill stat.
matchId – Integer ID to identify match. There are no matches that are in both the training and testing set.
revives – Number of times this player revived teammates.
rideDistance – Total distance traveled in vehicles measured in meters.
roadKills – Number of kills while in a vehicle.
swimDistance – Total distance traveled by swimming measured in meters.
teamKills – Number of times this player killed a teammate.
vehicleDestroys – Number of vehicles destroyed.
walkDistance – Total distance traveled on foot me asured in meters.
weaponsAcquired – Number of weapons picked up.
winPoints – Win-based external ranking of player. (Think of this as an Elo ranking where only winning matters.)
groupId – Integer ID to identify a group within a match. If the same group of players plays in different matches, they will have a different groupId each time.
numGroups – Number of groups we have data for in the match.
maxPlace – Worst placement we have data for in the match. This may not match with numGroups, as sometimes the data skips over placements.
winPlacePerc – The target of prediction. This is a percentile winning placement, where 1 corresponds to 1st place, and 0 corresponds to last place in the match. It is calculated off of maxPlace, not numGroups, so it is possible to have missing chunks in a match.

Empezamos el análisis

1. Importamos las librerias

In [1]:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
In [2]:
%matplotlib inline

2. Importamos el dataset de entrenamiento

In [3]:
train = pd.read_csv("data/train.csv")

Top 5 de los datos del dataset

In [4]:
train.head()
Out[4]:
tabla1
5 rows × 26 columns

3. Análisis de los datos del dataset

Número de Registros

In [5]:
train.Id.count()
Out[5]:
4357336

Validamos los valores únicos. Según la descripción los campos Id y groupId son identificadores que se generan en cada partida.

In [6]:
train.nunique()
#any(data['Id'].duplicated())
Out[6]:
Id                 4357336
groupId            1888732
matchId              47734
assists                 20
boosts                  19
damageDealt          31726
DBNOs                   40
headshotKills           25
heals                   50
killPlace              100
killPoints            1762
kills                   44
killStreaks             15
longestKill          26405
maxPlace                99
numGroups              100
revives                 22
rideDistance         33158
roadKills               14
swimDistance         27652
teamKills                7
vehicleDestroys          6
walkDistance         38048
weaponsAcquired         69
winPoints             1465
winPlacePerc          2949
dtype: int64

Obtenemos los tipos de datos de las columnas

In [7]:
train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4357336 entries, 0 to 4357335
Data columns (total 26 columns):
Id                 int64
groupId            int64
matchId            int64
assists            int64
boosts             int64
damageDealt        float64
DBNOs              int64
headshotKills      int64
heals              int64
killPlace          int64
killPoints         int64
kills              int64
killStreaks        int64
longestKill        float64
maxPlace           int64
numGroups          int64
revives            int64
rideDistance       float64
roadKills          int64
swimDistance       float64
teamKills          int64
vehicleDestroys    int64
walkDistance       float64
weaponsAcquired    int64
winPoints          int64
winPlacePerc       float64
dtypes: float64(6), int64(20)
memory usage: 864.3 MB

Obtenemos una descripción general de las columnas

In [8]:
train.describe()
Out[8]:
tabla2
8 rows × 26 columns

Obtenemos los nombres de las columnas.

In [9]:
train.columns
Out[9]:
Index(['Id', 'groupId', 'matchId', 'assists', 'boosts', 'damageDealt', 'DBNOs',
       'headshotKills', 'heals', 'killPlace', 'killPoints', 'kills',
       'killStreaks', 'longestKill', 'maxPlace', 'numGroups', 'revives',
       'rideDistance', 'roadKills', 'swimDistance', 'teamKills',
       'vehicleDestroys', 'walkDistance', 'weaponsAcquired', 'winPoints',
       'winPlacePerc'],
      dtype='object')

Verificamos por valores vacíos

In [10]:
train[train['groupId'].isnull()]
##sns.heatmap(train.isnull(),yticklabels=False,cbar=False,cmap='viridis')
Out[10]:
tabla3
0 rows × 26 columns

De acuerdo a lo visto no existen valores vacíos para este dataset.

4. Calidad de los datos

En este caso, para validar correctamente los datos necesitamos analizar los grupos y jugadores que hay en el dataset. Una partida generalmente tiene 100 participantes y los grupos que se desean analizar son para partidas individuales y partidas de grupos máximo de 4 personas. (https://www.kaggle.com/aparida/ingredients-for-chicken-dinner)

Primero analizamos los grupos y los números de jugadores por grupo

In [11]:
groupIdData=pd.DataFrame(train['groupId'].value_counts())
groupIdData.reset_index(level=0, inplace=True)
groupIdData.columns = ['groupId', 'Members']
groupIdData.head()
Out[11]:
groupId Members
0 1268134 96
1 1193309 93
2 2685082 76
3 737999 58
4 1223908 57

Después de una agrupación inicial observamos que hay grupos hasta de 96 miembros. Procedemos a eliminar los grupos invalidos de nuestro nuevo Data Frame.

In [12]:
groupIdDataValid=groupIdData[groupIdData['Members']<=4]
groupIdDataValid.head()
Out[12]:
groupId Members
121162 975060 4
121163 650171 4
121164 1794687 4
121165 1517641 4
121166 1890608 4

Analizamos la cantida de personas por partida.

In [13]:
matchIdData=pd.DataFrame(train['matchId'].value_counts())
matchIdData.reset_index(level=0, inplace=True)
matchIdData.columns = ['matchId', 'Players']
matchIdData.head()
Out[13]:
matchId Players
0 27978 100
1 13502 100
2 44049 100
3 9406 100
4 38870 100

Validamos algunos datos básicos

In [14]:
matchIdData['Players'].describe()
Out[14]:
count    47734.000000
mean        91.283697
std         12.754878
min          1.000000
25%         92.000000
50%         95.000000
75%         97.000000
max        100.000000
Name: Players, dtype: float64

Tenemos que en general la cantidad de jugadores es mayor a 90, pero tenemos partidas con valores de 1 como se observa para el valor mínimo. Procedemos a analizar y eliminar partidas con pocos jugadores.

In [15]:
plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
sns.distplot(matchIdData['Players'])
plt.subplot(1,2,2)
sns.boxplot(x='Players',data=matchIdData)
Out[15]:
output_34_2
In [16]:
matchIdData.matchId.count()
Out[16]:
47734
In [17]:
matchIdData[matchIdData['Players']<60].count()
Out[17]:
matchId    1278
Players    1278
dtype: int64

Consideraremos una partida valida aquella con más de 60 jugadores

In [18]:
matchIdDataValid=matchIdData[matchIdData['Players']>=60]
matchIdDataValid.tail()
Out[18]:
matchId Players
46451 8480 60
46452 23899 60
46453 35155 60
46454 34064 60
46455 35094 60

5. Preparación del dataset final

Actualizamos nuestro dataset eliminando los datos que consideramos validos acorde a los jugadores y número correcto de integrantes de los grupos

In [19]:
len(train['Id'])
Out[19]:
4357336
In [20]:
groupIdDataValidList=list(groupIdDataValid['groupId'])
train=train[train['groupId'].isin(groupIdDataValidList)]
matchIdDataValidList=list(matchIdDataValid['matchId'])
train=train[train['matchId'].isin(matchIdDataValidList)]
len(train['Id'])
Out[20]:
3558385

Algunos otros datos

In [21]:
train['assists'].describe()
Out[21]:
count    3.558385e+06
mean     2.787866e-01
std      6.345059e-01
min      0.000000e+00
25%      0.000000e+00
50%      0.000000e+00
75%      0.000000e+00
max      1.100000e+01
Name: assists, dtype: float64
In [22]:
train['boosts'].describe()
Out[22]:
count    3.558385e+06
mean     1.096366e+00
std      1.644609e+00
min      0.000000e+00
25%      0.000000e+00
50%      0.000000e+00
75%      2.000000e+00
max      1.800000e+01
Name: boosts, dtype: float64
In [23]:
train['damageDealt'].describe()
Out[23]:
count    3.558385e+06
mean     1.416230e+02
std      1.712703e+02
min      0.000000e+00
25%      1.323000e+01
50%      9.800000e+01
75%      2.000000e+02
max      3.914000e+03
Name: damageDealt, dtype: float64
In [24]:
killing=train[['kills','headshotKills','roadKills','teamKills']]
killing.describe(include='all')
Out[24]:
kills headshotKills roadKills teamKills
count 3.558385e+06 3.558385e+06 3.558385e+06 3.558385e+06
mean 1.009990e+00 2.574800e-01 2.795088e-03 1.329985e-02
std 1.580765e+00 6.249494e-01 6.622079e-02 1.288142e-01
min 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
25% 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
50% 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
75% 1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
max 4.200000e+01 2.400000e+01 4.200000e+01 4.000000e+00
In [25]:
train['heals'].describe()
Out[25]:
count    3.558385e+06
mean     1.315262e+00
std      2.468125e+00
min      0.000000e+00
25%      0.000000e+00
50%      0.000000e+00
75%      2.000000e+00
max      5.800000e+01
Name: heals, dtype: float64
In [26]:
train['revives'].describe()
Out[26]:
count    3.558385e+06
mean     1.766096e-01
std      4.797476e-01
min      0.000000e+00
25%      0.000000e+00
50%      0.000000e+00
75%      0.000000e+00
max      4.100000e+01
Name: revives, dtype: float64
In [27]:
train['weaponsAcquired'].describe()
Out[27]:
count    3.558385e+06
mean     3.615773e+00
std      2.225022e+00
min      0.000000e+00
25%      2.000000e+00
50%      3.000000e+00
75%      5.000000e+00
max      6.200000e+01
Name: weaponsAcquired, dtype: float64
In [28]:
train['totalDistance']=train.walkDistance+train.rideDistance+train.swimDistance
travel=train[['walkDistance','rideDistance','swimDistance','totalDistance']]
travel.describe(include='all')
Out[28]:
walkDistance rideDistance swimDistance totalDistance
count 3.558385e+06 3.558385e+06 3.558385e+06 3.558385e+06
mean 1.174604e+03 4.714695e+02 4.693540e+00 1.650767e+03
std 1.147880e+03 1.286089e+03 2.887615e+01 1.958949e+03
min 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
25% 1.718000e+02 0.000000e+00 0.000000e+00 1.743000e+02
50% 7.800000e+02 0.000000e+00 0.000000e+00 9.033000e+02
75% 2.000000e+03 0.000000e+00 0.000000e+00 2.548000e+03
max 1.544000e+04 4.839000e+04 5.286000e+03 4.953100e+04
In [29]:
Elo=train[['winPoints','killPoints']]
Elo.describe(include='all')
Out[29]:
winPoints killPoints
count 3.558385e+06 3.558385e+06
mean 1.502246e+03 1.083111e+03
std 3.414144e+01 1.224232e+02
min 3.560000e+02 1.570000e+02
25% 1.492000e+03 1.000000e+03
50% 1.500000e+03 1.031000e+03
75% 1.511000e+03 1.129000e+03
max 1.923000e+03 2.047000e+03

Análisis bivariado

In [30]:
dropCols = ['Id', 'groupId', 'matchId']
keepCols = [col for col in train.columns if col not in dropCols]
corr = train[keepCols].corr()
plt.figure(figsize=(15,10))
plt.title("Correlation Heat Map of Data")
sns.heatmap(corr,annot=True,cmap="RdYlGn")
Out[30]:
output_54_1.png

Con el análisis de correlación observamos que la variable maxPlace y numGroups están totalmente correlacionadas. Eliminamos una de ellas.

In [39]:
#'maxPlace'=='numGroups'
train=train.drop(['maxPlace'], axis=1)
In [41]:
plt.figure(figsize=(15,10))
keepCols = [col for col in train.columns if col not in dropCols]
corr = train[keepCols].corr()
sns.heatmap(corr,annot=True,cmap="PiYG")
Out[41]:
output_57_1

Exportamos nuestro dataset limpio

In [32]:
train.columns
Out[32]:
Index(['Id', 'groupId', 'matchId', 'assists', 'boosts', 'damageDealt', 'DBNOs',
       'headshotKills', 'heals', 'killPlace', 'killPoints', 'kills',
       'killStreaks', 'longestKill', 'numGroups', 'revives', 'rideDistance',
       'roadKills', 'swimDistance', 'teamKills', 'vehicleDestroys',
       'walkDistance', 'weaponsAcquired', 'winPoints', 'winPlacePerc',
       'totalDistance'],
      dtype='object')
In [35]:
train.to_csv('./data/cleanedTrain.csv')

Conclusion

En este artículo vimos la primera parte de la limpieza de datos del dataset de Battlegrounds enfocado principalmente en que los valores de cantidad de jugadores y miembros de equipos esten de acuerdo a la realidad que son equipos de 1 a 4 personas y partidas mínimo de 60 personas.
En el próximo artículo crearemos nuevas variables usando Feature Engineering.
Jupyter, Kaggle, Machine Learning, Python

Kaggle: Titanic, comenzando con Machine Learning

 Titanic

Soy nuevo en estos temas pero después de mucho tiempo estudiando un poco aquí y allá decidí comenzar con mi primer artículo de Machine Learning, espero comparar varios algoritmos usando el dataset del Titanic y encontrar el que sea mas acertado. Bienvenidos!

El Titanic es el dataset que Kaggle usa para enseñar a los miembros el uso del Machine Learning y el uso de Kaggle. Es un ejemplo sencillo que tiene multiples campos de los pasajeros además de tener el campo que indica si sobrevivió o no. El ejemplo incluye los datasets:

  • training set (train.csv)
  • test set (test.csv)

Training set este dataset es el que se debe utilizar para crear los modelos de Machine Learning.

Test set este dataset es el que se usará para validar como se comportan los modelos que creaste; es decir, que tan acertado fuimos en decir quien sobrevive o no.

Data Dictionary

Definicion de la tabla tomado de Kaggle

Variable Definition Key
survival Survival 0 = No, 1 = Yes
pclass Ticket class 1 = 1st, 2 = 2nd, 3 = 3rd
sex Sex
Age Age in years
sibsp # of siblings / spouses aboard the Titanic
parch # of parents / children aboard the Titanic
ticket Ticket number
fare Passenger fare
cabin Cabin number
embarked Port of Embarkation C = Cherbourg, Q = Queenstown, S = Southampton

Si quieren saber más información de los datasets les recomiendo ir a la página de Kaggle y mirar los comentarios que hacen acerca de estos.

Análisis de los datos

Lo primero que debemos realizar cuando vamos a comenzar un proceso de Machine Learning (ML) es saber como son los datos con los que estamos trabajando, cómo están distribuidos, cómo se relacionan, encontrar valores nulos, etc.

Importar librerias

In [1]:
import pandas as pd               #Para manejo de datos
import seaborn as sns             #Para realizar gráficas
import matplotlib.pyplot as plt   #Para algunos parámetros de las gráficas
#Para visualizar las gráficas en el notebook
%matplotlib inline

Importar datasets

Importamos los archivos csv que tiene la página de Kaggle, usamos Pandas read_csv para esto

In [2]:
titanic_train = pd.read_csv('train.csv')
titanic_test = pd.read_csv('test.csv')

Analizamos los datasets

En esta parte simplemente estamos viendo la información que cargamos en las variables que creamos a partir de los archivos, que en este caso corresponden a DataFrames de Pandas.

A primera vista podemos ver que el dataset de train tiene la columna Survived y el de Train no la tiene, esto se debe a que la idea del ejercicio es determinar los valores de esta columna para el dataset de test.

In [3]:
titanic_train.head()
Out[3]:
TitanicTabla1
In [4]:
titanic_test.head()
Out[4]:
TitanicTabla2

Más análisis del dataset Train

En esta parte vemos que nuestro dataset tiene 891 filas y que las columnas Age, Cabin y Embarked tienen menos datos que las demás. Además en la parte de abajo podemos ver datos como la media y la desviación estándar, etc.

In [5]:
titanic_train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB
In [6]:
titanic_train.describe()
Out[6]:
TitanicTabla3

Visualizamos los datos

Ahora intentamos obtener un resumen gráfico de los datos para tener una mejor idea de los datos con los cuales estamos trabajando. Como yo me vi la película Titanic recuerdo una frase que decía “Mujeres y niños primero”, intentemos ver que tan acertado es esa afirmación.

In [7]:
# Utilizamos Seaborn countplot para realizar la gráfica
# Gráfica por género
sns.countplot(x='Survived',data=titanic_train,hue='Sex',palette='muted')
plt.title('Gráfica por género')
 Out[7]:
TitanicFig1

Observamos que efectivamente hay más mujeres que se salvaron en el titanic que hombres. Ahora intentemos ver la distribución por edades. En esta observamos que los niños si tuvieron prioridad.

In [8]:
g = sns.FacetGrid(titanic_train, col='Survived')
g.map(sns.distplot, 'Age', bins=20)
Out[8]:
TitanicFig2

Siguiendo con el análisis visual de los datos tenemos. Según recuerdo en la película (no es una fuente confiable) se embarcaban los mejor posicionados económicamente primero. Miremos la gráfica por clase.

In [9]:
# Gráfica por clase
sns.countplot(x='Survived',data=titanic_train,hue='Pclass',palette='muted')
plt.title('Gráfica por clase')
Out[9]:
TitanicFig3

Aunque no es válido decir que se salvaron más de una clase o de otra dado que los números están muy cercanos, es bueno anotar que habían muchas más personas en la tercera clase que en primera, teniendo eso en cuenta la distribución aumenta.

Ahora intentemos analizar como es la distribución entre número de familiares y chance de sobrevivir.

In [10]:
titanic_train['FamilyNum'] = titanic_train['SibSp'] + titanic_train['Parch']
In [11]:
sns.countplot(x='FamilyNum',data=titanic_train,hue='Survived',palette='muted')
Out[11]:
TitanicFig4

Feature Engineering

Ya hemos visto como se comportan algunos datos, ahora intentemos llenar los datos vacíos y ver que otros grupos de datos podemos crear.
Primero tenemos dos columnas que tienen datos faltantes Age y Cabin, intentemos completar los datos.

In [12]:
#Cabin
titanic_train['Cabin'].apply(lambda x: str(x)[0]).value_counts()
Out[12]:
n    687
C     59
B     47
D     33
E     32
A     15
F     13
G      4
T      1
Name: Cabin, dtype: int64

En este caso para Cabin hay demasiados valores faltantes para Cabin y no destaca ningún valor que podamos ussar para obtener los valores faltantes (n).
Empezamos a crear nuestro DataFrame para aplicar nuestro algoritmo, para eso empezamos analizando que columnas utilizaremos para la predicción. La columna Cabin tiene muchos valores faltantes, la columnas PassengerId es simplemente un número consecutivo, la columna Ticket no parece tener ninguna relación con el campo Survived, la columna Name es solamente el nombre del pasajero y obviamente la columna Survived es la que tenemos que encontrar.
Eliminamos todas estas columnas de nuestro dataset para predicciones

In [13]:
titanic_train.columns
Out[13]:
Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
       'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked', 'FamilyNum'],
      dtype='object')
In [14]:
ds = titanic_train[['Pclass', 'Sex', 'Age', 'SibSp','Parch', 'Fare', 'Embarked', 'FamilyNum']]
In [15]:
ds.head()
Out[15]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 male 22.0 1 0 7.2500 S 1
1 1 female 38.0 1 0 71.2833 C 1
2 3 female 26.0 0 0 7.9250 S 0
3 1 female 35.0 1 0 53.1000 S 1
4 3 male 35.0 0 0 8.0500 S 0

Para Age podemos crear grupos:

1 – 0 a 5
2 – 6 a 10
3 – 11 a 15
4 – 16 a 20
5 – 21 a 30
6 – 31 a 45
7 – 46 a 60
8 – >61
9 – Otros

Y de paso podemos hacer lo mismo para Fare:

1 – 0 a 100
2 – >100 a 200
3 – >200 a 300
4 – >300 a 400
5 – >400 a 500
6 – >500

Muchas operaciones!!!!

Para este punto hemos añadido la columna de FamilyNum, eliminado 5 columnas y estamos a punto de crear dos columnas más. Recordemos que además de trabajar con el dataset de titanic_train también tenemos que hacer las mismas operaciones con el dataset titanic_test así que debemos ir pensando en la manera de replicar las operaciones para el dataset faltante.

In [16]:
#Creamos el proceso

#Eliminamos las columnas
def eliminarColumnas(datos):
    return datos[['Pclass', 'Sex', 'Age', 'SibSp','Parch', 'Fare', 'Embarked']]

#Agregamos la columna FamilyNum
def agregarFamilyNum(datos):
    datos['FamilyNum'] = datos['SibSp'] + datos['Parch']
    return datos

#Creamos los grupos para Age
def gruposAge(valor):
    if valor > 0 and valor <= 5:
        return 1
    elif valor > 5 and valor <= 10:
        return 2
    elif valor > 10 and valor <= 15:
        return 3
    elif valor > 15 and valor <= 20:
        return 4
    elif valor > 20 and valor <= 30:
        return 5
    elif valor > 30 and valor <= 45:
        return 6
    elif valor > 45 and valor <= 60:
        return 7
    elif valor > 60:
        return 8
    else:
        return 9
    
#Creamos los grupos para Fare
def gruposFare(valor):
    if valor > 0 and valor <= 100:
        return 1
    elif valor > 100 and valor <= 200:
        return 2
    elif valor > 200 and valor <= 300:
        return 3
    elif valor > 300 and valor <= 400:
        return 4
    elif valor > 400 and valor <= 500:
        return 5
    elif valor > 500:
        return 6
    else:
        return 7
In [17]:
#Agrupamos las funciones
def aConvertir(datos):
    ds = eliminarColumnas(datos)
    ds = agregarFamilyNum(ds)
    ds['Age'] = ds['Age'].apply(gruposAge)
    ds['Fare'] = ds['Fare'].apply(gruposFare)
    ds.fillna('',inplace =True)
    return ds
In [18]:
ds_train = aConvertir(titanic_train)
ds_train.head()
Out[18]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 male 5 1 0 1 S 1
1 1 female 6 1 0 1 C 1
2 3 female 5 0 0 1 S 0
3 1 female 6 1 0 1 S 1
4 3 male 6 0 0 1 S 0
In [19]:
#Convertimos test también
ds_test = aConvertir(titanic_test)
ds_test.head()
Out[19]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 male 6 0 0 1 Q 0
1 3 female 7 1 0 1 S 1
2 2 male 8 0 0 1 Q 0
3 3 male 5 0 0 1 S 0
4 3 female 5 1 1 1 S 2

Ahora tenemos solamente dos campos de texto Sex y Embarked, intentemos convertir estos en valores más entendibles para los algoritmos

In [20]:
from sklearn import preprocessing
In [21]:
def preprocessCampos(train,test):
    campos = ['Sex', 'Embarked']
    ds_combinado = pd.concat([train[campos], test[campos]])
    
    for campo in campos:
        le = preprocessing.LabelEncoder()
        le = le.fit(ds_combinado[campo].fillna(''))
        train[campo] = le.transform(train[campo])
        test[campo] = le.transform(test[campo])
    return train, test
In [22]:
ds_train, ds_test = preprocessCampos(ds_train, ds_test)
ds_train.head()
Out[22]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 1 5 1 0 1 3 1
1 1 0 6 1 0 1 1 1
2 3 0 5 0 0 1 3 0
3 1 0 6 1 0 1 3 1
4 3 1 6 0 0 1 3 0
In [23]:
ds_test.head()
Out[23]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 1 6 0 0 1 2 0
1 3 0 7 1 0 1 3 1
2 2 1 8 0 0 1 2 0
3 3 1 5 0 0 1 3 0
4 3 0 5 1 1 1 3 2

Aplicar algoritmos

En esta parte ya tenemos nuestros datos transformados de una forma más fácil de procesar, ahora vamos a aplicar varios algoritmos y validaremos su eficacia.

In [24]:
#Creamos nuestro dataset de Survived y de entrenamiento
X = ds_train
y = titanic_train['Survived']
In [25]:
#Creamos los splits de entrenamiento y test que vamos a utilizar para nuestros algoritmos
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=66)

Linear Regression

In [26]:
from sklearn.linear_model import LinearRegression
lrmodel = LinearRegression()
lrmodel.fit(X_train,y_train)
lr_predictions = lrmodel.predict(X_test)

Logistic Regression

In [27]:
from sklearn.linear_model import LogisticRegression
logmodel = LogisticRegression()
logmodel.fit(X_train,y_train)
log_predictions = logmodel.predict(X_test)

K-Means Clustering

In [28]:
from sklearn.cluster import KMeans
kmeansmodel = KMeans(n_clusters=2)
kmeansmodel.fit(X_train)
km_predictions = kmeansmodel.predict(X_test)

K-Nearest neighbor

In [29]:
from sklearn.neighbors import KNeighborsClassifier
knnmodel = KNeighborsClassifier(n_neighbors=20)
knnmodel.fit(X_train,y_train)
knn_predictions = knnmodel.predict(X_test)

Decision Tree

In [30]:
from sklearn.tree import DecisionTreeClassifier
dtreemodel = DecisionTreeClassifier()
dtreemodel.fit(X_train,y_train)
dtree_predictions = dtreemodel.predict(X_test)

Random Forest

In [31]:
from sklearn.ensemble import RandomForestClassifier
rfcmodel = RandomForestClassifier(n_estimators=200)
rfcmodel.fit(X_train,y_train)
rfc_predictions = rfcmodel.predict(X_test)

Support Vector Machines

In [32]:
from sklearn.svm import SVC
svcmodel = SVC()
svcmodel.fit(X_train,y_train)
svc_predictions = svcmodel.predict(X_test)

Gaussian Naive Bayes

In [33]:
from sklearn.naive_bayes import GaussianNB
gnbmodel = GaussianNB()
gnbmodel.fit(X_train,y_train)
gnb_predictions = gnbmodel.predict(X_test)

Validating Scores

Después de ejecutar los algoritmos podemos comparar la precisión y escoger el mejor:

In [34]:
print('Linear Regression: ',lrmodel.score(X_test,y_test))
print('Logistic Regression: ', logmodel.score(X_test,y_test))
print('K-Means Clustering: ', kmeansmodel.score(X_test,y_test))
print('K-Nearest neighbor: ', knnmodel.score(X_test,y_test))
print('Decision Tree: ', dtreemodel.score(X_test,y_test))
print('Random Forest: ', rfcmodel.score(X_test,y_test))
print('Support Vector Machines: ', svcmodel.score(X_test,y_test))
print('Gaussian Naive Bayes: ', gnbmodel.score(X_test,y_test))
Linear Regression:  0.371556568359
Logistic Regression:  0.80223880597
K-Means Clustering:  -2114.45854816
K-Nearest neighbor:  0.791044776119
Decision Tree:  0.820895522388
Random Forest:  0.84328358209
Support Vector Machines:  0.850746268657
Gaussian Naive Bayes:  0.776119402985

Predecir el verdardero Test dataset

El mejor Algoritmo fue el de Support Vector Machines, procedamos a generar el archivo de predicciones.

In [36]:
passengers = titanic_test['PassengerId']
predictions = svcmodel.predict(ds_test)

output = pd.DataFrame({ 'PassengerId' : passengers, 'Survived': predictions })
output.to_csv('titanic-predictions.csv', index = False)
output.head()
Out[36]:
PassengerId Survived
0 892 0
1 893 1
2 894 0
3 895 0
4 896 1

Cuando subimos nuestro dataset a Kaggle, este nos da un maravilloso mensaje informándonos que somos los mejores.

KaggleTitanic