Manejo de valores faltantes en Pandas

En los datos reales a menudo existen valores faltantes (NaN). Pandas proporciona funciones abundantes para procesar datos faltantes. Esta sección detalla el uso de métodos como fillna, dropna, interpolate.


Representación de valores faltantes

En Pandas se utilizaNaN(Not a Number) para representar un valor faltante, que proviene de la biblioteca NumPy.

Ejemplo

import pandas as pd
import numpy as np

# Crear datos con valores faltantes
s = pd.Series([1, 2, np.nan, 4, 5])
print("Series con NaN:")
print(s)
print(f"¿Tiene valores faltantes?: {s.isna().any()}")
print()

# Valores faltantes en DataFrame
df = pd.DataFrame({
    "A": [1, 2, np.nan, 4],
    "B": [np.nan, 2, 3, 4],
    "C": [1, 2, 3, np.nan]
})

print("DataFrame con valores faltantes:")
print(df)
print()

# Detectar valores faltantes
print("Ubicación de los valores faltantes:")
print(df.isna())
print()

# Contar la cantidad de valores faltantes por columna
print("Cantidad de valores faltantes por columna:")
print(df.isna().sum())

En Pandas,NaN、None、pandas.NAse reconocen como valores faltantes. Useisna()oisnull()para detectar estos valores faltantes de manera uniforme.


dropna: eliminar valores faltantes

Eliminar filas

Ejemplo

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, np.nan, 4],
    "B": [1, np.nan, 3, 4],
    "C": [1, 2, 3, np.nan]
})

print("Datos originales:")
print(df)
print()

# Eliminar filas que contienen valores faltantes (por defecto)
print("Eliminar filas con valores faltantes:")
print(df.dropna())
print()

# how='all': solo elimina si todos son valores faltantes
print("Solo se eliminan las filas donde todos son valores faltantes:")
print(df.dropna(how="all"))
print()

# thresh: conservar solo si tiene al menos N valores no faltantes
print("Solo se conservan las filas con al menos 2 valores no faltantes:")
print(df.dropna(thresh=2))

Eliminar columnas

Ejemplo

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, np.nan, 4],
    "B": [np.nan, np.nan, np.nan, np.nan],  # Todos faltantes
    "C": [1, 2, 3, 4]
})

print("Datos originales:")
print(df)
print()

# Eliminar columnas que contienen valores faltantes
print("Eliminar columnas con valores faltantes:")
print(df.dropna(axis=1))
print()

# how='all': eliminar columnas donde todos son valores faltantes
print("Eliminar columnas donde todos son valores faltantes:")
print(df.dropna(axis=1, how="all"))

fillna: rellenar valores faltantes

Relleno con valor fijo

Ejemplo

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, np.nan, 4, 5],
    "B": [np.nan, 2, 3, np.nan, 5],
    "C": [1, 2, 3, 4, np.nan]
})

print("Datos originales:")
print(df)
print()

# Rellenar con 0
print("Rellenar con 0:")
print(df.fillna(0))
print()

# Rellenar diferentes columnas con valores específicos
print("Diferentes columnas rellenas con diferentes valores:")
print(df.fillna({"A": 0, "B": 99, "C": -1}))
print()

# Rellenar con el valor anterior (relleno hacia adelante)
print("Relleno hacia adelante:")
print(df.fillna(method="ffill"))
print()

# Rellenar con el siguiente valor (relleno hacia atrás)
print("Relleno hacia atrás:")
print(df.fillna(method="bfill"))

Relleno con valores estadísticos

Ejemplo

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, np.nan, 4, 5, 6],
    "B": [10, np.nan, 30, np.nan, 50, 60]
})

print("Datos originales:")
print(df)
print()

# Rellenar con la media
print("Rellenar con la media:")
print(df.fillna(df.mean()))
print()

# Rellenar con la mediana
print("Rellenar con la mediana:")
print(df.fillna(df.median()))
print()

# Rellenar por columna por separado
print("Columna A con media, columna B con 0:")
print(df.fillna({"A": df["A"].mean(), "B": 0}))

El relleno hacia adelante y hacia atrás es especialmente útil en datos de series temporales, ya que mantiene la continuidad de los datos. La elección del método depende del significado comercial de los datos.


interpolate: relleno por interpolación

La interpolación es un método de relleno más inteligente que puede inferir valores faltantes a partir de datos adyacentes.

Interpolación lineal

Ejemplo

import pandas as pd
import numpy as np

s = pd.Series([1, 2, np.nan, 4, 5, np.nan, 7])

print("Serie original:")
print(s)
print()

# Interpolación lineal (por defecto)
print("Interpolación lineal:")
print(s.interpolate())
print()

# Especificar método de interpolación
print("Interpolación ponderada por tiempo (series temporales):")
s2 = pd.Series([1, np.nan, np.nan, 4], index=pd.date_range("2024-01-01", periods=4, freq="D"))
print(s2.interpolate(method="time"))
print()

# Relleno con valores vecinos
print("Rellenar con valores vecinos:")
print(s.interpolate(method="nearest"))

Interpolación en DataFrame

Ejemplo

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, np.nan, 4, 5],
    "B": [10, np.nan, 30, 40, np.nan]
})

print("Datos originales:")
print(df)
print()

# Interpolar sobre el DataFrame original
df_interpolated = df.interpolate(method="linear")
print("Después de la interpolación lineal:")
print(df_interpolated)
print()

# Limitar el rango de interpolación
print("Solo rellenar el inicio y el final de los valores faltantes consecutivos (máximo 1):")
print(df.interpolate(limit=1))

Práctica: procesamiento de datos reales

Ejemplo

import pandas as pd
import numpy as np

# Simular datos comerciales reales
np.random.seed(42)
n = 20

df = pd.DataFrame({
    "Fecha": pd.date_range("2024-01-01", periods=n),
    "Ventas": np.random.choice([100, 200, np.nan, 300, np.nan], n),
    "Número de clientes": np.random.choice([10, np.nan, 20, 30], n),
    "Tasa de conversión": np.random.choice([0.05, 0.1, np.nan, 0.15], n)
})

print("Situación de valores faltantes en los datos originales:")
print(df.isna().sum())
print()

# Estrategia de procesamiento:
# 1. Las ventas se rellenan con la media de los valores anterior y posterior (el negocio permite la fluctuación)
df["Ventas"] = df["Ventas"].interpolate()

# 2. El número de clientes se rellena con la media
df["Número de clientes"] = df["Número de clientes"].fillna(df["Número de clientes"].mean())

# 3. La tasa de conversión se rellena con 0 (indica que no hubo conversión)
df["Tasa de conversión"] = df["Tasa de conversión"].fillna(0)

print("Datos después del procesamiento:")
print(df)
print()

print("Situación de valores faltantes después del procesamiento:")
print(df.isna().sum())

Preguntas frecuentes

1. ¿fillna crea un objeto nuevo o modifica in situ?

fillnaPor defecto devuelve un objeto nuevo; usandoinplace=Truese puede modificar in situ.

2. Aún quedan valores faltantes después de la interpolación

Si el valor faltante está al inicio o al final de la secuencia, la interpolación no puede rellenarlo y se necesita un procesamiento adicional.

3. Distinguir entre NaN y cadena vacía

La cadena vacía""no es un valor faltante; se necesita usarreplace("", np.nan)para convertir.

Al elegir el método de relleno se debe considerar el significado comercial: el relleno hacia adelante es adecuado para series temporales, el relleno hacia atrás para datos estáticos, la media para datos numéricos y la interpolación para datos continuos.

Otras extensiones