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

Anaconda, Jupyter, Python

Anaconda: Crear un notebook con Jupyter

Jupyter Notebook es una aplicación web en la que se puede crear y compartir documentos, código, ecuaciones, visualizaciones y text, el Jupyter Notebook es una de las herramientas ideales para ayudarnos a obtener los skills de data science que necesitamos.

En este artículo veremos como crear un ambiente básico de Anaconda, instalar Jupyter Notebook en él y luego instalar cualquier paquete que necesitemos para trabajar.

Paso 1: Crear un environment de Anaconda

Este paso es opcional, Anaconda trae un ambiente por defecto (Root) en el que podemos ejecutar Jupyter Notebook, pero en este paso vamos a especificar como crear un environment con los paquetes mínimos:

Creamos el environment:

conda create -n jupytertest python=3.5

En este paso estamos creando un environment en Anaconda de nombre jupytertest y con la versión de python 3.5. Escribimos “y” y presionamos ENTER cuando lo solicité y podemos ver que paquetes serán instalados en nuestro ambiente.

CondaEnvironment

Paso 2: Activar el ambiente e instalar Jupyter

Una vez creado el ambiente procedemos a activar el ambiente e instalar Jupyter.

activate jupytertest
conda install jupyter

Cuando activamos el ambiente a la izquierda nos aparece el nombre del environment indicándonos que estamos en un virtual env. Procedemos a instalar Jupyter y todas sus dependencias.

CondaJupyterInstall

Para confirmar que paquetes tenemos instalados en nuestro environment podemos utilizar:

conda list

Paso 3: Instalación de paquetes restantes

Este enunciado depende de lo que vayamos a realizar con el Jupyter Notebook, para este ejemplo vamos a realizar una gráfica con Matplotlib creado un DataFrame de Pandas.

Para esto necesitamos lo siguiente:

conda install pandas

CondaInstallPandas

condas install matplotlib

CondaInstallMatplotlib

Paso 4: Ejecutar el Jupyter Notebook

Una vez verificado que todos los paquetes fueron instalados correctamente procedemos a ejecutar nuestro Jupyter Notebook.

jupyter notebook

Cuando ejecutamos la anterior sentencia se crear un servidor y se abre el navegador en la en la carpeta en la cual ejecutamos el comando.

Paso 5: Hola Mundo Pandas y Matplotlib

A este punto deberíamos estar viendo la pantalla princiapl del Notebook en la carpeta que especificamos:

JupyterNotebok

Creamos un nuevo Notebook, dando click en New -> Python. También podemos crear carpetas y otros tipos de archivos que tengamos configurados.

JupyterNotebokNew

Creamos un pequeño ejemplo para validar que todo importó bien:

NotebookRandomMatplotlib

Aquí está el código usado:

import numpy as np   # Paquete para generar números aleatorios
import pandas as pd  # Paquete para crear el DataFrame
import matplotlib.pyplot as plt # Paquete para crear gráficas
%matplotlib inline   # Para que aparezca en linea en el Notebook
df = pd.DataFrame(np.random.randn(100,1), columns=['A'])
df.plot()
plt.title('Hola Mundo')

 

Recomendaciones

Jupyter Notebook es una plataforma para facilitar el desarrollo de modelos y realizar pruebas, es un buen consejo seguir las siguientes recomendaciones:

  • Aprendete los hotkeys, en el command palette el último botón de la barra de herramientas aparecen todos los atajos de teclado que usa el Notebook, es buena idea aprenderse algunos para tener una experiencia más cómoda.
  • Documenta, documenta, documenta… Jupyter Notebooks proveen ademas de poder escribir código una buena forma de documentar tu proyecto, y así poder mostrar más fácilmente a otros tus resultados o pruebas.
  • Limita los códigos por linea, intenta tener un espacio entre varias lineas de código para documentar, así es más entendible.
  • Renombra tus Notebooks, haz que sean fáciles de encontrar y diferenciar.
  • Despliega los gráficos en linea como lo vimos en el ejemplo.
  • Intenta importar tus paquetes en la primera linea del Notebook.
Python

Python & Anaconda: Instalación y Configuración (Windows)

Python es un lenguaje de programación interpretado cuya filosofía hace hincapié en una sintaxis que favorezca un código legible.

Se trata de un lenguaje de programación multiparadigma, ya que soporta orientación a objetos, programación imperativa y en menor medida programación funcional. Es un lenguaje interpretado, usa tipado dinámico y es multiplataforma. Wikipedia

Los lenguajes preferidos para Machine Learning son Python y R, en mi caso prefiero usar es Python, aquí hay dos opciones para instalar Python, una es directamente desde la página de Python la otra es instalando Anaconda que trae varios packages predeterminados para Machine Learning.

Instalar Python desde Python.org

Primero descargamos la última versión de Python desde Downloads, sino estamos seguros cual versión instalar, si 2 o 3 puedes comenzar con la 3 y validar después de acuerdo a tus requerimientos, si necesitas más ayuda puedes validar acá Python 2 or Python 3.

PythonDownload

Una vez descargado instalamos la aplicación, mi recomendación es instalarlo en una carpeta de raíz,puede ser C:\ u otro disco duro.

PythonInstall1

En Optional Features podemos dejar todos seleccionados, y en Advance Options verificar que esté la opción seleccionada para añadir Python a las variables de entorno y en mi caso también quiero tener los binarios de VS2015 instalados porque utilizaré Python con VS más adelante.

PythonInstall2

Luego de instalado podemos verificar la versión escribiendo en la línea de comando:

python --version

Si tenemos instaladas varias versiones de Python y queremos ejecutar una versión específica podemos usar el comando py -x.x filename.py.

PythonVersion

Instalar Python desde Anaconda

Para instalar Python desde Anaconda vamos a la página de Downloads y escogemos la versión que queramos.

AnacondaDownload

Podemos escoger en que carpeta vamos a instalar, en mi caso la dejo por defecto y en la siguiente pantalla, dependiendo de la versión que queramos por defecto de Python, podemos habilitar o deshabilitar Anaconda como default Python.

AnacondaInstall3

Una vez lo instalemos podremos acceder al Anaconda Navigator, en la cual tendremos dos pantallas de importancia Home y Environments. En Home encontraremos las aplicaciones que tenemos instalados en el workspace actual de Anaconda que por Default es Root.

AnacondaNav

Y en Environments tendremos todos los paquetes instalados en Root.

AnacondaNavEnv

Para utilizar el ambiente root que creamos una carpeta y verificamos que tengamos acceso a Conda, como no instalamos Anaconda en la variable de Path como nos recomendaron, para ejecutar comandos tenemos que apuntar a la carpeta de scripts.

C:\Users\Michael\Anaconda3\Scripts\conda -V

CondaVersion

Actualizamos Conda

C:\Users\Michael\Anaconda3\Scripts\conda update conda

CondaUpdate

Creamos un nuevo Environment con el comando

C:\Users\Michael\Anaconda3\Scripts\conda create -n mytestenv biopython

biopython es un Package Spec que nos instala una lista de paquetes, para tener más detalle podemos entrar a esta URL Anaconda Package List.

Para usar los environments simplemente los activamos y desactivamos con los siguientes comandos:

C:\Users\Michael\Anaconda3\Scripts\activate mytestenv
deactivate mytestenv

CondaActivate

Siempre podemos añadir un Environment o la ruta de los environments al PATH de las variables del sistema para hacer mucho más amigable el uso de los comandos de Conda.