Al crear un nuevo DataFrame en Pandas, si no se indica de forma explícita, el constructor le asignará a cada una de las series el tipo de dato que considere más adecuado. Pudiendo ser diferente al que necesitamos. Especialmente cuando en los datos originales se combinan valores numéricos con cadenas de texto. Para solucionar estos problema y cambiar el tipo de columnas en un DataFrame se puede recurrir al método to_numeric()
.
Texto y valores numéricos en una serie
Cuando se crea un DataFrame en Pandas a partir de un diccionario de listas es posible que nos encontremos con un problema como el siguiente.
import pandas as pd df = pd.DataFrame({'X': [1, '2', 3], 'Y': [4, 5, 6], 'Z': ['7', '8', '9']})
X Y Z 0 1 4 7 1 2 5 8 2 3 6 9
Aparentemente se tiene tres columnas numéricas, pero al consultar el tipo de dato veremos que no es así, solamente la serie Y
es de tipo entero.
df.dtypes
X object Y int64 Z object dtype: object
El resto son objetos. Debido esto al hecho de usar textos en lugar de números para representar valores en estas dos series. Impidiendo llevar a cabo operaciones algebraicas con estas series, apareciendo un error cuando se intenta algo tan sencillo como sumar un número: df.X + 1
.
Cambiar el tipo de columnas con to_numeric
Para solucionar problemas como el visto anteriormente en Pandas se puede utilizar la función to_numeric()
, con la que es posible convertir una serie cualquier en una equivalente de tipo numérica. Así, para convertir la serie X
de nuestro ejemplo solamente se tendría que hacer
pd.to_numeric(df.X)
0 1 1 2 2 3 Name: X, dtype: int64
Con lo que se obtiene una serie equivalente, pero de tipo entero en lugar de objeto. Siendo ya posible realizar operaciones algebraicas sobre ella.
Reducción de los datos
Generalmente el tipo de dato asignado por defecto suele ser adecuado, pero, en algunas ocasiones, puede que nos interese emplear un tipo de dato más pequeño para usar menos memoria. Por ejemplo, los valores usados hasta ahora, entre uno y nueve, se pueden representar mediante un entero de 8 bits. Un tipo de dato con el que se puede guardar 8 enteros en el espacio necesario para por un entero de 64.
La reducción del tipo de dato al más pequeño con el que se pueden representar los datos de la serie se puede forzar mediante la propiedad downcast
. Propiedad que tiene las siguientes opciones:
-
None
: valor por defecto y el tipo no se reduce -
'integer'
: tipo entero con signo más pequeño -
'unsigned'
: tipo entero sin signo más pequeño -
'float'
: tipo real más pequeño
Mediante el siguiente código se puede ver el resultado de aplicar las diferentes opciones en el DataFrame de ejemplo.
df.X = pd.to_numeric(df.X, downcast='float') df.Y = pd.to_numeric(df.Y, downcast='unsigned') df.Z = pd.to_numeric(df.Z, downcast='integer') df.dtypes
X float32 Y uint8 Z int8 dtype: object
Gestionar los errores
En los casos que no es posible convertir el dato original en uno numérico, por ejemplo, cuando uno de los valores es una palabra en lugar de un número. La función to_numeric()
produciría una excepción. Los cuales se pueden gestionar mediante la propiedad errors
de la función. Propiedad que tiene las siguientes opciones:
-
'raise'
: ante una transformación no válida se generará una excepción. -
'coerce'
: los valores que no se pueden transformar producen unNaN
. -
'ignore'
: los valores que no se pueden transformar devuelven el valor original
Así cuando se usa 'coerce'
todos los valores inválidos eran un NaN
.
df = pd.DataFrame({'X': [1, 'pd', 3], 'Y': [4, 5, 6], 'Z': ['7', '8', '9']}) pd.to_numeric(df.X, errors='coerce')
0 1.0 1 NaN 2 3.0 Name: X, dtype: float64
Mientras que en el caso de emplear 'ignore'
los valores volverán tal cual, por lo que la serie resultante seguirá siendo de tipo objeto.
pd.to_numeric(df.X, errors='ignore')
0 1 1 pd 2 3 Name: X, dtype: object
Conclusiones
En esta entrada se ha visto un método mediante el cual se puede cambiar el tipo de columnas en un DataFrame para conseguir tipos numéricos. Lo que permite depurar los datos antes de realizar cualquier análisis. Si necesitamos convertir cadenas de texto en objetos de tipos fecha el método que necesitamos será to_datetime()
.