El misterioso NaN
Estás realizando un cálculo importante o cargando un nuevo conjunto de datos. Esperas una salida numérica clara, pero en su lugar, ves NaN . Tus gráficos no funcionan, tu modelo de aprendizaje automático deja de funcionar y tu análisis se detiene por completo. ¿Qué es este valor misterioso y qué significa?
Primero, aclaremos la confusión. Si bien «nan» puede ser un término cariñoso para referirse a una abuela, naan un pan delicioso o Nan una provincia de Tailandia, en el mundo de la informática tiene un significado muy específico e importante. Esta guía te ayudará a comprender NaN en su contexto técnico.
Este artículo explicará NaN en términos sencillos. Exploraremos qué es a nivel básico, las situaciones comunes que lo generan y cómo detectarlo correctamente, lo cual es más complejo de lo que parece. Lo más importante es que aprenderá estrategias prácticas y fiables para manejar NaN en el análisis de datos y el desarrollo de software.
Definir lo que no es un número
En esencia, NaN es un valor especial dentro del tipo de datos numérico. Significa "No es un número" y representa un resultado indefinido o imposible en un cálculo de punto flotante. No es un error que detenga el programa; más bien, es un valor que se propaga silenciosamente a través de los cálculos, lo cual puede ser útil, pero también una posible fuente de errores.
Este concepto proviene del estándar IEEE 754 para aritmética de punto flotante. Este estándar representó un avance significativo en la informática, diseñado para proporcionar al hardware un método consistente y fiable para manejar números reales. Una parte fundamental de este estándar fue la creación de valores especiales para gestionar situaciones inusuales, como la división por cero (que da como resultado infinito) u operaciones no válidas, sin provocar un fallo en el sistema. NaN es la respuesta del estándar a una operación que no produce un resultado numérico matemáticamente significativo.
Para trabajar eficazmente con NaN , debes comprender sus dos reglas importantes:
-
La regla más confusa:
NaNno es igual a nada, ni siquiera a sí mismo. Una comparación comoNaN == NaNsiempre seráfalse. Esto es intencional. SiNaNrepresenta un resultado indefinido (p. ej., el resultado de0/0) y otroNaNrepresenta un resultado indefinido diferente (p. ej.,sqrt(-1), ¿son realmente iguales? El estándar dice que no. Dos valores indefinidos no son necesariamente iguales. -
Regla de propagación: Cualquier operación aritmética que incluya
NaNcomo entrada dará como resultadoNaN. Por ejemplo,5 + NaNesNaN,2 * NaNesNaNymax(10, NaN)esNaN. Esto garantiza que el estado "indefinido" se propague a través de una cadena de cálculos, alertándote al final de que algo falló en algún punto del proceso.
Las 5 principales causas de NaN
Comprender por qué aparece NaN es el primer paso para prevenirlo y solucionarlo. Estos son los cinco escenarios más comunes que observamos en la práctica profesional.
1. Operaciones matemáticas no válidas
Esta es la causa más directa. NaN es el resultado especificado para las operaciones de punto flotante que son matemáticamente imposibles de determinar.
- Dividir cero por cero (
0.0 / 0.0). - Calcular la raíz cuadrada de un número negativo (por ejemplo,
sqrt(-1.0)en sistemas que no admiten números complejos de forma predeterminada). - El logaritmo de un valor negativo o cero (por ejemplo,
log(-10)). - Operaciones que involucran el infinito y que son imposibles de determinar, como
Infinity - InfinityoInfinity / Infinity.
Estas operaciones no tienen como resultado un número real válido, por lo que el sistema devuelve NaN para representar esto.
2. Fallos en el análisis de datos
Cuando intentas convertir un dato en un número, pero el dato no se puede representar numéricamente, el resultado suele ser NaN . Esto es extremadamente común al trabajar con datos del mundo real.
Por ejemplo, intentar convertir una cadena no numérica a un número producirá NaN .
En JavaScript:
let result = parseInt ( "hello world" ); // result is NaN
En Python, este escenario normalmente generaría un ValueError , pero las bibliotecas de análisis de datos lo manejan de manera diferente.
3. Datos faltantes o dañados
Esta es una realidad cotidiana para los analistas y científicos de datos. Al leer datos de una fuente como un archivo CSV, un objeto JSON o una base de datos, las columnas numéricas a menudo contienen valores faltantes. Estos pueden ser celdas vacías o contener texto de marcador de posición como "N/A", "faltante" o simplemente una cadena vacía "" .
Las bibliotecas modernas de análisis de datos, como Pandas en Python, están diseñadas para manejar esto sin problemas. Cuando Pandas carga una columna numérica y encuentra un valor que no puede interpretar como un número, automáticamente representa esa entrada faltante como NaN .
# Imagine a CSV file with an empty value in the 'age' column
# Name,Age
# Alice,30
# Bob,
# Charlie,25
import pandas as pd
importar io
datos_csv = "Nombre,Edad \n Alice,30 \n Bob, \n Charlie,25"
df = pd.read_csv ( io.StringIO ( csv_data ) )
# La 'Edad' de Bob se representará como NaN
imprimir ( df )
# Nombre Edad
# 0 Alicia 30.0
# 1 Bob NaN
# 2 Charlie 25.0
4. Operaciones con variables no definidas
En algunos lenguajes o escenarios menos estrictos, es posible que se realice un cálculo con una variable declarada pero sin asignarle un valor numérico. Si esta variable no inicializada toma un valor predeterminado como undefined en JavaScript, su uso en una operación aritmética puede producir NaN .
let a ; // a is undefined
let b = a + 5 ; // b is now NaN
5. NaN propagado
A menudo, el NaN que aparece en el resultado final no se debe a la última operación. Puede haberse generado mucho antes en una larga secuencia de cálculos. Debido a la regla de propagación ( 5 + NaN es NaN ), un solo valor NaN puede afectar a toda una cadena de cálculos, por lo que resulta crucial rastrear el problema hasta su origen.
Detección fiable de NaN
Dado que my_variable == NaN siempre devuelve falso, es necesario usar funciones específicas del lenguaje para comprobar si existen valores NaN . Usar una comprobación de igualdad directa es un error común entre los desarrolladores que se inician en este concepto.
En Python
Python es el lenguaje común de la ciencia de datos, y su ecosistema cuenta con herramientas sólidas para manejar NaN .
Para un único número de punto flotante, utilice el módulo math .
import math
x = float ( 'nan' )
imprimir ( math.isnan ( x ) ) # Salida: True
y = 5.0
imprimir ( math.isnan ( y ) ) # Salida: Falso
Para los datos almacenados en arrays NumPy, que son la base de la computación numérica en Python, utilice numpy.isnan() . Funciona elemento por elemento en todo el array.
import numpy as np
arr = np . array ([ 1.0 , np . nan , 3.0 ])
print ( np . isnan ( arr )) # Output: [False True False]
Para las Series y DataFrames de Pandas, el método estándar y más común es usar .isna() o su alias ` .isnull() . Estos métodos son esenciales para la limpieza de datos.
import pandas as pd
import numpy as np
df = pd . Marco de datos ({ 'A' : [ 1 , 2 , np . nan ], 'B' : [ 5 , np . nan , np . nan ]})
imprimir ( df . isna ())
# AB
# 0 Falso Falso
# 1 Falso Verdadero
# 2 Verdadero Verdadero
En JavaScript
JavaScript tiene dos funciones para este propósito, y es fundamental comprender la diferencia.
isNaN() es la función global más antigua. Tiene una peculiaridad importante: primero intenta convertir su argumento a un número. Esto da lugar a resultados inesperados.
isNaN ( 'hello' ); // true, because 'hello' coerces to NaN
isNaN ( undefined ); // true, because undefined coerces to NaN
isNaN ( 123 ); // false
esNaN ( NaN ); // verdadero
Number.isNaN() es el método moderno y más seguro introducido en ES6 (ECMAScript 2015). No realiza conversión de tipo. Solo devuelve true si el valor es de tipo `Number` y es NaN . A partir de 2025, esta es la mejor práctica.
Number . isNaN ( 'hello' ); // false, because 'hello' is not a number
Number . isNaN ( undefined ); // false
Número.esNaN ( 123 ) ; // FALSO
Número.esNaN ( NaN ) ; // verdadero
Siempre es preferible usar Number.isNaN() para evitar comportamientos inesperados derivados de la conversión de tipos.
En Java
Java proporciona un método sencillo en sus clases envolventes de punto flotante.
public class NanCheck {
público estático vacío principal ( Cadena [] argumentos ) {
doble d1 = 0.0 / 0.0 ; // Esto es NaN
doble d2 = 5.0 ;
System.out.println ( Double.isNaN ( d1 ) ) ; // Salida: verdadero
System.out.println ( Double.isNaN ( d2 ) ) ; // Salida: falso
flotar f1 = Flotante . NaN ;
System.out.println ( Float.isNaN ( f1 ) ) ; // Salida: verdadero
}
}
En C++
C++ utiliza la biblioteca <cmath> para su comprobación.
#include <iostream>
#include <cmath>
#include <limits>
int main () {
doble d1 = std :: numeric_limits < double >:: quiet_NaN ();
doble d2 = 5.0 ;
si ( std :: isnan ( d1 )) {
std :: cout << "d1 es NaN" << std :: endl ; // Esto se imprimirá
}
si ( ! std :: isnan ( d2 )) {
std :: cout << "d2 no es NaN" << std :: endl ; // Esto se imprimirá
}
devolver 0 ;
}
Estrategias prácticas para NaN
Has encontrado valores NaN en tus datos. ¿Y ahora qué? La estrategia que elijas dependerá totalmente de tu contexto y tus objetivos.
Estrategia 1: Eliminación
La solución más sencilla consiste en eliminar los puntos de datos que contienen NaN . En Pandas, esto se realiza con el método dropna() .
Cuándo usarla: Esta es una opción viable para conjuntos de datos muy grandes donde el número de filas o columnas con NaN es pequeño (por ejemplo, menos del 1-2 % de los datos). En tales casos, es improbable que su eliminación introduzca un sesgo significativo en el análisis.
Cómo hacerlo (Pandas):
import pandas as pd
import numpy as np
df = pd . Marco de datos ({ 'A' : [ 1 , 2 , np . nan , 4 ], 'B' : [ 5 , np . nan , 7 , 8 ]})
# Eliminar cualquier fila que contenga al menos un NaN
df_filas_eliminadas = df.dropna ( )
imprimir ( df_filas_eliminadas )
# AB
# 0 1.0 5.0
# 3 4.0 8.0
# Eliminar cualquier columna que contenga al menos un NaN
df_dropped_cols = df.dropna ( axis = ' columns ' )
imprimir ( df_columnas_eliminadas )
# DataFrame vacío
# Columnas: []
# Índice: [0, 1, 2, 3]
Precaución: Tenga mucho cuidado. Si los datos faltantes no son aleatorios, eliminarlos puede sesgar gravemente sus resultados. Por ejemplo, si los valores NaN para "ingresos" solo aparecen para un grupo demográfico específico, eliminar esas filas lo excluye del análisis.
Estrategia 2: Imputación
La imputación es el proceso de reemplazar los valores NaN con un valor sustituto. Este método suele preferirse porque preserva el tamaño del conjunto de datos, lo cual es fundamental para muchos algoritmos de aprendizaje automático y análisis de series temporales.
Técnicas comunes de imputación:
-
Valor constante: Reemplace
NaNcon 0, -1 u otro valor. Si bien es sencillo, puede distorsionar las propiedades estadísticas de la columna. Por ejemplo, reemplazar las edades faltantes con 0 reduciría drásticamente la edad promedio.
python # Replace all NaNs with 0 df_filled_zero = df.fillna(0) print(df_filled_zero) -
Medidas estadísticas: Reemplace
NaNcon la media, la mediana o la moda de la columna. La media es sensible a los valores atípicos, mientras que la mediana es más robusta. La moda es adecuada para variables categóricas codificadas numéricamente.
python # Replace with the mean of each column df_filled_mean = df.fillna(df.mean()) print(df_filled_mean) -
Relleno hacia adelante/atrás: Esto es ideal para datos ordenados como series temporales.
ffill(relleno hacia adelante) extiende la última observación válida hacia adelante, mientras quebfill(relleno hacia atrás) usa la siguiente observación válida para completar un hueco.
python # Forward-fill df_ffilled = df.fillna(method='ffill') print(df_ffilled)
Estrategia 3: Ignorar
A veces, no es necesario modificar los datos en sí. Basta con realizar un cálculo que sea robusto ante la presencia de NaN . Muchas bibliotecas numéricas ofrecen versiones seguras NaN de funciones comunes.
Cómo hacerlo (NumPy):
La biblioteca NumPy ofrece un conjunto de funciones que calculan resultados ignorando por completo los valores NaN . Esto resulta extremadamente útil para obtener resúmenes estadísticos rápidos.
import numpy as np
arr_with_nan = np . array ([ 1.0 , 2.0 , np . nan , 4.0 ])
# Standard sum and mean are "infected" by NaN
print ( np.sum ( arr_with_nan ) ) # Salida : nan
print ( np.mean ( arr_with_nan ) ) # Salida: nan
# Versiones seguras para NaN
print ( np.nansum ( arr_with_nan ) ) # Salida: 7.0 (1+2+4 )
print ( np.nanmean ( arr_with_nan )) # Salida: 2.333... ((1+2+4)/ 3 )
print ( np.nanmax ( arr_with_nan ) ) # Salida: 4.0
Esta estrategia te permite obtener agregados significativos sin modificar tu conjunto de datos original.
NaN frente a NULL frente a indefinido
Los desarrolladores, especialmente aquellos que trabajan con JavaScript, Python y SQL, suelen confundir NaN con otros valores "vacíos" o "inexistentes". Comprender sus distintos significados es fundamental para escribir código libre de errores.
| Concepto | Idioma(s) | Significado | Ejemplo |
|---|---|---|---|
NaN
|
JavaScript, Python, Java | "No es un número" - Resultado de una operación matemática no válida. Es de tipo numérico. | 0 / 0
|
null
|
JavaScript, Java, SQL | "Ausencia intencional de valor." - Un desarrollador asigna explícitamente esto a una variable para indicar que no tiene valor. | let user = null;
|
None
|
Pitón | En Python, es el equivalente a null . Se trata de un objeto único de tipo NoneType que representa la ausencia de un valor. |
user = None
|
undefined
|
JavaScript | "Valor no asignado." - Se ha declarado una variable pero aún no se le ha asignado un valor. | let name;
|
En resumen: NaN es un valor numérico que indica un error en un problema matemático. null y None son asignaciones explícitas de "nada". undefined es el estado predeterminado de una variable que espera un valor.
Conclusión: Dominar NaN
NaN no es un error que deba temerse, sino un valor definido y especial con reglas específicas. Su comportamiento más inusual —que no es igual a sí mismo— requiere el uso de funciones específicas como math.isnan() o Number.isNaN() para una detección fiable. Una vez detectado, su manejo es una decisión estratégica que depende del objetivo específico: se puede eliminar, reemplazar con otro valor o simplemente usar funciones seguras para NaN para ignorarlo durante los cálculos.
Comprender y dominar el uso NaN es una habilidad fundamental que distingue a los programadores y analistas de datos principiantes de los expertos experimentados. Es la piedra angular para escribir código sólido, resistente y listo para producción, capaz de manejar con eficacia las imperfecciones de los datos del mundo real en 2025 y más allá.
Preguntas frecuentes sobre NaN
P1: ¿Qué significa NaN?
A: NaN significa "No es un número". Es un valor en la aritmética de punto flotante que se utiliza para representar resultados que no están definidos o que no se pueden representar como un número real.
P2: ¿Por qué NaN == NaN devuelve falso?
R: Este comportamiento está especificado en el estándar IEEE 754. NaN representa un valor indefinido. Dado que el resultado de una operación indefinida (como 0/0 ) no es necesariamente el mismo que el de otra (como Infinity - Infinity ), dos valores NaN nunca se consideran iguales. Este diseño evita comparaciones lógicas incorrectas. Utilice siempre una función específica como Number.isNaN() en JavaScript o math.isnan() en Python para comprobarlo.
P3: ¿Debo convertir todos los valores NaN a 0?
R: Depende, pero conviene ser precavido. Si bien es una solución sencilla, reemplazar NaN con 0 puede sesgar significativamente los resultados estadísticos, especialmente la media. Si NaN representa datos de ventas faltantes, convertirlo a 0 implica que no hubo ventas, lo cual podría ser incorrecto. A menudo es mejor considerar el reemplazo con la media o la mediana de la columna, o usar un método que ignore específicamente los valores NaN .
P4: ¿Cómo manejan las bases de datos SQL NaN ?
R: La mayoría de las bases de datos SQL tradicionales (como PostgreSQL, MySQL y SQL Server) no tienen un tipo NaN que se comporte como en los lenguajes de programación. En SQL, el concepto de datos faltantes o desconocidos se maneja con NULL . Cualquier operación aritmética o de comparación que involucre NULL generalmente resulta en NULL , que es conceptualmente similar a la propagación de NaN , pero distinto en su implementación y tipo.