Se trata de un conjunto de datos con el interés, por parte del compilador, de realizar un análisis y predicción de ataques cardíacos. Fue subido por Rashik Rahman hace 3 meses al Kaggle para que se realice un modelo para la clasificación de ataques cardíacos.
https://www.kaggle.com/rashikrahmanpritom/heart-attack-analysis-prediction-dataset
Describir los estados “probabilidad baja de ataque cardiaco” y “probabilidad alta de ataque cardiaco”, además también determinar las condiciones de cambiar de estados.
¿Existe alguna relación entre el sexo y el dolor de pecho después del ejercicio. ¿Existe alguna relación entre el azúcar en la sangre en ayunas y el dolor de pecho después del ejercicio? ¿Existe alguna relación entre las variables numéricas? ¿Existe alguna diferencia notoria entre las edades de las personas, según su probabilidad de ataque cardiaco? ¿Existe alguna angina particular según la probabilidad de ataque cardiaco?
Edad: edad del paciente.
Sexo: sexo del paciente(1: hombre, 0: mujer.)
exng: angina inducida por el ejercicio (1 = sí; 0 = no) significa que hay dolor en el pecho después del ejercicio?
ca: número de vasos principales (0-3).
cp: tipo de dolor de pecho tipo de dolor de pecho.
trtbps: presión arterial en reposo (en mm Hg).
chol: colesterol en mg / dl obtenido a través del sensor de IMC.
fbs: (azúcar en sangre en ayunas> 120 mg / dl) (1 = verdadero; 0 = falso).
rest_ecg: resultados electrocardiógrafos en reposo
oldpeak - Depresión del ST inducida por el ejercicio en relación con el reposo.
thalach: frecuencia cardíaca máxima alcanzada. thal-2 = normal; 1 = defecto fijo; 3 = defecto reversible.
output: 0 = menos probabilidad de ataque cardíaco, 1 = más probabilidad de ataque cardíaco.
library(readr)
heart <- read_csv("C:/Users/Andres1/Downloads/Trabajo B1M/data/heart.csv")
head(heart,5)
## # A tibble: 5 x 14
## age sex cp trtbps chol fbs restecg thalachh exng oldpeak slp
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 63 1 3 145 233 1 0 150 0 2.3 0
## 2 37 1 2 130 250 0 1 187 0 3.5 0
## 3 41 0 1 130 204 0 0 172 0 1.4 2
## 4 56 1 1 120 236 0 1 178 0 0.8 2
## 5 57 0 0 120 354 0 1 163 1 0.6 2
## # ... with 3 more variables: caa <dbl>, thall <dbl>, output <dbl>
sum(is.na(heart))
## [1] 0
Con lo cual no hay valores faltantes.
boxplot(scale(heart), xlab ="Variables",ylab = "Rango de Valores", col="blue", main="Diagrama de Caja Conjunto para Variables Escaladas")
Con lo cual se ha detectado valores atípicos en las siguientes variables trtbps, chol,fbs,thalachh,oldpeak,caa y thall.
x <- cbind(heart$trtbps,heart$chol,heart$fbs,heart$thalachh,heart$oldpeak,heart$caa,heart$thall);
colnames(x) <- c("trtbps", "chol","fbs","thalachh","oldpeak","caa", "thall")
boxplot(scale(x), xlab ="Variables",
ylab = "Rango de Valores", col="blue", main="Diagrama de Caja Conjunto para Variables Escaladas"
)
Para verificar que son realmente atípicos se va a realizar la prueba de Tukey, a cada variable:
library(rapportools)
x <- cbind(heart$trtbps,heart$chol,heart$fbs,heart$thalachh,heart$oldpeak,heart$caa,heart$thall);
colnames(x) <- c("trtbps", "chol","fbs","thalachh","oldpeak","caa", "thall")
nombres <- colnames(x);
matriz_nom <- rep(1,7);
for(i in 1:7)
{
m <- x[,i];
q1 <- quantile(m,0.25);
q3 <- quantile(m,0.75);
p <- q3-q1;
ati_tukey <- (m<(q1-1.5*p) | m>(q3+1.5*p));
matriz_nom[i] <- sum(ati_tukey);
}
matriz_nom <- rbind(nombres,matriz_nom)
matriz_nom
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## nombres "trtbps" "chol" "fbs" "thalachh" "oldpeak" "caa" "thall"
## matriz_nom "9" "5" "45" "1" "5" "25" "2"
Finalmente se puede comprobar que todas las variables en cuestión tienen atípicos según la prueba de Tukey, de manera que se va a reemplazar los atípicos por la media. Recuérdese que el método de Tukey usa la distancia intercuartílica (DIQ = cuartil 3 menos cuartil 1) y todo punto que se encuentre por debajo del cuartil uno -DIQ es atípico, lo mismo para todo punto que este por encima del cuartil 3+DIQ.
x <- cbind(heart$trtbps,heart$chol,heart$fbs,heart$thalachh,heart$oldpeak,heart$caa,heart$thall);
colnames(x) <- c("trtbps", "chol","fbs","thalachh","oldpeak","caa", "thall")
y <- x;
nombres <- colnames(x);
matriz_nom <- rep(1,7);
for(i in 1:7)
{
m <- x[,i];
q1 <- quantile(m,0.25);
q3 <- quantile(m,0.75);
p <- q3-q1;
ati_tukey <- (m<(q1-1.5*p) | m>(q3+1.5*p));
for(j in 1:length(ati_tukey))
{
med <- mean(x[,i]);
if(ati_tukey[j]==TRUE)
{
y[j,i] <- med;
}
}
}
boxplot(scale(y), xlab ="Variables",
ylab = "Rango de Valores", col="blue", main="Diagrama de Caja Conjunto de Variables Escaladas"
)
Con lo cual ya no tenemos datos atípicos. Finalmente la base de datos queda como:
x <- cbind(heart$trtbps,heart$chol,heart$fbs,heart$thalachh,heart$oldpeak,heart$caa,heart$thall);
colnames(x) <- c("trtbps", "chol","fbs","thalachh","oldpeak","caa", "thall")
y <- x;
heart2 <- cbind(heart[,c(-4,-5,-6,-8,-10,-12,-13)],y)
head(heart2,5)
## age sex cp restecg exng slp output trtbps chol fbs thalachh oldpeak caa thall
## 1 63 1 3 0 0 0 1 145 233 1 150 2.3 0 1
## 2 37 1 2 1 0 0 1 130 250 0 187 3.5 0 2
## 3 41 0 1 0 0 2 1 130 204 0 172 1.4 0 2
## 4 56 1 1 1 0 2 1 120 236 0 178 0.8 0 2
## 5 57 0 0 1 1 2 1 120 354 0 163 0.6 0 2
De manera que se va a empezar el análisis con la correlación entre las variables:
library(tidyverse)
library(corrplot)
heart2p <- heart2[,c(-14,-13,-6)];
corrplot(cor(heart2p))
Debido a que “cp” es una variable categórica no existe una relación lineal tangible entre las variables.
A continuación se va a dividir los datos en dos partes según la probabilidad de ataque cardiaco:
library(tidyverse)
heart2p <- heart2[,c(-14,-13,-6)];
heartProbBaja <- heart2p[heart2p[,6]==0, ];
heartProbAlta <- heart2p[heart2p[,6]==1, ];
Comparación de Histogramas para la variable Edad:
par(mfrow=c(1,3))
hist(heart2p$age,main="Histograma de la Edad",col="red",
xlab = " Edad",ylab = " Frecuencia")
hist(heartProbBaja$age,main="Hist: Edad, Baja Probabilidad",col="red",
xlab = " Edad",ylab = " Frecuencia")
hist(heartProbAlta$age,main="Hist: Edad, Alta Probabilidad",col="red",
xlab = " Edad",ylab = " Frecuencia")
Se puede notar que existe mayor cantidad de personas con alta probabilidad de ataque cardiaco en personas con edad entre 40 y 45 años. En las demás edades parece no existir una diferencia apreciable.
Sexo del paciente:
par(mfrow=c(1,3))
plot(table(heart2p$sex),main="Sexo",col="blue",
xlab="Sexo",ylab="Número de personas",type = "h")
plot(table(heartProbBaja$sex),main="Sexo: Prob. baja",col="blue",
xlab="Sexo",ylab="Número de personas",type = "h")
plot(table(heartProbAlta$sex),main="Sexo: Prob. alta",col="blue",
xlab="Sexo",ylab="Número de personas",type = "h")
Existe porcentualmente una menor cantidad de mujeres con baja probabilidad de ataque cardiaco en comparación con los hombres.
Comparación de la angina (dolor en el pecho):
par(mfrow=c(1,3))
plot(table(heart2p$cp),main="Tipo de Dolor de Pecho",col="blue",
xlab="Tipos de angina",ylab="Número de personas",type = "h")
plot(table(heartProbBaja$cp),main="Dolor de Pecho: Prob. baja",col="blue",
xlab="Tipos de angina",ylab="Número de personas",type = "h")
plot(table(heartProbAlta$cp),main="Dolor de Pecho: Prob. alta",col="blue",
xlab="Tipos de angina",ylab="Número de personas",type = "h")
Podemos observar una clara característica para cada grupo, en especial para el grupo con baja probabilidad. El tipo de angina para las personas con baja probabilidad es de tipo 1, el cual es un dolor de pecho muy común y para las de alta probabilidad es de tipo 3, el cual se clasifica como dolor no anginoso.
Comparación de “fbs” o azúcar en la sangre en ayunas:
par(mfrow=c(1,3))
plot(table(heart2p$fbs),main="Azucar en la Sangre en Ayunas",col="blue",
xlab="fbs",ylab="Número de personas",type = "h")
plot(table(heartProbBaja$fbs),main="Prob. baja",col="blue",
xlab="fbs",ylab="Número de personas",type = "h")
plot(table(heartProbAlta$fbs),main="Prob. alta",col="blue",
xlab="fbs",ylab="Número de personas",type = "h")
Esta variable parece ser irrelevante en la probabilidad de ataque cardiaco.
Comparación de “rest_ecg”, resultados electrocardiógrafos en reposo:
par(mfrow=c(1,3))
plot(table(heart2p$restecg),main="Resultados elec. en reposo",col="blue",
xlab="rest_ecg",ylab="Número de personas",type = "h")
plot(table(heartProbBaja$restecg),main="Prob. baja",col="blue",
xlab="rest_ecg",ylab="Número de personas",type = "h")
plot(table(heartProbAlta$restecg),main="Prob. alta",col="blue",
xlab="rest_ecg",ylab="Número de personas",type = "h")
Se ve que en personas con probabilidad alta de ataque cardiaco, el patrón normal deja de ser el dominante y cambia para mostrar un electrocardiograma con una anomalía en las ondas ST-T, dichas ondas reflejan la recuperación eléctrica de las células.
Ahora se va a observar, fbs (azúcar en la sangre) vs sexo:
par(mfrow=c(1,3))
plot(table(heart2p$fbs,heart2p$sex),main="Azucar en la Sangre vs Sexo",col="green",
xlab="fbs",ylab="Número de personas",type = "h")
plot(table(heartProbBaja$fbs,heartProbBaja$sex),main="Prob. baja",col="green",
xlab="fbs",ylab="Número de personas",type = "h")
plot(table(heartProbAlta$fbs,heartProbAlta$sex),main="Prob. alta",col="green",
xlab="fbs",ylab="Número de personas",type = "h")
Se puede establecer que en las personas con baja probabilidad de ataque cardiaco, los hombres poseen considerablemente mayor cantidad de azúcar en la sangre que las mujeres.
De manera que, se va a realizar una prueba Ji-Cuadrado, para ver si existe independencia entre los sexos en el nivel de azúcar en la sangre;
Para las personas con baja probabilidad de ataque cardiaco:
library(stats)
chisq.test(table(heartProbBaja$fbs,heartProbBaja$sex))
## Warning in chisq.test(table(heartProbBaja$fbs, heartProbBaja$sex)): Chi-squared
## approximation may be incorrect
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: table(heartProbBaja$fbs, heartProbBaja$sex)
## X-squared = 1.0546, df = 1, p-value = 0.3044
Al haber probabilidad de que la aproximación sea incorrecta se va a usar el test exacto de Fischer:
fisher.test(table(heartProbBaja$fbs,heartProbBaja$sex))
##
## Fisher's Exact Test for Count Data
##
## data: table(heartProbBaja$fbs, heartProbBaja$sex)
## p-value = 0.2189
## alternative hypothesis: true odds ratio is not equal to 1
## 95 percent confidence interval:
## 0.1550137 1.7477711
## sample estimates:
## odds ratio
## 0.4927461
Entonces al ser el p, muy alto, para las personas con baja probabilidad de ataque cardiaco, el sexo no infiere en la cantidad de azúcar en la sangre.
Para las personas con alta probabilidad de ataque cardiaco:
chisq.test(table(heartProbAlta$fbs,heartProbAlta$sex))
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: table(heartProbAlta$fbs, heartProbAlta$sex)
## X-squared = 2.5688, df = 1, p-value = 0.109
Debido a que el p-valor es mayor a 0.05 no se rechaza la hipótesis nula de independencia, entonces se puede afirmar que el dolor de pecho varía según el sexo.
Ahora se va a observar el tipo de angina vs sexo:
par(mfrow=c(1,3))
plot(table(heart2p$cp,heart2p$sex),main="Tipo de Dolor de Pecho vs Sexo",col="green",
xlab="angina",ylab="Número de personas",type = "h")
plot(table(heartProbBaja$cp,heartProbBaja$sex),main="Prob. baja",col="green",
xlab="angina",ylab="Número de personas",type = "h")
plot(table(heartProbAlta$cp,heartProbAlta$sex),main="Prob. alta",col="green",
xlab="angina",ylab="Número de personas",type = "h")
Con lo cual se tiene que, en la probabilidad baja, los hombres mayoritariamente poseen angina tipo 1.
Entonces se va a realizar un test ji cuadrado para ver la independencia del dolor de pecho y el sexo de la persona;
Para persona con probabilidad baja:
chisq.test(table(heartProbBaja$cp,heartProbBaja$sex))
## Warning in chisq.test(table(heartProbBaja$cp, heartProbBaja$sex)): Chi-squared
## approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: table(heartProbBaja$cp, heartProbBaja$sex)
## X-squared = 3.9429, df = 3, p-value = 0.2677
De manera que se aplica nuevamente el test exacto de Fisher:
fisher.test(table(heartProbBaja$cp,heartProbBaja$sex))
##
## Fisher's Exact Test for Count Data
##
## data: table(heartProbBaja$cp, heartProbBaja$sex)
## p-value = 0.3033
## alternative hypothesis: two.sided
Entonces al ser el p, muy alto, para las personas con baja probabilidad de ataque cardiaco, el sexo no infiere en el dolor de pecho.
Para personas con alta probabilidad:
chisq.test(table(heartProbAlta$cp,heartProbAlta$sex))
##
## Pearson's Chi-squared test
##
## data: table(heartProbAlta$cp, heartProbAlta$sex)
## X-squared = 3.6066, df = 3, p-value = 0.3072
Debido a que el p-valor es mayor a 0.05 no se rechaza la hipótesis nula de independencia, entonces se puede afirmar que el dolor de pecho varía según el sexo.
Ahora se va a observar el tipo de restecg (resultados electrocardiógrafos en reposo) vs sexo:
par(mfrow=c(1,3))
plot(table(heart2p$restecg,heart2p$sex),main="Resultados elec. en reposo",col="green",
xlab="rest_ecg",ylab="Número de personas",type = "h")
plot(table(heartProbBaja$restecg,heartProbBaja$sex),main="Prob. baja",col="green",
xlab="rest_ecg",ylab="Número de personas",type = "h")
plot(table(heartProbAlta$restecg,heartProbAlta$sex),main="Prob. alta",col="green",
xlab="rest_ecg",ylab="Número de personas",type = "h")
En la probabilidad baja, los hombres nuevamente son mayoría para resultado de electrocardiograma en reposo de tipo normal y anómala de la onda ST-T.
Entonces se procede a realizar el test Ji-Cuadrado;
Para las personas con baja probabilidad:
chisq.test(table(heartProbBaja$restecg,heartProbBaja$sex))
## Warning in chisq.test(table(heartProbBaja$restecg, heartProbBaja$sex)): Chi-
## squared approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: table(heartProbBaja$restecg, heartProbBaja$sex)
## X-squared = 5.1862, df = 2, p-value = 0.07479
Por lo cual se procede a usar el test exacto de Fisher:
fisher.test(table(heartProbBaja$restecg,heartProbBaja$sex))
##
## Fisher's Exact Test for Count Data
##
## data: table(heartProbBaja$restecg, heartProbBaja$sex)
## p-value = 0.1217
## alternative hypothesis: two.sided
Entonces al ser p-valor, alto, para las personas con baja probabilidad de ataque cardiaco, el sexo no infiere en el electrocardiograma en reposo.
Para las personas con alta probabilidad:
chisq.test(table(heartProbAlta$restecg,heartProbAlta$sex))
## Warning in chisq.test(table(heartProbAlta$restecg, heartProbAlta$sex)): Chi-
## squared approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: table(heartProbAlta$restecg, heartProbAlta$sex)
## X-squared = 1.5484, df = 2, p-value = 0.4611
Por lo cual se procede a usar el test exacto de Fisher:
fisher.test(table(heartProbAlta$restecg,heartProbAlta$sex))
##
## Fisher's Exact Test for Count Data
##
## data: table(heartProbAlta$restecg, heartProbAlta$sex)
## p-value = 0.5167
## alternative hypothesis: two.sided
Entonces al ser el p, muy alto, para las personas con alta probabilidad de ataque cardiaco, el sexo no infiere en el electrocardiograma en reposo.
Se va a ver si el tipo de dolor de pecho tiene alguna relación con el nivel de azúcar en la sangre, para las personas con probabilidad baja:
chisq.test(table(heartProbBaja$cp,heartProbBaja$fbs))
## Warning in chisq.test(table(heartProbBaja$cp, heartProbBaja$fbs)): Chi-squared
## approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: table(heartProbBaja$cp, heartProbBaja$fbs)
## X-squared = 0.1908, df = 3, p-value = 0.9791
Por lo cual se va a utilizar el test exacto de Fisher:
fisher.test(table(heartProbBaja$cp,heartProbBaja$fbs))
##
## Fisher's Exact Test for Count Data
##
## data: table(heartProbBaja$cp, heartProbBaja$fbs)
## p-value = 1
## alternative hypothesis: two.sided
El cual nos muestra que se acepta la independencia, esto es que para las personas con probabilidad baja, el tipo de dolor de pecho no depende de la cantidad de azúcar en la sangre.
Se va a ver si el tipo de dolor de pecho tiene alguna relación con el nivel de azúcar en la sangre, para las personas con probabilidad alta:
chisq.test(table(heartProbAlta$cp,heartProbAlta$fbs))
## Warning in chisq.test(table(heartProbAlta$cp, heartProbAlta$fbs)): Chi-squared
## approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: table(heartProbAlta$cp, heartProbAlta$fbs)
## X-squared = 8.756, df = 3, p-value = 0.03272
De manera que se va a usar el test exacto de Fisher:
fisher.test(table(heartProbAlta$cp,heartProbAlta$fbs))
##
## Fisher's Exact Test for Count Data
##
## data: table(heartProbAlta$cp, heartProbAlta$fbs)
## p-value = 0.0193
## alternative hypothesis: two.sided
Con lo cual se rechaza la hipótesis nula, es decir, para las personas con probabilidad alta de ataque cardiaco, el dolor de pecho no se relaciona con la cantidad de azúcar en la sangre.
Everitt, B., & Hothorn, T. (2011). An introduction to applied multivariate analysis with R. Springer Science & Business Media.
Abedin, J., & Das, K. K. (2015). Data manipulation with R. Packt Publishing Ltd.