MG
  • Home
  • About me

On this page

  • 1a. Entendimiento del negocio
    • Contexto
    • Hipótesis a probar
  • 1b. Entendimiento de los datos
  • 2a. Preparación de los datos
    • 2a.1 Typecasting
    • 2a.2 Manejo de duplicados
    • 2a.3 Análisis de valores atípicos
    • 2a.4 Variables con varianza cercana a cero
    • 2a.5 Valores ausentes o faltantes
  • 4. Pruebas de hipótesis
    • 4.1 ¿Los fumadores generan más gasto a la aseguradora que los no fumadores?
    • 4.2 ¿Las mujeres tienen un BMI diferente a los hombres?
    • 4.3 ¿La proporción de fumadores es diferente según la región?
    • 4.4 ¿El promedio de BMI en las mujeres es diferente según el número de hijos que tengan?
    • 4.5 ¿Es diferente la proporción de fumadores en ambos sexos?
  • 5. Recapitulación y reflexiones

Test de Hipótesis: explorando correlaciones en datos de seguros de salud

Hypothesis Testing
2-Sample T-Test
Welch’s T-Test
Chi-Square Tests of Independence
One-Way ANOVA
Two-Sample Proportion Test
Se utiliza como base el libro de Jim Fros: ‘Hypothesis Testing: An Intuitive Guide for Making Data Driven Decisions’. Este análisis se enfoca en descubrir y entender las correlaciones subyacentes en los datos de seguros de salud, aplicando métodos de prueba de hipótesis para revelar tendencias y patrones significativos.
Author

Micael García

Published

November 14, 2023

1a. Entendimiento del negocio

From Kaggle: Health Insurance dataset

Contexto

Dataset de una asegurada de salud. En las aseguradoras, la capacidad de predecir los costes de cada cliente es crucial. En función de estas predicciones ajustaran el precio de la póliza y el beneficio que obtendrán.

Hipótesis a probar

Vamos a responder a las siguientes preguntas con validez estadística:

  • ¿Los fumadores generan más gasto a la aseguradora que los no fumadores?
  • ¿Las mujeres tienen un BMI diferente a los hombres?
  • ¿La proporción de fumadores es diferente según la región?
  • ¿El promedio de BMI en las mujeres es diferente según el número de hijos que tengan?
  • ¿Es diferente la proporción de fumadores en ambos sexos?
Matemáticas y código: en Inglés

Aunque el texto principal está en español, los términos matemáticos y el código están en inglés.

Esta práctica sigue el estándar internacional y ayuda a familiarizarse con el lenguaje técnico más utilizado en el campo de la ciencia de datos.

1b. Entendimiento de los datos

Para empezar, importamos las librerías que vamos a utilizar:

  • Pandas: Pandas es una biblioteca esencial en la ciencia de datos que proporciona estructuras de datos flexibles y eficientes, como DataFrames, para el análisis y manipulación de datos tabulares. Es ampliamente utilizada para limpiar, transformar y analizar datos, lo que la convierte en una herramienta fundamental para la preparación de datos en proyectos de ciencia de datos.

  • Scipy: Scipy es una biblioteca que se construye sobre NumPy y ofrece una amplia variedad de módulos y funciones especializadas para aplicaciones científicas y matemáticas. Incluye herramientas para estadísticas, optimización, álgebra lineal y procesamiento de señales, lo que la hace esencial en la investigación y el análisis de datos en ciencia de datos.

  • Numpy: NumPy es esencial en ciencia de datos para operaciones numéricas eficientes. Su estructura de matriz multidimensional permite cálculos y análisis de datos, siendo clave en manipulación y modelado.

  • Statsmodels: Statsmodels se centra en proporcionar herramientas y modelos estadísticos para el análisis de datos. La usaremos únicamente para realizar un Two-Sample Proportion Test.

  • Plotly Express: Plotly Express es una biblioteca de visualización de datos que simplifica la creación de gráficos interactivos y visuales. Es especialmente útil en la exploración de datos y la comunicación de resultados en ciencia de datos, permitiendo a los científicos de datos crear visualizaciones informativas y atractivas con facilidad.

Code
# Import libraries
import pandas as pd
from scipy import stats
import numpy as np

import statsmodels.api as sm

# Import plotly and customize
import plotly.io as pio
import plotly.express as px

pio.templates.default = "plotly"
pio.templates["plotly"].layout.colorway = px.colors.qualitative.Set2

Cargamos el dataset y describimos brevemente sus características.

df = pd.read_csv("health_insurance.csv")
df.head()
age sex bmi children smoker region charges
0 19 female 27.900 0 yes southwest 16884.92400
1 18 male 33.770 1 no southeast 1725.55230
2 28 male 33.000 3 no southeast 4449.46200
3 33 male 22.705 0 no northwest 21984.47061
4 32 male 28.880 0 no northwest 3866.85520
Campo Tipo de Dato Descripción Ejemplo
age Numérico (entero) Edad del asegurado 29
sex Categórico Sexo del asegurado Female/Male
bmi Numérico Índice de Masa Corporal del asegurado 26.6
children Numérico (entero) Número de hijos del asegurado 2
smoker Categórico Estatus de fumador del asegurado No/Yes
region Categórico Región del asegurado Southwest
charges Numérico (USD) Cargos realizados a la compañía 12345.67

2a. Preparación de los datos

2a.1 Typecasting

Comprobamos el tipo de datos de las columnas y los modificamos conforme nuestra descripción inicial.

df.dtypes
age           int64
sex          object
bmi         float64
children      int64
smoker       object
region       object
charges     float64
dtype: object
categorical_columns = ["sex", "smoker", "region"]
df[categorical_columns] = df[categorical_columns].astype("category")
df.dtypes
age            int64
sex         category
bmi          float64
children       int64
smoker      category
region      category
charges      float64
dtype: object

2a.2 Manejo de duplicados

¿Cuantas filas son exactamente iguales?

df.duplicated().sum()
1
df[df.duplicated(keep=False)]
age sex bmi children smoker region charges
195 19 male 30.59 0 no northwest 1639.5631
581 19 male 30.59 0 no northwest 1639.5631
df[df["bmi"] == 30.59]
age sex bmi children smoker region charges
195 19 male 30.59 0 no northwest 1639.56310
423 25 male 30.59 0 no northeast 2727.39510
526 19 female 30.59 2 no northwest 24059.68019
567 41 male 30.59 2 no northwest 7256.72310
581 19 male 30.59 0 no northwest 1639.56310
983 27 female 30.59 1 no northeast 16796.41194
1158 20 female 30.59 0 no northeast 2459.72010

Vemos que las observaciones 195 y 581 tienen exactamente los mismos datos. Teniendo en cuenta que comparten el mismo “bmi” exacto con otras muchas observaciones. Vamos a valorar el duplicado como una casualidad. Por ello, vamos a mantenerlo en nuestro conjunto de datos.

2a.3 Análisis de valores atípicos

En esta ocasión vamos a observar los outliers mediante dos métodos diferentes.

Usando Z-Score

Usando Z-Score: El Z-Score mide cuántas desviaciones estándar se encuentra un valor de la media. Valores que caen fuera de un rango de Z-Score específico se consideran outliers. Por ejemplo, un Z-Score de 2 indica que el valor está a dos desviaciones estándar de la media.

En general, un Z-Score de más de 3 se considera un outlier.

def identify_outliers(data, column_name, threshold=3):
    z_scores = np.abs(stats.zscore(data[column_name]))
    outliers = data[z_scores > threshold]
    return outliers


# Identify outliers in 'age'
outliers_age = identify_outliers(df, "age")

# Identify outliers in 'bmi'
outliers_bmi = identify_outliers(df, "bmi")

# Identify outliers in 'charges'
outliers_charges = identify_outliers(df, "charges")

print("Outliers in 'age':")
print(outliers_age)

print("Outliers in 'bmi':")
print(outliers_bmi)

print("Outliers in 'charges':")
print(outliers_charges)
Outliers in 'age':
Empty DataFrame
Columns: [age, sex, bmi, children, smoker, region, charges]
Index: []
Outliers in 'bmi':
      age   sex    bmi  children smoker     region     charges
116    58  male  49.06         0     no  southeast  11381.3254
847    23  male  50.38         1     no  southeast   2438.0552
1047   22  male  52.58         1    yes  southeast  44501.3982
1317   18  male  53.13         0     no  southeast   1163.4627
Outliers in 'charges':
      age     sex     bmi  children smoker     region      charges
34     28    male  36.400         1    yes  southwest  51194.55914
543    54  female  47.410         0    yes  southeast  63770.42801
577    31  female  38.095         1    yes  northeast  58571.07448
819    33  female  35.530         0    yes  northwest  55135.40209
1146   60    male  32.800         0    yes  southwest  52590.82939
1230   52    male  34.485         3    yes  northwest  60021.39897
1300   45    male  30.360         0    yes  southeast  62592.87309

Usando boxplot y IQR

IQR: El rango intercuartil (IQR) es la diferencia entre el tercer cuartil (Q3) y el primer cuartil (Q1). Los valores que caen por debajo de Q1 - 1.5 * IQR o por encima de Q3 + 1.5 * IQR se consideran outliers.

Los valores fuera del de este rango, son los que se representa como puntos en los boxplots.

# create a boxplot with 'age', 'bmi' y 'charges' variables
selected_columns = ["age", "bmi", "charges"]

for column in selected_columns:
    fig = px.box(df, x=column, title=f"Boxplot of {column}")
    fig.update_layout(title_x=0.5)
    fig.show()

Z-score vs Boxplot

Podemos ver como boxplot señala a más observaciones como outliers. En el caso de “bmi” las duplica, mientras que en “charges” son más del doble los detectados. Esto nos recuerda que juzgar una muestra como atípica, depende de nuestro método.

Ideas destacadas

Ambos métodos coinciden en: - “age”: no se detectan outliers - “BMI”: existen outliers, personas con una alta obesidad - “charges”: existen outliers, personas con cargos muy altos al seguro

Se pueden hacer tres cosas con los outliers, siguiendo la mnemotecnia 3R: rectificar, retener o remover. En este caso, podemos estar ante valores atípicos genuinos, por tanto vamos a retenerlos por el momento.

2a.4 Variables con varianza cercana a cero

Variables númericas

selected_columns = ["age", "bmi", "children", "charges"]

# Calculate the variance for each column
variances = df[selected_columns].var()

# Define a threshold for variance
threshold = 0.1

# Identify columns with near-zero or very small variance
zero_variance_cols = variances[variances <= threshold].index

print("Columns with Zero & Near Zero Variance:")
print(zero_variance_cols)
Columns with Zero & Near Zero Variance:
Index([], dtype='object')

Variables categoricas

selected_columns = ["sex", "smoker", "region"]

# Calculate the proportion of the most common category in each column
prop_most_common = df[selected_columns].apply(
    lambda col: col.value_counts().max() / len(col)
)

# Define a threshold for the proportion
threshold = 1

# Identify columns with the proportion of the most common category close to 1
zero_variance_cols = prop_most_common[prop_most_common >= threshold].index

print("Columns with Zero & Near Zero Proportion:")
print(zero_variance_cols)
Columns with Zero & Near Zero Proportion:
Index([], dtype='object')

Ideas destacadas

No se detectan variables con Zero & Near Zero Variance. A priori, todas las variables pueden estar aportando información.

2a.5 Valores ausentes o faltantes

df.isnull().sum()
age         0
sex         0
bmi         0
children    0
smoker      0
region      0
charges     0
dtype: int64

Ideas destacadas

  • No hay missing values

4. Pruebas de hipótesis

Vamos a responder a las siguientes preguntas con validez estadística:

  • ¿Los fumadores generan más gasto a la aseguradora que los no fumadores?
  • ¿Las mujeres tienen un BMI diferente a los hombres?
  • ¿La proporción de fumadores es diferente según la región?
  • ¿El promedio de BMI en las mujeres es diferente según el número de hijos que tengan?
  • ¿Es diferente la proporción de fumadores en ambos sexos?

4.1 ¿Los fumadores generan más gasto a la aseguradora que los no fumadores?

Primero hagamos una exploración visual.

fig = px.violin(
    df,
    x="charges",
    color="smoker",
    box=True,
    points="outliers",
)

fig.update_layout(
    title_text="Charges violin plot by smoker status",
)

fig.show()

En este caso las diferencias entre ambos grupos son obvias. Pero para poder afirmarlo adecuadamente, debemos hacerlo con significancia estadística. Vamos a comprobarlo con un test de hipótesis.

1. Seleccionamos la hipótesis y el nivel de significancia

H0: El gasto medio de los fumadores es igual al de los no-fumadores

Ha: El gasto medio de los fumadores es diferente al de los no-fumadores

alpha = 0.05

2. Identificamos el tipo de test

Deseamos comparar las medias de dos grupos de nuestra sample. Por lo tanto, un 2-Sample t-Test parece ser adecuado. Lo primero es verificar si se cumplen los requisitos del test.

2.1 Requisitos del test
  • Tenemos una sample representativa de la population.
  • Los datos son continuos.
  • Las muestras siguen una distribución normal o hay más de 15 observaciones.
  • Los grupos son independientes.
  • Las varianzas son iguales (o al menos similares).

Examinemos nuestra sample para ver si podemos aplicar el test.

Libro de refencia

Book: Hypothesis Testing An Intuitive Guide For Making Data Driven Decisions

Page: 48

Section: 2-Sample t-Tests

Número de observaciones para cada grupo:

df["smoker"].value_counts()
smoker
no     1064
yes     274
Name: count, dtype: int64

En inspección visual de los datos, vemos que no siguen una distribución normal.

Estudiemos la relación entre las varianzas de cada grupo.

smokers = df[df["smoker"] == "yes"]
nonsmokers = df[df["smoker"] == "no"]
# Perform the Levene's Test
statistic, p_value = stats.levene(smokers["charges"], nonsmokers["charges"])

# Significance level
alpha = 0.05

# Check for significance
if p_value < alpha:
    print("We reject the null hypothesis. The variances are not similar.")
else:
    print("We fail to reject the null hypothesis. The variances are similar.")
We reject the null hypothesis. The variances are not similar.

Volvamos sobre los requisitos del test:

  • ¿Tenemos una sample representativa de la population? Suponemos que sí.
  • ¿Los datos son continuos? Sí.
  • ¿Las muestras siguen una distribución normal o hay más de 15 observaciones?
    • No, las muestras no siguen una distribución normal. Pero hay más de 15 observaciones en cada grupo, gracias al teorema central del límite podemos renunciar al supuesto de normalidad.
  • ¿Los grupos son independientes? Sí.
  • ¿Las varianzas son iguales (o al menos similares)?
    • No.

No cumplen los requisitos para realizar un 2-Sample t-Test. Vamos a realizar un test tipo Welch’s t-test.

Para realizar el test utilizaremos scipy.stats.ttest_ind. Es necesario definir el parámetro equal_varbool como False.

# Perform the Welch's t-test (equal_var=False)
statistic, p_value = stats.ttest_ind(
    nonsmokers["charges"], smokers["charges"], equal_var=False
)

# Print the results
print("p-value:", p_value)

# Check for significance
alpha = 0.05  # Significance level
if p_value < alpha:
    print(
        "We reject the null hypothesis. There are significant differences between the groups."
    )
else:
    print(
        "We fail to reject the null hypothesis. There are no significant differences between the groups."
    )
p-value: 5.88946444671698e-103
We reject the null hypothesis. There are significant differences between the groups.

Ideas destacadas

Como ya nos adelantaba la exploración visual, rechazamos la hipótesis nula. Tenemos evidencia suficiente (95% y 99%) para demostrar que existe una diferencia en los cargos de fumadores y no fumadores.

4.2 ¿Las mujeres tienen un BMI diferente a los hombres?

Primero hagamos una exploración visual.

fig = px.violin(
    df,
    x="bmi",
    color="sex",
    box=True,
    points="outliers",
)

fig.update_layout(
    title_text="Charges violin plot by smoker status",
)

fig.show()

En esta ocasión “bmi” podría no variar en función de “sex”. ¿Pero es estadísticamente significativo? Vamos a comprobarlo con un test de hipótesis.

1. Seleccionamos la hipótesis y el nivel de significancia

H0: El BMI medio de las mujeres es igual al de los hombres

Ha: El BMI medio de las mujeres es diferente al de los hombres

alpha = 0.05

2. Identificamos el tipo de test

Deseamos comparar las medias de dos grupos de nuestra sample. Por lo tanto, un 2-Sample t-Test parece ser adecuado. Lo primero es verificar si se cumplen los requisitos del test.

2.1 Requisitos del test
  • Tenemos una sample representativa de la population.
  • Los datos son continuos.
  • Las muestras siguen una distribución normal o hay más de 15 observaciones.
  • Los grupos son independientes.
  • Las varianzas son iguales (o al menos similares).

Examinemos nuestra sample para ver si podemos aplicar el test.

Libro de refencia

Book: Hypothesis Testing An Intuitive Guide For Making Data Driven Decisions

Page: 48

Section: 2-Sample t-Tests

Número de observaciones para cada grupo:

df["sex"].value_counts()
sex
male      676
female    662
Name: count, dtype: int64

Realizamos un test de normalidad para cada grupo.

men = df[df["sex"] == "male"]
women = df[df["sex"] == "female"]
def shapiro_test(data, alpha=0.05):
    """
    Perform the Shapiro-Wilk test to check the normality of the data.

    Parameters:
    data (array-like): The data to analyze.
    alpha (float): Significance level.

    Returns:
    str: The test result.
    """
    statistic, p_value = stats.shapiro(data)

    if p_value < alpha:
        return "We reject the null hypothesis. The data does not follow a normal distribution."
    else:
        return "We fail to reject the null hypothesis. The data can be considered normally distributed."


# Run the Shapiro-Wilk test
result_men = shapiro_test(men["charges"])
result_women = shapiro_test(women["charges"])

print("For men:", result_men)
print("For women:", result_women)
For men: We reject the null hypothesis. The data does not follow a normal distribution.
For women: We reject the null hypothesis. The data does not follow a normal distribution.

Estudiemos la relación entre las varianzas de cada grupo.

# Perform the Levene's Test
statistic, p_value = stats.levene(men["bmi"], women["bmi"])

# Significance level
alpha = 0.05

# Check for significance
if p_value < alpha:
    print("We reject the null hypothesis. The variances are not similar.")
else:
    print("We fail to reject the null hypothesis. The variances are similar.")
We fail to reject the null hypothesis. The variances are similar.

Volvamos sobre los requisitos del test:

  • ¿Tenemos una sample representativa de la population? Suponemos que sí.
  • ¿Los datos son continuos? Sí.
  • ¿Las muestras siguen una distribución normal o hay más de 15 observaciones?
    • No, las muestras no siguen una distribución normal. Pero hay más de 15 observaciones en cada grupo, gracias al teorema central del límite podemos renunciar al supuesto de normalidad.
  • ¿Los grupos son independientes? Sí.
  • ¿Las varianzas son iguales (o al menos similares)? Sí.

Se cumplen los requisitos para realizar un 2-Sample t-Test.

Para realizar el test vamos a usar scipy.stats.ttest_ind.

# Realiza el test t de Welch (equal_var=False)
statistic, p_value = stats.ttest_ind(men["bmi"], women["bmi"])

# Check for significance
alpha = 0.05  # Significance level
if p_value < alpha:
    print(
        "We reject the null hypothesis. There are significant differences between the groups."
    )
else:
    print(
        "We fail to reject the null hypothesis. There are no significant differences between the groups."
    )
We fail to reject the null hypothesis. There are no significant differences between the groups.

Ideas destacadas

No tenemos evidencia suficiente para rechazar la hipótesis nula. No podemos afirmar que exista una diferencia en el BMI medio de hombres y mujeres.

4.3 ¿La proporción de fumadores es diferente según la región?

# Calculate the proportion of smokers by region
smokers_by_region = (
    df.groupby("region")["smoker"]
    .value_counts(normalize=True)
    .rename("proportion")
    .reset_index()
)

# Create a bar chart to show the proportion of smokers by region
fig = px.bar(
    smokers_by_region,
    x="region",
    y="proportion",
    color="smoker",
    title="Proportion of Smokers by Region",
    labels={
        "proportion": "Proportion of Policyholders",
        "smoker": "Smoker",
        "region": "Region",
    },
    category_orders={"smoker": ["yes", "no"]},
)  # Order the legend

# Adjust the text to display the proportions as percentages and ensure it's inside the bar for better readability
fig.update_traces(texttemplate="%{y:.1%}", textposition="inside")

fig.show()

La máxima diferencia entre regiones es de un 7.2%. ¿Es suficiente para afirmar que la proporción es diferente según la región? Vamos a comprobarlo con un test de hipótesis.

1. Seleccionamos la hipótesis y el nivel de significancia

H0: No existe una diferencia en la proporción de fumadores según la región. Es decir, las variables son independientes.

Ha: Existe una diferencia en la proporción de fumadores según la región

alpha = 0.05

2. Identificamos el tipo de test

Queremos determinar si existe una relación estadísticamente significativa entre dos variables categóricas. Por lo que un Chi-Square Test parece lo adecuado.

2.1 Requisitos del test
  • Las variables son categóricas.
  • Las observaciones son independientes.
  • Cada celda de la tabla de contingencia tiene un valor esperado de al menos 5.

Examinemos nuestra sample para ver si podemos aplicar el test.

Libro de refencia

Book: Hypothesis Testing An Intuitive Guide For Making Data Driven Decisions

Page: 315

Section: Chi-Square Tests of Independence

Creamos la tabla de contingencia.

contingency_table = pd.crosstab(df["region"], df["smoker"])
contingency_table
smoker no yes
region
northeast 257 67
northwest 267 58
southeast 273 91
southwest 267 58

Volvamos sobre los requisitos del test:

  • ¿Las variables son categóricas? Sí.
  • ¿Las observaciones son independientes? Sí.
  • ¿Cada celda de la tabla de contingencia tiene un valor esperado de al menos 5? Sí.

Se cumplen los requisitos para realizar un Chi-Square Test.

Para realizar el test utilizaremos stats.chi2_contingency.

# Perform the Chi-square independence test
c, p_value, dof, expected = stats.chi2_contingency(contingency_table)

print("P-value:", p_value)

# Check for significance
alpha = 0.05  # Significance level
if p_value < alpha:
    print(
        "We reject the null hypothesis. There is a relationship between the variables."
    )
else:
    print("We fail to reject the null hypothesis")
P-value: 0.06171954839170541
We fail to reject the null hypothesis

Ideas destacadas

Fallamos al rechazar la hipótesis nula. No podemos concluir que no existe relación entre fumadores y la región.

4.4 ¿El promedio de BMI en las mujeres es diferente según el número de hijos que tengan?

En este caso vamos a trabajar con los datos de las mujeres que tienen entre 0 y 2 hijos.

women_few_children_df = df.loc[
    (df["sex"] == "female") & (df["children"].isin([0, 1, 2]))
]

Primero hagamos una exploración visual.

fig = px.violin(
    women_few_children_df,
    x="bmi",
    color="children",
    box=True,
    points="outliers",
)

fig.update_layout(
    title_text="BMI violin plot by children",
)

fig.show()

Parece que no existen grandes diferencias. ¿Pero es estadísticamente significativo? Vamos a comprobarlo con un test de hipótesis.

1. Seleccionamos la hipótesis y el nivel de significancia

H0: Los tres grupos tienen el mismo promedio de BMI

Ha: Al menos uno de los grupos tiene un promedio de BMI diferente

alpha = 0.05

2. Identificamos el tipo de test

Deseamos comparar las medias de tres grupos de nuestra muestra. Por lo que un One-Way ANOVA parece lo adecuado. Lo primero es ver si se cumplen los requisitos del test.

2.1 Requisitos del test
  • La variable dependiente es continua.
  • La variable independiente es categórica.
  • Las muestras siguen una distribución normal o hay más de 20 observaciones.
  • Los grupos son independientes.
  • Las varianzas son similares.

Examinemos nuestra sample para ver si podemos aplicar el test.

Libro de refencia

Book: Hypothesis Testing An Intuitive Guide For Making Data Driven Decisions

Page: 197

Section: One-Way ANOVA

Número de observaciones para cada grupo:

women_few_children_df["children"].value_counts()
children
0    289
1    158
2    119
Name: count, dtype: int64
# Run the Shapiro-Wilk test
result_zero = shapiro_test(df[df["children"] == 0]["bmi"])
result_one = shapiro_test(df[df["children"] == 1]["bmi"])
result_two = shapiro_test(df[df["children"] == 2]["bmi"])

print("For zero child:", result_zero)
print("For one child:", result_one)
print("For two children:", result_two)
For zero child: We reject the null hypothesis. The data does not follow a normal distribution.
For one child: We reject the null hypothesis. The data does not follow a normal distribution.
For two children: We fail to reject the null hypothesis. The data can be considered normally distributed.
# Perform the Levene's Test
statistic, p_value = stats.levene(
    df[df["children"] == 0]["bmi"],
    df[df["children"] == 1]["bmi"],
    df[df["children"] == 2]["bmi"],
)

# Significance level
alpha = 0.05

# Check for significance
if p_value < alpha:
    print("We reject the null hypothesis. The variances are not similar.")
else:
    print("We fail to reject the null hypothesis. The variances are similar.")
We fail to reject the null hypothesis. The variances are similar.

Volvamos sobre los requisitos del test:

  • ¿La variable dependiente es continua? Sí.
  • ¿La variable independiente es categórica? Sí.
  • ¿Las muestras siguen una distribución normal o hay más de 20 observaciones
    • No, las muestras no siguen una distribución normal. Pero hay más de 20 observaciones en cada grupo, gracias al teorema central del límite podemos renunciar al supuesto de normalidad.
  • ¿Los grupos son independientes? Sí.
  • ¿Las varianzas son similares? Sí.

Se cumplen los requisitos para realizar un One-Way ANOVA.

Para realizar el test utilizaremos scipy.stats.f_oneway.

f_statistic, p_value = stats.f_oneway(
    df[df["children"] == 0]["bmi"],
    df[df["children"] == 1]["bmi"],
    df[df["children"] == 2]["bmi"],
)

# Check for significance
alpha = 0.05  # Significance level
if p_value < alpha:
    print(
        "We reject the null hypothesis. There are significant differences between the groups."
    )
else:
    print(
        "We fail to reject the null hypothesis. There are no significant differences between the groups."
    )
We fail to reject the null hypothesis. There are no significant differences between the groups.

Ideas destacadas

Fallamos al rechazar la hipótesis nula. No hay diferencias en el BMI en función del número de hijos.

4.5 ¿Es diferente la proporción de fumadores en ambos sexos?

Primero hagamos una exploración visual.

# Calculate the proportion of smokers by sex
smokers_by_sex = (
    df.groupby("sex")["smoker"]
    .value_counts(normalize=True)
    .rename("proportion")
    .reset_index()
)

# Create a bar chart to show the proportion of smokers by sex
fig = px.bar(
    smokers_by_sex,
    x="sex",
    y="proportion",
    color="smoker",
    title="Proportion of Smokers by sex",
    labels={
        "proportion": "Proportion of Policyholders",
        "smoker": "Smoker",
        "sex": "sex",
    },
    category_orders={"smoker": ["yes", "no"]},
)  # Order the legend

# Adjust the text to display the proportions as percentages and ensure it's inside the bar for better readability
fig.update_traces(texttemplate="%{y:.1%}", textposition="inside")

fig.show()

Parece que existen diferencias. ¿Pero son estadísticamente significativas? Vamos a comprobarlo con un test de hipótesis.

1. Seleccionamos la hipótesis y el nivel de significancia

H0: La proporcion de fumadores es igual en ambos sexos.

Ha: La proporcion de fumadores es diferente.

alpha = 0.05

2. Identificamos el tipo de test

Deseamos comparar la proporción en dos variables binarias. Por lo que un Two-Sample Proportion Test parece lo adecuado. Lo primero es ver si se cumplen los requisitos del test.

2.1 Requisitos del test
  • Variables binarias.
  • Grupos independientes.
  • Cada muestra es independiente.
  • Las proporciones se mantienen constantes en el tiempo.

Examinemos nuestra sample para ver si podemos aplicar el test.

Libro de refencia

Book: Hypothesis Testing An Intuitive Guide For Making Data Driven Decisions

Page: 283

Section: Two-Sample Proportion Test

Volvamos sobre los requisitos del test:

  • ¿Variables binarias? Sí.
  • ¿Grupos independientes? Sí.
  • ¿Cada muestra es independiente? Sí.
  • ¿Las proporciones se mantienen constantes en el tiempo? Sí.

Se cumplen los requisitos para realizar un Two-Sample Proportion Test.

Para realizar el test vamos a usar statsmodels.stats.proportion.proportions_ztest.

contingency_table = pd.crosstab(df["sex"], df["smoker"])
contingency_table
smoker no yes
sex
female 547 115
male 517 159
# Create two groups based on "sex" and "smoker"
group1 = df[(df["sex"] == "female") & (df["smoker"] == "yes")]
group2 = df[(df["sex"] == "female") & (df["smoker"] == "no")]

# Count the number of observations in each group
count1 = len(group1)
count2 = len(group2)

# Count the number of smokers (successes) in each group
success1 = len(group1[group1["smoker"] == "yes"])
success2 = len(group2[group2["smoker"] == "yes"])

# Perform the Two-Sample Proportions Test
stat, p_value = sm.stats.proportions_ztest([success1, success2], [count1, count2])

# Check for significance
alpha = 0.05

if p_value < alpha:
    print(
        "We reject the null hypothesis. There are significant differences in proportions between sexes."
    )
else:
    print(
        "We fail to reject the null hypothesis. There are no significant differences in proportions between sexes."
    )
We reject the null hypothesis. There are significant differences in proportions between sexes.

Ideas destacadas

Rechazamos la hipótesis nula. Existen diferencias en a proporción de fumadores entre ambos sexos.

5. Recapitulación y reflexiones

Repasemos nuestras preguntas iniciales y lo que hemos averiguado al respecto:

  • ¿Los fumadores generan más gasto a la aseguradora que los no fumadores?
    • Sí, con una evidencia muy alta.
  • ¿Las mujeres tienen un BMI diferente a los hombres?
    • No, no podemos afirmar que exista una diferencia en el BMI medio de hombres y mujeres.
  • ¿La proporción de fumadores es diferente según la región?
    • No, no podemos concluir que no existe relación entre fumadores y región.
  • ¿El promedio de BMI en las mujeres es diferente según el número de hijos que tengan?
    • No, no hay diferencias en el BMI en función del número de hijos.
  • ¿Es diferente la proporción de fumadores en ambos sexos?
    • Sí, los hombres tienen una mayor proporción de fumadores.