Convertir columnas a cadenas en pandas

179

Tengo el siguiente DataFrame de una consulta SQL:

(Pdb) pp total_rows
     ColumnID  RespondentCount
0          -1                2
1  3030096843                1
2  3030096845                1

y quiero pivotarlo así:

total_data = total_rows.pivot_table(cols=['ColumnID'])

(Pdb) pp total_data
ColumnID         -1            3030096843   3030096845
RespondentCount            2            1            1

[1 rows x 3 columns]


total_rows.pivot_table(cols=['ColumnID']).to_dict('records')[0]

{3030096843: 1, 3030096845: 1, -1: 2}

pero quiero asegurarme de que las 303 columnas se conviertan en cadenas en lugar de enteros para que obtenga esto:

{'3030096843': 1, '3030096845': 1, -1: 2}
sontek
fuente
De pandas 1.0, la documentación recomienda usar en astype("string")lugar deastype(str) por muy buenas razones, eche un vistazo.
cs95 hace

Respuestas:

333

Una forma de convertir a cadena es usar un tipo :

total_rows['ColumnID'] = total_rows['ColumnID'].astype(str)

Sin embargo, quizás esté buscando la to_jsonfunción, que convertirá las claves en json válidas (y, por lo tanto, sus claves en cadenas):

In [11]: df = pd.DataFrame([['A', 2], ['A', 4], ['B', 6]])

In [12]: df.to_json()
Out[12]: '{"0":{"0":"A","1":"A","2":"B"},"1":{"0":2,"1":4,"2":6}}'

In [13]: df[0].to_json()
Out[13]: '{"0":"A","1":"A","2":"B"}'

Nota: puede pasar un búfer / archivo para guardar esto, junto con algunas otras opciones ...

Andy Hayden
fuente
3
Creo que to_string () es preferible debido a la preservación de los NULL stackoverflow.com/a/44008334/3647167
Keith
1
La conservación nula de @Keith es atractiva. pero el documento dice que su propósito es 'Renderizar un DataFrame a una salida tabular amigable para la consola'. Me gustaría que alguien con autoridad pesara
3pitt
to_json()probablemente no llame astype(str)ya que deja datetime64 y sus subclases en milisegundos desde la época.
Sussch
1
@Sussch Sospecho que es porque json no tiene un formato de fecha y hora explícito, por lo que estás obligado a usar epoch. Es decir, creo que ese es el estándar.
Andy Hayden
50

Si necesita convertir TODAS las columnas en cadenas, simplemente puede usar:

df = df.astype(str)

Esto es útil si necesita todo excepto algunas columnas para ser cadenas / objetos, luego regrese y convierta las otras a lo que necesite (entero en este caso):

 df[["D", "E"]] = df[["D", "E"]].astype(int) 
Miguel
fuente
28

Aquí está el otro, particularmente útil para convertir las múltiples columnas en cadenas en lugar de solo una columna:

In [76]: import numpy as np
In [77]: import pandas as pd
In [78]: df = pd.DataFrame({
    ...:     'A': [20, 30.0, np.nan],
    ...:     'B': ["a45a", "a3", "b1"],
    ...:     'C': [10, 5, np.nan]})
    ...: 

In [79]: df.dtypes ## Current datatype
Out[79]: 
A    float64
B     object
C    float64
dtype: object

## Multiple columns string conversion
In [80]: df[["A", "C"]] = df[["A", "C"]].astype(str) 

In [81]: df.dtypes ## Updated datatype after string conversion
Out[81]: 
A    object
B    object
C    object
dtype: object
Surya
fuente
3

Utilice .astype (str)

Ex:

Let d be the Pandas DataFrame

d['Column_name'].astype(str)

Kranthi Kumar Valaboju
fuente
0

pandas> = 1.0: ¡ Es hora de dejar de usar astype(str)!

Antes de los pandas 1.0 (bueno, 0.25 en realidad) esta era la forma de facto de declarar una Serie / columna como una cadena:

# pandas <= 0.25
# Note to pedants: specifying the type is unnecessary since pandas will 
# automagically infer the type as object
s = pd.Series(['a', 'b', 'c'], dtype=str)
s.dtype
# dtype('O')

Desde pandas 1.0 en adelante, considere usar el "string"tipo en su lugar.

# pandas >= 1.0
s = pd.Series(['a', 'b', 'c'], dtype="string")
s.dtype
# StringDtype

He aquí por qué, como lo citan los documentos:

  1. Puede almacenar accidentalmente una mezcla de cadenas y no cadenas en una matriz dtype de objeto. Es mejor tener un tipo dedicado.

  2. objectdtype rompe operaciones específicas de dtype como DataFrame.select_dtypes(). No hay una manera clara de seleccionar solo texto mientras se excluyen las columnas que no son de texto pero que siguen siendo de tipo objeto

  3. Al leer el código, el contenido de una objectmatriz dtype es menos claro que 'string'.

Consulte también la sección sobre Diferencias de comportamiento entre "string"yobject .

Los tipos de extensión (introducidos en 0.24 y formalizados en 1.0) están más cerca de los pandas que numpy, lo cual es bueno porque los tipos de numpy no son lo suficientemente potentes. Por ejemplo, NumPy no tiene ninguna forma de representar datos faltantes en datos enteros (desde type(NaN) == float). Pero los pandas pueden usar columnas de enteros anulables .


¿Por qué debería dejar de usarlo?

Mezcla accidental de dtypes
La primera razón, como se describe en los documentos, es que puede almacenar accidentalmente datos que no son de texto en columnas de objetos.

# pandas <= 0.25
pd.Series(['a', 'b', 1.23])   # whoops, this should have been "1.23"

0       a
1       b
2    1.23
dtype: object

pd.Series(['a', 'b', 1.23]).tolist()
# ['a', 'b', 1.23]   # oops, pandas was storing this as float all the time.
# pandas >= 1.0
pd.Series(['a', 'b', 1.23], dtype="string")

0       a
1       b
2    1.23
dtype: string

pd.Series(['a', 'b', 1.23], dtype="string").tolist()
# ['a', 'b', '1.23']   # it's a string and we just averted some potentially nasty bugs.

Desafiando diferenciar cadenas y otros objetos de python
Otro ejemplo de ejemplo obvio es que es más difícil distinguir entre "cadenas" y "objetos". Los objetos son esencialmente el tipo de cobertura para cualquier tipo que no admite operaciones vectorizables .

Considerar,

# Setup
df = pd.DataFrame({'A': ['a', 'b', 'c'], 'B': [{}, [1, 2, 3], 123]})
df
 
   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

Hasta los pandas 0.25, prácticamente no había forma de distinguir que "A" y "B" no tienen el mismo tipo de datos.

# pandas <= 0.25  
df.dtypes

A    object
B    object
dtype: object

df.select_dtypes(object)

   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

De pandas 1.0, esto se vuelve mucho más simple:

# pandas >= 1.0
# Convenience function I call to help illustrate my point.
df = df.convert_dtypes()
df.dtypes

A    string
B    object
dtype: object

df.select_dtypes("string")

   A
0  a
1  b
2  c

Legibilidad
Esto se explica por sí mismo ;-)


OK, ¿debería dejar de usarlo ahora?

...No. Al momento de escribir esta respuesta (versión 1.1), no hay beneficios de rendimiento, pero los documentos esperan que las mejoras futuras mejoren significativamente el rendimiento y reduzcan el uso de memoria para las "string"columnas en lugar de los objetos. Dicho esto, sin embargo, ¡nunca es demasiado temprano para formar buenos hábitos!

cs95
fuente
-1

Usar .apply()con una lambdafunción de conversión también funciona en este caso:

total_rows['ColumnID'] = total_rows['ColumnID'].apply(lambda x: str(x))

Para marcos de datos completos que puede usar .applymap(). (pero en cualquier caso probablemente .astype()sea ​​más rápido)

dbouz
fuente