Cómo tratar valores nulos en PySpark: paso a paso
Los valores nulos (NULL) aparecen en casi todos los conjuntos de datos reales: un campo sin rellenar, un join sin coincidencia o un sensor que falló. Si no se tratan, distorsionan las medias, producen recuentos engañosos e incluso provocan errores en modelos de machine learning. Saber tratar valores nulos en PySpark a escala es, por eso, una competencia esencial, y Spark ofrece tres enfoques sencillos y rápidos: eliminarlos, rellenarlos o sustituirlos por un valor alternativo.
Requisitos previos
- Python 3.8 o superior instalado.
- PySpark instalado con
pip install pysparky Java 8, 11 o 17 en el sistema. - Nociones básicas de DataFrames en PySpark (cómo leer datos y listar columnas).
Paso 1: Crear una SparkSession y un DataFrame de ejemplo
Para probar cada técnica de forma segura, empezamos creando una SparkSession y un pequeño DataFrame con algunos None — que Spark convierte automáticamente en NULL. Tener datos de ejemplo controlados hace mucho más fácil ver el efecto de cada función.
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("valores-nulos").getOrCreate()
dados = [
("Ana", "Porto", 30),
("Bruno", None, None),
(None, "Lisboa", 25),
("Rita", None, 41),
]
df = spark.createDataFrame(dados, ["nome", "cidade", "idade"])
df.show()
Paso 2: Contar valores nulos por columna
Antes de decidir qué hacer, es buena práctica medir el problema. La siguiente expresión recorre cada columna y cuenta cuántas filas son nulas, dándote una foto inmediata de la calidad de los datos.
from pyspark.sql.functions import col, count, when
df.select([
count(when(col(c).isNull(), c)).alias(c)
for c in df.columns
]).show()
El resultado muestra el número de nulos en nome, cidade e idade. Con estos números queda claro qué columna necesita más atención y qué estrategia encaja mejor.
Paso 3: Eliminar filas con na.drop
Cuando una fila con datos ausentes no aporta nada al análisis, lo más sencillo es eliminarla con na.drop() (también disponible como dropna()). El parámetro how decide si borramos filas con cualquier nulo o solo las que están completamente vacías.
# Elimina filas con CUALQUIER valor nulo
df.na.drop(how="any").show()
# Elimina solo filas totalmente vacias
df.na.drop(how="all").show()
# Conserva filas con al menos 2 valores no nulos
df.na.drop(thresh=2).show()
# Comprueba los nulos solo en columnas especificas
df.na.drop(subset=["cidade"]).show()
Por defecto, na.drop() usa how="any", así que basta un nulo para que la fila se elimine. Usa subset cuando solo te importan las columnas críticas.
Paso 4: Rellenar nulos con na.fill
Muchas veces queremos conservar todas las filas y solo sustituir los nulos por un valor por defecto. Eso es justo lo que hace na.fill() (o fillna()). Con un diccionario puedes indicar un valor diferente para cada columna.
# Rellena las columnas de texto nulas con "Desconhecido"
df.na.fill("Desconhecido").show()
# Un valor diferente por columna
df.na.fill({"cidade": "Sem cidade", "idade": 0}).show()
Cuidado con un error habitual: Spark solo rellena columnas cuyo tipo sea compatible con el valor indicado. Un texto no rellena columnas numéricas ni al revés, por lo que el diccionario por columna es la forma más segura de evitar sorpresas.
Paso 5: Sustituir nulos por otra columna con coalesce
La función coalesce devuelve el primer valor no nulo de una lista de columnas o expresiones. Es ideal para crear un valor de reserva: si la primera opción está vacía, usa la siguiente.
from pyspark.sql.functions import coalesce, lit
df.withColumn(
"cidade_final",
coalesce(col("cidade"), lit("N/D"))
).show()
Siempre que cidade sea nula, la nueva columna cidade_final toma "N/D"; en caso contrario mantiene el valor original. También puedes encadenar varias columnas, como coalesce(col("telemovel"), col("fixo"), lit("sem contacto")).
Verificar el resultado
Para confirmar que la limpieza salió bien, vuelve a ejecutar el recuento del Paso 2 sobre el DataFrame ya tratado: si todas las columnas muestran 0, no quedan nulos. Como alternativa, prueba una columna concreta con df.filter(col("idade").isNull()).count() y confirma que devuelve 0.
Conclusión
Con na.drop, na.fill y coalesce tienes los tres enfoques fundamentales para tratar valores nulos en PySpark: eliminar las filas, rellenarlas con un valor por defecto o sustituirlas por una columna alternativa. El siguiente paso es elegir la estrategia según la necesidad del negocio — por ejemplo, rellenar la edad con la mediana en lugar de cero, para no sesgar las estadísticas. ¿Cuál de estas tres técnicas tiene más sentido para tu conjunto de datos?