Cambiar tipo de columna en pandas

Resuelto asked hace 11 años • 16 respuestas

Creé un DataFrame a partir de una lista de listas:

table = [
    ['a',  '1.2',  '4.2' ],
    ['b',  '70',   '0.03'],
    ['x',  '5',    '0'   ],
]

df = pd.DataFrame(table)

¿Cómo convierto las columnas a tipos específicos? En este caso, quiero convertir las columnas 2 y 3 en flotantes.

¿Hay alguna manera de especificar los tipos al convertir la lista a DataFrame? ¿O es mejor crear el DataFrame primero y luego recorrer las columnas para cambiar el tipo de cada columna? Idealmente, me gustaría hacer esto de forma dinámica porque puede haber cientos de columnas y no quiero especificar exactamente qué columnas son de qué tipo. Todo lo que puedo garantizar es que cada columna contiene valores del mismo tipo.

 avatar Apr 09 '13 06:04
Aceptado

Tienes cuatro opciones principales para convertir tipos en pandas:

  1. to_numeric()- proporciona funcionalidad para convertir de forma segura tipos no numéricos (por ejemplo, cadenas) a un tipo numérico adecuado. (Ver también to_datetime()y to_timedelta().)

  2. astype()- convertir (casi) cualquier tipo a (casi) cualquier otro tipo (incluso si no es necesariamente sensato hacerlo). También te permite convertir a tipos categoriales (muy útil).

  3. infer_objects()- un método de utilidad para convertir columnas de objetos que contienen objetos Python a un tipo pandas, si es posible.

  4. convert_dtypes()- convertir columnas de DataFrame al "mejor tipo de formato posible" que admita pd.NA(objeto de pandas para indicar un valor faltante).

Continúe leyendo para obtener explicaciones más detalladas y el uso de cada uno de estos métodos.


1.to_numeric()

La mejor manera de convertir una o más columnas de un DataFrame a valores numéricos es utilizar pandas.to_numeric().

Esta función intentará cambiar objetos no numéricos (como cadenas) a números enteros o de punto flotante, según corresponda.

Uso básico

La entrada to_numeric()es una serie o una sola columna de un DataFrame.

>>> s = pd.Series(["8", 6, "7.5", 3, "0.9"]) # mixed string and numeric values
>>> s
0      8
1      6
2    7.5
3      3
4    0.9
dtype: object

>>> pd.to_numeric(s) # convert everything to float values
0    8.0
1    6.0
2    7.5
3    3.0
4    0.9
dtype: float64

Como puede ver, se devuelve una nueva Serie. Recuerde asignar esta salida a un nombre de variable o columna para continuar usándola:

# convert Series
my_series = pd.to_numeric(my_series)

# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])

También puedes usarlo para convertir múltiples columnas de un DataFrame mediante el apply()método:

# convert all columns of DataFrame
df = df.apply(pd.to_numeric) # convert all columns of DataFrame

# convert just columns "a" and "b"
df[["a", "b"]] = df[["a", "b"]].apply(pd.to_numeric)

Siempre que todos sus valores se puedan convertir, probablemente eso sea todo lo que necesite.

Manejo de errores

Pero ¿qué pasa si algunos valores no se pueden convertir a un tipo numérico?

to_numeric()también toma un errorsargumento de palabra clave que le permite forzar que los valores no numéricos sean NaN, o simplemente ignorar las columnas que contienen estos valores.

A continuación se muestra un ejemplo que utiliza una serie de cadenas sque tiene el tipo de objeto:

>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])
>>> s
0         1
1         2
2       4.7
3    pandas
4        10
dtype: object

El comportamiento predeterminado es aumentar si no puede convertir un valor. En este caso, no puede manejar la cadena 'pandas':

>>> pd.to_numeric(s) # or pd.to_numeric(s, errors='raise')
ValueError: Unable to parse string

En lugar de fallar, es posible que deseemos que 'pandas' se considere un valor numérico faltante o incorrecto. Podemos forzar valores no válidos de NaNla siguiente manera usando el errorsargumento de palabra clave:

>>> pd.to_numeric(s, errors='coerce')
0     1.0
1     2.0
2     4.7
3     NaN
4    10.0
dtype: float64

La tercera opción errorses simplemente ignorar la operación si se encuentra un valor no válido:

>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched

Esta última opción es particularmente útil para convertir todo su DataFrame, pero no sabe cuál de nuestras columnas se puede convertir de manera confiable a un tipo numérico. En ese caso, simplemente escribe:

df.apply(pd.to_numeric, errors='ignore')

La función se aplicará a cada columna del DataFrame. Las columnas que se puedan convertir a un tipo numérico se convertirán, mientras que las columnas que no se puedan convertir (por ejemplo, que contengan cadenas sin dígitos o fechas) se dejarán como están.

abatido

De forma predeterminada, la conversión con to_numeric()le dará un tipo int64o float64d (o cualquier ancho entero que sea nativo de su plataforma).

Normalmente eso es lo que quieres, pero ¿qué pasaría si quisieras ahorrar algo de memoria y usar un tipo de letra más compacto, como float32o int8?

to_numeric()le da la opción de abatir a 'integer', 'signed', 'unsigned', 'float'. A continuación se muestra un ejemplo de una serie simple sde tipo entero:

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Downcasting 'integer'utiliza el entero más pequeño posible que puede contener los valores:

>>> pd.to_numeric(s, downcast='integer')
0    1
1    2
2   -7
dtype: int8

Downcasting para 'float'elegir de manera similar un tipo flotante más pequeño de lo normal:

>>> pd.to_numeric(s, downcast='float')
0    1.0
1    2.0
2   -7.0
dtype: float32

2.astype()

El astype()método le permite ser explícito sobre el tipo de datos que desea que tenga su DataFrame o Serie. Es muy versátil porque puedes probar y pasar de un tipo a otro.

Uso básico

Simplemente elija un tipo: puede usar un tipo de NumPy (p. ej. np.int16), algunos tipos de Python (p. ej., bool) o tipos específicos de pandas (como el tipo de d categórico).

Llame al método en el objeto que desea convertir e astype()intentará convertirlo por usted:

# convert all DataFrame columns to the int64 dtype
df = df.astype(int)

# convert column "a" to int64 dtype and "b" to complex type
df = df.astype({"a": int, "b": complex})

# convert Series to float16 type
s = s.astype(np.float16)

# convert Series to Python strings
s = s.astype(str)

# convert Series to categorical type - see docs for more details
s = s.astype('category')

Observe que dije "intentar": si astype()no sabe cómo convertir un valor en la serie o el marco de datos, generará un error. Por ejemplo, si tiene un valor NaNo infobtendrá un error al intentar convertirlo a un número entero.

A partir de pandas 0.20.0, este error se puede suprimir pasando errors='ignore'. Su objeto original será devuelto intacto.

Ten cuidado

astype()es potente, pero a veces convierte valores "incorrectamente". Por ejemplo:

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Estos son números enteros pequeños, entonces, ¿qué tal si los convertimos a un tipo de 8 bits sin signo para ahorrar memoria?

>>> s.astype(np.uint8)
0      1
1      2
2    249
dtype: uint8

¡La conversión funcionó, pero el -7 se transformó en 249 (es decir, 2 8 - 7)!

Intentar abatir usando pd.to_numeric(s, downcast='unsigned')en su lugar podría ayudar a prevenir este error.


3.infer_objects()

La versión 0.21.0 de pandas introdujo el método infer_objects()para convertir columnas de un DataFrame que tienen un tipo de datos de objeto a un tipo más específico (conversiones suaves).

Por ejemplo, aquí hay un DataFrame con dos columnas de tipo de objeto. Uno contiene números enteros reales y el otro contiene cadenas que representan números enteros:

>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a    object
b    object
dtype: object

Usando infer_objects(), puedes cambiar el tipo de columna 'a' a int64:

>>> df = df.infer_objects()
>>> df.dtypes
a     int64
b    object
dtype: object

La columna 'b' se ha dejado sola ya que sus valores eran cadenas, no números enteros. Si quisiera forzar ambas columnas a un tipo de número entero, podría usarlas df.astype(int)en su lugar.


4.convert_dtypes()

La versión 1.0 y superiores incluyen un método convert_dtypes()para convertir columnas Series y DataFrame al mejor tipo de formato posible que admita el pd.NAvalor faltante.

Aquí "mejor posible" significa el tipo más adecuado para contener los valores. Por ejemplo, este es un tipo entero de pandas, si todos los valores son enteros (o valores faltantes): una columna de objeto de objetos enteros de Python se convierte en Int64, una columna de valores NumPy int32, se convertirá en el tipo de pandas Int32.

Con nuestro objectDataFrame df, obtenemos el siguiente resultado:

>>> df.convert_dtypes().dtypes                                             
a     Int64
b    string
dtype: object

Dado que la columna 'a' contenía valores enteros, se convirtió al Int64tipo (que es capaz de contener valores faltantes, a diferencia de int64).

La columna 'b' contenía objetos de cadena, por lo que se cambió al stringtipo de pandas.

De forma predeterminada, este método inferirá el tipo a partir de los valores del objeto en cada columna. Podemos cambiar esto pasando infer_objects=False:

>>> df.convert_dtypes(infer_objects=False).dtypes                          
a    object
b    string
dtype: object

Ahora la columna 'a' sigue siendo una columna de objeto: pandas sabe que puede describirse como una columna 'entera' (internamente se ejecutó infer_dtype) pero no infirió exactamente qué tipo de entero debería tener, por lo que no la convirtió. La columna 'b' se convirtió nuevamente al tipo d 'cadena' ya que se reconoció que contenía valores de 'cadena'.

Alex Riley avatar Feb 21 '2015 17:02 Alex Riley

Utilizar esta:

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])
df

Out[16]:
  one  two three
0   a  1.2   4.2
1   b   70  0.03
2   x    5     0

df.dtypes

Out[17]:
one      object
two      object
three    object

df[['two', 'three']] = df[['two', 'three']].astype(float)

df.dtypes

Out[19]:
one       object
two      float64
three    float64
hernamesbarbara avatar Apr 21 '2013 18:04 hernamesbarbara

El siguiente código cambiará el tipo de datos de una columna.

df[['col.name1', 'col.name2'...]] = df[['col.name1', 'col.name2'..]].astype('data_type')

En lugar del tipo de datos, puede darle al tipo de datos lo que desee, como str, float, int, etc.

Akash Nayak avatar Nov 15 '2017 09:11 Akash Nayak

Cuando solo necesitaba especificar columnas específicas y quiero ser explícito, utilicé (según pandas.DataFrame.astype ):

dataframe = dataframe.astype({'col_name_1':'int','col_name_2':'float64', etc. ...})

Entonces, usando la pregunta original, pero proporcionándole nombres de columnas...

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col_name_1', 'col_name_2', 'col_name_3'])
df = df.astype({'col_name_2':'float64', 'col_name_3':'float64'})
Thom Ives avatar Oct 12 '2018 21:10 Thom Ives