Skip to content

Master Data Science - AI - Data life cycle and typology (Práctica 2: Limpieza y validación de los datos) - Titanic dataset

License

Notifications You must be signed in to change notification settings

AbigailBG153/titanic-data-cleaning-and-validation

 
 

Repository files navigation

M2.851 - Tipología y ciclo de vida de los datos aula 1 · Práctica 1

2018 · Máster universitario en Ciencia de datos (Data science)

Prof. Colaboradora: Mireia Calvo Gonzalez

Alumno: Fernando Antonio Barbeiro Campos - [email protected]

 

Práctica 2 - Limpieza y validación de los datos

Contenidos

  1. Dataset

  2. Integración y selección de los datos de interés a analizar.

  3. Limpieza de los datos.

    3.1. ¿Los datos contienen ceros o elementos vacíos? ¿Cómo gestionarías cada uno de estos casos?

    3.2. Identificación y tratamiento de valores extremos.

  4. Análisis de los datos.

    4.1. Selección de los grupos de datos que se quieren analizar/comparar (planificación de los análisis a aplicar).

    4.2. Comprobación de la normalidad y homogeneidad de la varianza.

    4.3. Aplicación de pruebas estadísticas para comparar los grupos de datos. En función de los datos y el objetivo del estudio, aplicar pruebas de contraste de hipótesis, correlaciones, regresiones, etc.

  5. Representación de los resultados a partir de tablas y gráficas.

  6. Resolución del problema. A partir de los resultados obtenidos, ¿cuáles son las conclusiones? ¿Los resultados permiten responder al problema?

  7. Código

  8. Referencias

1. Dataset

Descripción del dataset. ¿Por qué es importante y qué pregunta/problema pretende responder?

He elegido el dataset "Titanic: Machine Learning from Disaster" de Kagle. Titanic

Figura 1: Titanic

La información presente en el dataset són datos sobre cada pasajero del famoso naufragio, si la persona sobrevivió o no, su sexo, tipo de cabina que estaba, entre otros.

Aunque hubo algún elemento de suerte involucrado en sobrevivir al hundimiento, algunos grupos de personas tenían más probabilidades de sobrevivir que otros, como las mujeres, los niños y la clase alta.

Justamente, el problema que buscamos a contestar es precisamente esto: hacer el análisis de ¿qué tipos de personas podrían sobrevivir?

Aún hablando un poco sobre el dataset, vamos a mirar un poco más de información sobre el mismo:

# Objetivo: Asegurar que estamos trabajando con el formato en ingles separado por comas
L <- readLines("train.csv", n = 1)
if (grepl(",", L)) print("File has an English format")
[1] "File has an English format"
# Como estamos trabajando con ficheros separados por commas, vamos a mirar un poco de datos
df <- read.csv("train.csv")
head(df)

# Mirando los nombres de columnas del dataframe y los tipos de variables y informacion adicional
print(paste("We are evaluating", nrow(df), "rows of code"))
print("Column's names: ")
colnames(df)
sapply(df,class)
str(df)
summary(df)
PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
1 0 3 Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.2500 S
2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Thayer)female 38 1 0 PC 17599 71.2833 C85 C
3 1 3 Heikkinen, Miss. Laina female 26 0 0 STON/O2. 3101282 7.9250 S
4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1000 C123 S
5 0 3 Allen, Mr. William Henry male 35 0 0 373450 8.0500 S
6 0 3 Moran, Mr. James male NA 0 0 330877 8.4583 Q
[1] "We are evaluating 891 rows of code"
[1] "Column's names: "
  1. 'PassengerId'
  2. 'Survived'
  3. 'Pclass'
  4. 'Name'
  5. 'Sex'
  6. 'Age'
  7. 'SibSp'
  8. 'Parch'
  9. 'Ticket'
  10. 'Fare'
  11. 'Cabin'
  12. 'Embarked'
PassengerId
'integer'
Survived
'integer'
Pclass
'integer'
Name
'factor'
Sex
'factor'
Age
'numeric'
SibSp
'integer'
Parch
'integer'
Ticket
'factor'
Fare
'numeric'
Cabin
'factor'
Embarked
'factor'
'data.frame':	891 obs. of  12 variables:
 $ PassengerId: int  1 2 3 4 5 6 7 8 9 10 ...
 $ Survived   : int  0 1 1 1 0 0 0 0 1 1 ...
 $ Pclass     : int  3 1 3 1 3 3 1 3 3 2 ...
 $ Name       : Factor w/ 891 levels "Abbing, Mr. Anthony",..: 109 191 358 277 16 559 520 629 417 581 ...
 $ Sex        : Factor w/ 2 levels "female","male": 2 1 1 1 2 2 2 2 1 1 ...
 $ Age        : num  22 38 26 35 35 NA 54 2 27 14 ...
 $ SibSp      : int  1 1 0 1 0 0 0 3 0 1 ...
 $ Parch      : int  0 0 0 0 0 0 0 1 2 0 ...
 $ Ticket     : Factor w/ 681 levels "110152","110413",..: 524 597 670 50 473 276 86 396 345 133 ...
 $ Fare       : num  7.25 71.28 7.92 53.1 8.05 ...
 $ Cabin      : Factor w/ 148 levels "","A10","A14",..: 1 83 1 57 1 1 131 1 1 1 ...
 $ Embarked   : Factor w/ 4 levels "","C","Q","S": 4 2 4 4 4 3 4 4 4 2 ...



  PassengerId       Survived          Pclass     
 Min.   :  1.0   Min.   :0.0000   Min.   :1.000  
 1st Qu.:223.5   1st Qu.:0.0000   1st Qu.:2.000  
 Median :446.0   Median :0.0000   Median :3.000  
 Mean   :446.0   Mean   :0.3838   Mean   :2.309  
 3rd Qu.:668.5   3rd Qu.:1.0000   3rd Qu.:3.000  
 Max.   :891.0   Max.   :1.0000   Max.   :3.000  
                                                 
                                    Name         Sex           Age       
 Abbing, Mr. Anthony                  :  1   female:314   Min.   : 0.42  
 Abbott, Mr. Rossmore Edward          :  1   male  :577   1st Qu.:20.12  
 Abbott, Mrs. Stanton (Rosa Hunt)     :  1                Median :28.00  
 Abelson, Mr. Samuel                  :  1                Mean   :29.70  
 Abelson, Mrs. Samuel (Hannah Wizosky):  1                3rd Qu.:38.00  
 Adahl, Mr. Mauritz Nils Martin       :  1                Max.   :80.00  
 (Other)                              :885                NA's   :177    
     SibSp           Parch             Ticket         Fare       
 Min.   :0.000   Min.   :0.0000   1601    :  7   Min.   :  0.00  
 1st Qu.:0.000   1st Qu.:0.0000   347082  :  7   1st Qu.:  7.91  
 Median :0.000   Median :0.0000   CA. 2343:  7   Median : 14.45  
 Mean   :0.523   Mean   :0.3816   3101295 :  6   Mean   : 32.20  
 3rd Qu.:1.000   3rd Qu.:0.0000   347088  :  6   3rd Qu.: 31.00  
 Max.   :8.000   Max.   :6.0000   CA 2144 :  6   Max.   :512.33  
                                  (Other) :852                   
         Cabin     Embarked
            :687    :  2   
 B96 B98    :  4   C:168   
 C23 C25 C27:  4   Q: 77   
 G6         :  4   S:644   
 C22 C26    :  3           
 D          :  3           
 (Other)    :186           

2. Integración y selección de los datos de interés a analizar

Dando un poco más de contexto en la selección de variables: debemos escoger un grupo de variables originales (también llamadas características o atributos desde el mundo del machine learning) que contenga la mayor parte de la información relevante para resolver el problema a tratar. Existen muchas metodologías y es un campo de investigación muy importante [1] (Stanczyk y Jain, 2014).

Dado el contexto, queda claro que podemos aquí reducir un poco la dimensionalidad en el ámbito de atributos (columnas) porque hay variables en las cuales detectamos que no aportan mucho para el tipo de conocimiento que necesitamos recolectar. Por ejemplo:

  • el número del Ticket de cada persona es bastante irrelevante para extraer un modelo y predecir si la persona ha sobrevivido o no
  • Embarked - el puerto donde ha embarcado una persona en el navio tampoco
  • Cabin - hay inumeros registros en la columna que no estan rellenados

Ahora que tenemos un poco más de información sobre el dataset, con el intuito de obtener un modelo significativo, he elegido los siguientes atributos para el análisis:

  • Survived
  • Pclass
  • Name
  • Sex
  • Age
  • Fare

Queda claro que el atributo Name tampoco es relevante, pero mantuve por si acaso necesito explicar o hacer alguna comparación de pasajeros (será más sencillo identificar las personas por sus nombres).

Definidos los atributos, antes de seguir para el próximo ejercicio, hago la selección de los datos que vamos a trabajar abajo.

keeps <- c("Survived", "Pclass", "Name", "Sex", "Age", "Fare")
df <- df[keeps] 
head(df)
SurvivedPclassNameSexAgeFare
0 3 Braund, Mr. Owen Harris male 22 7.2500
1 1 Cumings, Mrs. John Bradley (Florence Briggs Thayer)female 38 71.2833
1 3 Heikkinen, Miss. Laina female 26 7.9250
1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 53.1000
0 3 Allen, Mr. William Henry male 35 8.0500
0 3 Moran, Mr. James male NA 8.4583

3. Limpieza de los datos

3.1. ¿Los datos contienen ceros o elementos vacíos? ¿Cómo gestionarías cada uno de estos casos?

# Como resultado del comando abajo, podemos ver que solamente Age tiene elementos NA
print("Columnas con NAs:")
unlist(lapply(df, function(x) any(is.na(x))))

print("Cantidad de columnas con NAs:")
sapply(df, function(x) sum(is.na(x)))

# Abajo comentaré las aproximaciones posibles para el escenario y la adoptada              
df_no_NA <- df[rowSums(is.na(df)) == 0,]
nrow(df_no_NA)
options(warn=-1)             
for(i in 1:ncol(df)){
  # Aquí estamos calculando un promedio basado en la información de las otras filas para los casos donde hay elemento vacío
  df[is.na(df[,i]), i] <- mean(df[,i], na.rm = TRUE)
}
options(warn=0)  
       
print("Aplicando un promedio para los atributos vacios, ahora no hay más NAs:")
unlist(lapply(df, function(x) any(is.na(x))))
nrow(df)
[1] "Columnas con NAs:"
Survived
FALSE
Pclass
FALSE
Name
FALSE
Sex
FALSE
Age
TRUE
Fare
FALSE
[1] "Cantidad de columnas con NAs:"
Survived
0
Pclass
0
Name
0
Sex
0
Age
177
Fare
0

714

[1] "Aplicando un promedio para los atributos vacios, ahora no hay más NAs:"
Survived
FALSE
Pclass
FALSE
Name
FALSE
Sex
FALSE
Age
FALSE
Fare
FALSE

891

Como podemos notar, solamente la columna Age presentaba datos vacíos. Además, la cantidad de registros que estamos trabajando tampoco es masiva, es decir, tenemos un muestreo pequeño de datos (891 registros).

Esto básicamente motiva con que no adoptaramos una aproximación posible en los casos de datos vacíos (NA):

  • Eliminación de registros (filas) donde haya a ocurrencia de NAs

Como podemos ver en el dataset df_no_NA, quedamos simplemente con 714 filas para trabajar (particularmente he considerado poco), por lo tanto, he adoptado una aproximación distinta:

  • Calcular un promedio basado en la información de las otras filas para los casos donde hubiera un elemento vacío

Finalmente había un registro NA en la última línea del comando head(df) (Moran, Mr. James) veamos como ha quedado los datos de Age ahora:

head(df)
SurvivedPclassNameSexAgeFare
0 3 Braund, Mr. Owen Harris male 22.00000 7.2500
1 1 Cumings, Mrs. John Bradley (Florence Briggs Thayer)female 38.00000 71.2833
1 3 Heikkinen, Miss. Laina female 26.00000 7.9250
1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.00000 53.1000
0 3 Allen, Mr. William Henry male 35.00000 8.0500
0 3 Moran, Mr. James male 29.69912 8.4583

Por lo tanto, los valores vacios en Edad están ahora calculados con base en la media.

Para cerrar el tema de los Missing Values, hay otras aproximaciones que no parecían adecuadas para el escenario, sin embargo añado para dejar claro que las he tenido en cuenta:

  • Rellenar manualmente los valores que faltan
  • Rellenar con una constante global
  • Rellenar con un valor más probable (podría ser echo con una regresión, por ejemplo)

Finalmente, he explicado porque no he utilizado la estrategia de eliminar los campos (por el muestreo es demasiado pequeño). Voy a explicar brevemente porque no he adoptado ninguna de las tres estrategias mencionadas arriba:

  1. Rellenar los valores manualmente es un trabajo repetitivo y tedioso (hay más de 100 registros sin valores).
  2. Utilizar una constante global con un valor cualquiera es lo basicamente la misma aproximación que hice, con la diferencia de que usando la media estamos aplicando una medida un poco más factible que simplemente adivinar un valor constante.
  3. La opción de un valor más probable es interesante, pero exige la utilización de un algoritmo como KNN o algo del genero, siendo así una aproximación de más liosa teniendo en cuenta que los objetivos del ejercicio son más sencillos - si fuera una situación que queremos obtener muchisima precisión en el análisis, seguramente podría ser adoptada.

Con esto, queda claro que la adopción de media como valores vacios atende el trade-off de sencillez en su implementación y añade algunas características interesantes como la utilización de alguna medida calculada del propio dataset.

3.2. Identificación y tratamiento de valores extremos

La verdad es que, mismo antes de seguir con el análisis si hay o no valores extremos (outliers) queda evidente que hay pocas posibilidades de haber muchos problemas, dado que tenemos simplemente 2 columnas con valores propiamente numéricos. Eso porque aunque Survived y Pclass son numeric, toman valores finitos, por lo que no pueden considerarse variables contínuas y deben factorizarse - abajo lo hacemos antes de empezar la identificación de extremos.

Los outliers afectan especialmente a la media (medida poco robusta). Y cuando la muestra es pequeña como en nuestro, el efecto se nota aún más acentuado.

sapply(df,class)
Survived
'numeric'
Pclass
'numeric'
Name
'factor'
Sex
'factor'
Age
'numeric'
Fare
'numeric'
df$Survived <- as.factor(ifelse(df$Survived == 1, "Yes", "No"))
df$Pclass <- as.factor(df$Pclass)
checkingOutliers <- function(df) {
    par(mfrow=c(1,2))
    for(i in 1:ncol(df)) {
        if (is.numeric(df[,i])){
            boxplot(df[,i], main = colnames(df)[i], width = 100, col="gray")
        }
    }

    max(df$Age, na.rm = TRUE)
    min(df$Age, na.rm = TRUE)
    fivenum(df$Age)

    max(df$Fare, na.rm = TRUE)
    min(df$Fare, na.rm = TRUE)
    fivenum(df$Fare)
}
checkingOutliers(df)
  1. 0
  2. 7.9104
  3. 14.4542
  4. 31
  5. 512.3292

png

#Aqui podemos ver los valores que son outliers
boxplot.stats(df$Fare)$out
boxplot.stats(df$Age)$out
  1. 71.2833
  2. 263
  3. 146.5208
  4. 82.1708
  5. 76.7292
  6. 80
  7. 83.475
  8. 73.5
  9. 263
  10. 77.2875
  11. 247.5208
  12. 73.5
  13. 77.2875
  14. 79.2
  15. 66.6
  16. 69.55
  17. 69.55
  18. 146.5208
  19. 69.55
  20. 113.275
  21. 76.2917
  22. 90
  23. 83.475
  24. 90
  25. 79.2
  26. 86.5
  27. 512.3292
  28. 79.65
  29. 153.4625
  30. 135.6333
  31. 77.9583
  32. 78.85
  33. 91.0792
  34. 151.55
  35. 247.5208
  36. 151.55
  37. 110.8833
  38. 108.9
  39. 83.1583
  40. 262.375
  41. 164.8667
  42. 134.5
  43. 69.55
  44. 135.6333
  45. 153.4625
  46. 133.65
  47. 66.6
  48. 134.5
  49. 263
  50. 75.25
  51. 69.3
  52. 135.6333
  53. 82.1708
  54. 211.5
  55. 227.525
  56. 73.5
  57. 120
  58. 113.275
  59. 90
  60. 120
  61. 263
  62. 81.8583
  63. 89.1042
  64. 91.0792
  65. 90
  66. 78.2667
  67. 151.55
  68. 86.5
  69. 108.9
  70. 93.5
  71. 221.7792
  72. 106.425
  73. 71
  74. 106.425
  75. 110.8833
  76. 227.525
  77. 79.65
  78. 110.8833
  79. 79.65
  80. 79.2
  81. 78.2667
  82. 153.4625
  83. 77.9583
  84. 69.3
  85. 76.7292
  86. 73.5
  87. 113.275
  88. 133.65
  89. 73.5
  90. 512.3292
  91. 76.7292
  92. 211.3375
  93. 110.8833
  94. 227.525
  95. 151.55
  96. 227.525
  97. 211.3375
  98. 512.3292
  99. 78.85
  100. 262.375
  101. 71
  102. 86.5
  103. 120
  104. 77.9583
  105. 211.3375
  106. 79.2
  107. 69.55
  108. 120
  109. 93.5
  110. 80
  111. 83.1583
  112. 69.55
  113. 89.1042
  114. 164.8667
  115. 69.55
  116. 83.1583
  1. 2
  2. 58
  3. 55
  4. 2
  5. 66
  6. 65
  7. 0.83
  8. 59
  9. 71
  10. 70.5
  11. 2
  12. 55.5
  13. 1
  14. 61
  15. 1
  16. 56
  17. 1
  18. 58
  19. 2
  20. 59
  21. 62
  22. 58
  23. 63
  24. 65
  25. 2
  26. 0.92
  27. 61
  28. 2
  29. 60
  30. 1
  31. 1
  32. 64
  33. 65
  34. 56
  35. 0.75
  36. 2
  37. 63
  38. 58
  39. 55
  40. 71
  41. 2
  42. 64
  43. 62
  44. 62
  45. 60
  46. 61
  47. 57
  48. 80
  49. 2
  50. 0.75
  51. 56
  52. 58
  53. 70
  54. 60
  55. 60
  56. 70
  57. 0.67
  58. 57
  59. 1
  60. 0.42
  61. 2
  62. 1
  63. 62
  64. 0.83
  65. 74
  66. 56

Considerando que dependendo de cuando se compró el billete para el Titanic los precios pueden tener cambiado bastante, voy a utilizar una tecnica de Binning para clasificar el atributo Fare en categorías y con ello no tendremos más grande parte de los outliers. Sin embargo, voy a mantener el atributo con el nombre que tiene añadiendo otra columna para la información tratada. Sigue abajo:

df$FareBin <- as.factor(ifelse(df$Fare < 10, "3rd", ifelse(df$Fare < 30, "2nd", "1st")))
sapply(df,class)
tail(df)
Survived
'factor'
Pclass
'factor'
Name
'factor'
Sex
'factor'
Age
'numeric'
Fare
'numeric'
FareBin
'factor'
SurvivedPclassNameSexAgeFareFareBin
886No 3 Rice, Mrs. William (Margaret Norton) female 39.00000 29.125 2nd
887No 2 Montvila, Rev. Juozas male 27.00000 13.000 2nd
888Yes 1 Graham, Miss. Margaret Edith female 19.00000 30.000 1st
889No 3 Johnston, Miss. Catherine Helen "Carrie"female 29.69912 23.450 2nd
890Yes 1 Behr, Mr. Karl Howell male 26.00000 30.000 1st
891No 3 Dooley, Mr. Patrick male 32.00000 7.750 3rd

Con esto, hay simplemente los valores que aparecen en los boxplots como outliers en Age, y es completamente factible que una persona en el Titanic tuviera 80 años (y también 0.4 años, en el caso de un bebé).

Finalmente, la forma que he utilizado para tratar los atributos de Age ha sido la de Deleting observations definida por [2] (Sunil, 2016).

withoutOutlier <- df[df$Age<55 & df$Age>2, ]
nrow(withoutOutlier)
tail(withoutOutlier)

df <- withoutOutlier

825

SurvivedPclassNameSexAgeFareFareBin
886No 3 Rice, Mrs. William (Margaret Norton) female 39.00000 29.125 2nd
887No 2 Montvila, Rev. Juozas male 27.00000 13.000 2nd
888Yes 1 Graham, Miss. Margaret Edith female 19.00000 30.000 1st
889No 3 Johnston, Miss. Catherine Helen "Carrie"female 29.69912 23.450 2nd
890Yes 1 Behr, Mr. Karl Howell male 26.00000 30.000 1st
891No 3 Dooley, Mr. Patrick male 32.00000 7.750 3rd

Explicando el enfoque:

Como en algunas ocasiones, la información tiene un poco de ruido, nos interesa reducir al máximo lo mismo y, para ello, una posible solución es discretizar. Así lo hicimos para el atributo Fare. Por su vez, para el outlier en Age, teníamos pocos registros con outliers, entonces he adoptado la aproximación de eliminar las líneas con outliers.

Otras aproximaciones y tecnicas también podrían estar empleadas aquí, como Regression u Outlier Analysis, sin embargo, la que haría más sentido para lo que buscamos es sin duda el Binning.

4. Análisis de los datos

4.1. Selección de los grupos de datos que se quieren analizar/comparar (planificación de los análisis a aplicar)

# Agrupación por sexo
df.male <- df[df$Sex == "male",] 
df.female <- df[df$Sex == "female",] 

# Por Edad
df.batch1 <- df[df$FareBin == "1st",] 
df.batch2 <- df[df$FareBin == "2nd",] 
df.batch3 <- df[df$FareBin == "3rd",] 

# Por Cabina
df.first_class <- df[df$Pclass == 1,] 
df.second_class <- df[df$Pclass == 2,] 
df.third_class <- df[df$Pclass == 3,]

print(paste("Hombres: ", nrow(df.male)))
print(paste("Mujeres: ", nrow(df.female)))
print("------------------------------------------------")
print(paste("Primer batch: ", nrow(df.batch1)))
print(paste("Segundo batch: ", nrow(df.batch2)))
print(paste("Tercero batch: ", nrow(df.batch3)))
print("------------------------------------------------")
print(paste("Primera clase: ", nrow(df.first_class)))
print(paste("Segunda clase: ", nrow(df.second_class)))
print(paste("Tercera clase: ", nrow(df.third_class)))
[1] "Hombres:  531"
[1] "Mujeres:  294"
[1] "------------------------------------------------"
[1] "Primer batch:  212"
[1] "Segundo batch:  285"
[1] "Tercero batch:  328"
[1] "------------------------------------------------"
[1] "Primera clase:  187"
[1] "Segunda clase:  169"
[1] "Tercera clase:  469"

4.2. Comprobación de la normalidad y homogeneidad de la varianza

Honestamente, con el dataset y las informaciones que hemos elegido para trabajar (grande parte de ellas son categóricas), creo que las comprobaciones de varianza que se busca en el item 4.2 no se aplican para el escenario. Sin embargo, haré aún así algunas comprobaciones con el único atributo numérico y continuo que queda.

# H0: la muestra (de tamaño n) sigue una distribución normal
# Se rechaza H0 si p value < alfa - ejemplo: alfa = 0.05
# Si se aplica Shapiro (en toda la muestra)

ST_A <- shapiro.test(df$Age)
ST_A

pvalue_A <- ST_A[[2]]
pvalue_A
	Shapiro-Wilk normality test

data:  df$Age
W = 0.97057, p-value = 7.574e-12

7.57412000537885e-12

En el test de Shapiro-Wilk, cuando P r(D) ≥ α entonces se acepta la hipótesis nula, existe normalidad. El valor p del test de Shapiro ha dado para Age 7.57. Por tanto, no se rechaza la hipótesis nula de normalidad. Asumimos que la muestra sigue una distribución normal.

4.3. Aplicación de pruebas estadísticas para comparar los grupos de datos. En función de los datos y el objetivo del estudio, aplicar pruebas de contraste de hipótesis, correlaciones, regresiones, etc.

head(df)
SurvivedPclassNameSexAgeFareFareBin
No 3 Braund, Mr. Owen Harris male 22.00000 7.2500 3rd
Yes 1 Cumings, Mrs. John Bradley (Florence Briggs Thayer)female 38.00000 71.2833 1st
Yes 3 Heikkinen, Miss. Laina female 26.00000 7.9250 3rd
Yes 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.00000 53.1000 1st
No 3 Allen, Mr. William Henry male 35.00000 8.0500 3rd
No 3 Moran, Mr. James male 29.69912 8.4583 3rd
# Obtain train set (80%) and test set (20%)
lines  <- nrow(df)

ntrain <- round(lines * 0.8)      # number of training examples
tindex <- sample(lines, ntrain)   # indices of training samples (random)
xtrain <- df[tindex,2:6]          # data are in columns 2:6 - "Pclass", "Sex", "Age", "FareBin" (nombre va a ser eliminado abajo)
xtest  <- df[-tindex,2:6]         # data are in columns 2:6 - "Pclass", "Sex", "Age", "FareBin" (nombre va a ser eliminado abajo)
ytrain <- df[tindex,1]            # labels are in column 4 - "SURVIVED"
ytest  <- df[-tindex,1]           # labels are in column 4 - "SURVIVED"

xtrain$Name <- NULL
xtest$Name <- NULL
xtrain$Fare <- NULL
xtest$Fare <- NULL

summary(xtrain)
summary(xtest)

model_titanic <- C50::C5.0(xtrain, ytrain)
summary(model_titanic)
 Pclass      Sex           Age       
 1:147   female:232   Min.   : 3.00  
 2:140   male  :428   1st Qu.:22.00  
 3:373                Median :29.70  
                      Mean   :28.78  
                      3rd Qu.:33.25  
                      Max.   :54.00  



 Pclass     Sex           Age       
 1:40   female: 62   Min.   : 3.00  
 2:29   male  :103   1st Qu.:23.00  
 3:96                Median :29.70  
                     Mean   :29.28  
                     3rd Qu.:34.50  
                     Max.   :54.00  




Call:
C5.0.default(x = xtrain, y = ytrain)


C5.0 [Release 2.07 GPL Edition]  	Wed Jan  2 15:38:50 2019
-------------------------------

Class specified by attribute `outcome'

Read 660 cases (4 attributes) from undefined.data

Decision tree:

Sex = male: No (428/82)
Sex = female:
:...Pclass in {1,2}: Yes (126/7)
    Pclass = 3:
    :...Age > 38: No (7)
        Age <= 38:
        :...Age <= 6: Yes (5)
            Age > 6:
            :...Age <= 14.5: No (7)
                Age > 14.5: Yes (87/39)


Evaluation on training data (660 cases):

	    Decision Tree   
	  ----------------  
	  Size      Errors  

	     6  128(19.4%)   <<


	   (a)   (b)    <-classified as
	  ----  ----
	   360    46    (a): class No
	    82   172    (b): class Yes


	Attribute usage:

	100.00%	Sex
	 35.15%	Pclass
	 16.06%	Age


Time: 0.0 secs

5. Representación de los resultados a partir de tablas y gráficas

# MOSTRAR EL ARBOL OBTENIDO
plot(model_titanic)

estimated_ytest <- predict(model_titanic, xtest, type="class")
accuracy <- sum(ytest==estimated_ytest)/length(ytest)
error <- 1- accuracy
print(paste("La accuracy del modelo es: ", accuracy))
print(paste("El error del modelo es: ", error))

# Mirando las reglas del modelo
mod <- C50::C5.0(ytrain ~ ., data = xtrain, rules = TRUE)
summary(mod)
cat(mod$rules)
[1] "La accuracy del modelo es:  0.842424242424242"
[1] "El error del modelo es:  0.157575757575758"




Call:
C5.0.formula(formula = ytrain ~ ., data = xtrain, rules = TRUE)


C5.0 [Release 2.07 GPL Edition]  	Wed Jan  2 15:38:50 2019
-------------------------------

Class specified by attribute `outcome'

Read 660 cases (4 attributes) from undefined.data

Rules:

Rule 1: (7, lift 1.4)
	Pclass = 3
	Sex = female
	Age > 6
	Age <= 14.5
	->  class No  [0.889]

Rule 2: (7, lift 1.4)
	Pclass = 3
	Sex = female
	Age > 38
	->  class No  [0.889]

Rule 3: (428/82, lift 1.3)
	Sex = male
	->  class No  [0.807]

Rule 4: (232/60, lift 1.9)
	Sex = female
	->  class Yes  [0.739]

Default class: No


Evaluation on training data (660 cases):

	        Rules     
	  ----------------
	    No      Errors

	     4  128(19.4%)   <<


	   (a)   (b)    <-classified as
	  ----  ----
	   360    46    (a): class No
	    82   172    (b): class Yes


	Attribute usage:

	100.00%	Sex
	  2.12%	Pclass
	  2.12%	Age


Time: 0.0 secs



id="See5/C5.0 2.07 GPL Edition 2019-01-02"
entries="1"
rules="4" default="No"
conds="4" cover="7" ok="7" lift="1.44499" class="No"
type="1" att="Pclass" val="3"
type="1" att="Sex" val="female"
type="2" att="Age" cut="6" result=">"
type="2" att="Age" cut="14.5" result="<"
conds="3" cover="7" ok="7" lift="1.44499" class="No"
type="1" att="Pclass" val="3"
type="1" att="Sex" val="female"
type="2" att="Age" cut="38" result=">"
conds="1" cover="428" ok="346" lift="1.31183" class="No"
type="1" att="Sex" val="male"
conds="1" cover="232" ok="172" lift="1.92106" class="Yes"
type="1" att="Sex" val="female"

png

6. Resolución del problema. A partir de los resultados obtenidos, ¿cuáles son las conclusiones? ¿Los resultados permiten responder al problema?

Analizando nuestro gráfico de árbol, queda claro que independientemente de la clase del pasajero, si su sexo fuera "Hombre", su capacidad de sobrevivir era más pequeña que de una mujer (probabilidad de los hombres como un todo alrededor de 20%).

Es importante resaltar que al elegir las variables, la variable PClass tiene más peso sobre las otras (Age y FareBin). Los pasajeros de la primera y segunda clase tiene un porcentaje más alto de sobrevivir que la tercera. Dicho, si la pasajera de la 3a clase tiene más que 38 años, posiblemente no sobrevivirá.

7. Código

Como he optado por hacer directamente en un Jupyter notebook, todos las partes del código estan presentes en este documento, sin embargo, en el repositorio de Github también es posible encontrar todos los archivos utilizados durante la práctica.

8. Referencias

[1] Stanczyk, U.; Jain, L. C. (2014). Feature Selection for Data and Pattern Recognition. Springer.

[2] Sunil, R. (2016). A Comprehensive Guide to Data Exploration. Artículo en línea. https://www.analyticsvidhya.com/blog/2016/01/guide-data-exploration/ Accedido en 02 de Enero de 2019.

About

Master Data Science - AI - Data life cycle and typology (Práctica 2: Limpieza y validación de los datos) - Titanic dataset

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Jupyter Notebook 100.0%