Ejercicio coches

"""
╔══════════════════════════════════════════════════════════════════╗
║   EJERCICIO: "NOS HAN DICHO QUE LOS COCHES MÁS POTENTES        ║
║               GASTAN MÁS COMBUSTIBLE... ¿ES CIERTO?"            ║
╚══════════════════════════════════════════════════════════════════╝

LA SITUACIÓN
────────────
  Un amigo mecánico te dice:
  "Oye, está clarísimo: cuantos más caballos tiene un coche,
   más combustible gasta. Siempre ha sido así."

  ¿Tiene razón? ¿Podemos demostrarlo (o refutarlo) con datos?

  En este ejercicio vas a:
    1. Cargar un dataset real de coches
    2. Entender qué contiene
    3. Limpiarlo correctamente
    4. Calcular si realmente existe esa relación
    5. Visualizarla
    6. Responder preguntas para interpretar los resultados

EL DATASET: MPG (Miles Per Gallon)
────────────────────────────────────
  Contiene información de 398 coches fabricados entre 1970 y 1982.
  Fue recopilado originalmente por la revista Consumer Reports y
  es uno de los datasets clásicos del aprendizaje automático.

  Columnas principales:
    mpg          → millas por galón (eficiencia: más = gasta MENOS)
    cylinders    → número de cilindros del motor
    displacement → cilindrada (pulgadas cúbicas)
    horsepower   → caballos de potencia (HP)
    weight       → peso del coche (libras)
    acceleration → aceleración (segundos de 0 a 60 mph)
    model_year   → año del modelo (70 = 1970, 82 = 1982)
    origin       → origen (1=EEUU, 2=Europa, 3=Japón)
    name         → nombre del modelo

  PREGUNTA A INVESTIGAR:
    ¿Existe relación entre los caballos de potencia (horsepower)
    y el consumo de combustible (mpg)?

Librerías necesarias:
  pip install pandas matplotlib seaborn
"""

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import seaborn as sns
import numpy as np
from scipy import stats


# ═══════════════════════════════════════════════════════════════════
#  PASO 1 — CARGA DE DATOS
# ═══════════════════════════════════════════════════════════════════
# Cargamos el dataset "mpg" directamente desde seaborn.
# seaborn incluye varios datasets de ejemplo listos para usar;
# no hace falta descargar ningún archivo manualmente.

print("\n" + "═"*60)
print("  PASO 1 — CARGA DE DATOS")
print("═"*60)

coches = sns.load_dataset("mpg")

# Comprobamos que se ha cargado correctamente: cuántas filas y columnas
print(f"\n  Filas    : {coches.shape[0]}")
print(f"  Columnas : {coches.shape[1]}")
print(f"  Nombres  : {coches.columns.tolist()}")


# ═══════════════════════════════════════════════════════════════════
#  PASO 2 — PRIMER VISTAZO
# ═══════════════════════════════════════════════════════════════════
# Antes de analizar nada, siempre hay que MIRAR los datos.
# Es como abrir una caja antes de saber qué hay dentro.

print("\n" + "═"*60)
print("  PASO 2 — PRIMER VISTAZO")
print("═"*60)

print("\n── .head(): primeras 5 filas ──────────────────────────────")
print(coches.head())

print("\n── .tail(): últimas 5 filas ───────────────────────────────")
print(coches.tail())

print("\n── .dtypes: tipo de dato de cada columna ──────────────────")
print(coches.dtypes)
# ATENCIÓN: fíjate en el tipo de 'horsepower'. ¿Es numérico?
# Si aparece como 'object' en lugar de 'float64', significa que
# pandas lo ha interpretado como texto.

print("\n── .describe(): estadísticas rápidas ──────────────────────")
print(coches.describe().round(2))
# describe() solo muestra columnas numéricas por defecto.
# Si 'horsepower' no aparece aquí, confirma que es texto.


# ═══════════════════════════════════════════════════════════════════
#  PASO 3 — ANÁLISIS DE CALIDAD: ¿ESTÁN BIEN LOS DATOS?
# ═══════════════════════════════════════════════════════════════════
# Los datos reales casi nunca son perfectos. Hay que buscar:
#   a) Valores nulos (celdas vacías)
#   b) Tipos de datos incorrectos
#   c) Valores extraños o imposibles

print("\n" + "═"*60)
print("  PASO 3 — ANÁLISIS DE CALIDAD DE LOS DATOS")
print("═"*60)

# ── a) Valores nulos ────────────────────────────────────────────
print("\n── a) ¿Cuántos valores nulos hay por columna? ─────────────")
nulos = coches.isnull().sum()
print(nulos)
print(f"\n  Total de celdas nulas: {nulos.sum()}")

print("\n── c) Rango de 'mpg' ──────────────────────────────────────")
print(f"  Mínimo: {coches['mpg'].min():.1f}  |  Máximo: {coches['mpg'].max():.1f}")


# ═══════════════════════════════════════════════════════════════════
#  PASO 4 — LIMPIEZA DE DATOS
# ═══════════════════════════════════════════════════════════════════
# Ahora que sabemos los problemas, los corregimos uno a uno.
# Es importante hacerlo en un paso separado y documentado.

print("\n" + "═"*60)
print("  PASO 4 — LIMPIEZA DE DATOS")
print("═"*60)

# Hacemos una copia para no modificar el dataset original
# (buena práctica: siempre trabajar sobre una copia)
df = coches.copy()

# ── Corrección 2: eliminar filas con NaN en las columnas clave ───
# Solo nos importan 'mpg' y 'horsepower' para este análisis.
# dropna(subset=[...]) elimina solo las filas con NaN en esas columnas.
filas_antes = len(df)
df = df.dropna(subset=["mpg", "horsepower"])
filas_despues = len(df)

print(f"  ✓ Filas eliminadas con NaN: {filas_antes - filas_despues}")
print(f"  ✓ Filas disponibles para el análisis: {filas_despues}")

# ── Verificación final ───────────────────────────────────────────
print(f"\n  Nulos restantes en 'mpg'       : {df['mpg'].isnull().sum()}")
print(f"  Nulos restantes en 'horsepower': {df['horsepower'].isnull().sum()}")
print("\n  Dataset limpio y listo para analizar.")


# ═══════════════════════════════════════════════════════════════════
#  PASO 5 — ESTADÍSTICAS DESCRIPTIVAS DE LAS VARIABLES CLAVE
# ═══════════════════════════════════════════════════════════════════
# Antes de calcular la correlación, conoce bien cada variable
# por separado. ¿En qué rango están? ¿Hay mucha variación?

print("\n" + "═"*60)
print("  PASO 5 — ESTADÍSTICAS DE LAS VARIABLES CLAVE")
print("═"*60)

for col, nombre in [("mpg", "Eficiencia (mpg)"),
                    ("horsepower", "Potencia (HP)")]:
    s = df[col]
    print(f"\n  {nombre}:")
    print(f"    Media         : {s.mean():.1f}")
    print(f"    Mediana       : {s.median():.1f}")
    print(f"    Desv. típica  : {s.std():.1f}")
    print(f"    Mínimo        : {s.min():.1f}")
    print(f"    Máximo        : {s.max():.1f}")


# ═══════════════════════════════════════════════════════════════════
#  PASO 6 — CALCULAR LA CORRELACIÓN
# ═══════════════════════════════════════════════════════════════════
# Ahora sí: calculamos el coeficiente de Pearson entre
# 'horsepower' y 'mpg'.
#
# RECORDATORIO:
#   r cercano a +1 → relación positiva fuerte
#   r cercano a -1 → relación negativa fuerte
#   r cercano a  0 → sin relación lineal clara
#
# OJO: mpg mide eficiencia (más mpg = MENOS consumo).
# Si el amigo tiene razón, esperamos r NEGATIVO:
# más HP → menos mpg (peor eficiencia = más consumo).

print("\n" + "═"*60)
print("  PASO 6 — CORRELACIÓN DE PEARSON")
print("═"*60)

r,p=stats.pearsonr(df["mpg"], df["horsepower"])
print(f"La correlación entre potencia y eficiencia es {r:.2f} con una significación de {p:.2f}.")

# ═══════════════════════════════════════════════════════════════════
#  PASO 7 — PREGUNTAS INTERPRETATIVAS
# ═══════════════════════════════════════════════════════════════════
# Lee los resultados con atención antes de responder.

print("\n" + "═"*60)
print("  PASO 8 — PREGUNTAS PARA REFLEXIONAR")
print("═"*60)
print(f"""
  Antes de responder, fíjate en:
    • El valor de r y su signo

  ──────────────────────────────────────────────────────────
  BLOQUE A — Sobre los datos

  1. ¿Cuántos coches tenía el dataset original?
     ¿Cuántos se han eliminado en la limpieza y por qué?
     ¿Crees que esa pérdida afecta al análisis?



  ──────────────────────────────────────────────────────────
  BLOQUE B — Sobre la correlación

  4. El coeficiente r 
     ¿Es positivo o negativo? ¿Qué significa eso en este contexto?
     (Recuerda: mpg alto = gasta POCO; mpg bajo = gasta MUCHO)

  5. ¿Tenía razón el amigo mecánico?
     Formula la respuesta con datos concretos.

  6. R² 
     Eso significa que la potencia (HP) explica el ___% de las
     diferencias de consumo entre coches.
     ¿Qué otros factores podrían explicar el resto?

  7. El p-valor es 
     ¿Podemos confiar en este resultado o podría ser coincidencia?

  

  ──────────────────────────────────────────────────────────
  BLOQUE D — Reflexión final

  11. "Correlación no implica causalidad."
      ¿Puedes pensar en una variable que esté relacionada tanto
      con la potencia como con el consumo y que pudiera estar
      "confundiendo" la relación? (Pista: mira las columnas del
      dataset)

  12. Si quisieras PREDECIR el consumo de un coche nuevo del que
      solo sabes los HP, ¿usarías este modelo?
      ¿Qué columnas añadirías para mejorar la predicción?
""")



Publicado por

Juan Pablo Fuentes

Formador de programación y bases de datos