Converti le colonne in stringhe in Panda


179

Ho il seguente DataFrame da una query SQL:

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

e voglio ruotarlo in questo modo:

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}

ma voglio assicurarmi che le colonne 303 siano espresse come stringhe anziché come numeri interi in modo da ottenere questo:

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

Da Panda 1.0, la documentazione consiglia di utilizzare astype("string")invece cheastype(str) per alcuni buoni motivi, dai un'occhiata.
cs95

Risposte:


333

Un modo per convertire in stringa è usare astype :

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

Tuttavia, forse stai cercando la to_jsonfunzione, che convertirà le chiavi in ​​json valido (e quindi le tue chiavi in ​​stringhe):

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: è possibile passare un buffer / file in cui salvarlo, insieme ad alcune altre opzioni ...


3
Penso che to_string () sia preferibile a causa della conservazione dei NULL stackoverflow.com/a/44008334/3647167
Keith

1
La conservazione nulla di @Keith è interessante. ma il documento afferma che il suo scopo è "Rendering di un DataFrame su un output tabulare compatibile con la console". Vorrei che qualcuno autorevole pesasse
3pitt

to_json()probabilmente non chiama astype(str)in quanto lascia datetime64 e le sue sottoclassi come millisecondi dall'epoca.
Sussch,

1
@Sussch Sospetto che sia perché Json non ha un formato datetime esplicito, quindi sei un po 'costretto a usare l'epoca. Vale a dire, penso che sia lo standard.
Andy Hayden,

50

Se devi convertire TUTTE le colonne in stringhe, puoi semplicemente usare:

df = df.astype(str)

Questo è utile se hai bisogno di tutto tranne alcune colonne per essere stringhe / oggetti, quindi torna indietro e converti gli altri in qualsiasi cosa tu abbia bisogno (numero intero in questo caso):

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

28

Ecco l'altro, particolarmente utile per convertire più colonne in stringa anziché in un'unica colonna:

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


0

panda> = 1.0: è tempo di smettere di usare astype(str)!

Prima di Panda 1.0 (bene, 0,25 in realtà) questo era il modo defacto di dichiarare una Serie / colonna come stringa:

# 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')

Da Panda 1.0 in poi, considera invece l' uso di "string"type .

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

Ecco perché, come citato dai documenti:

  1. È possibile memorizzare accidentalmente una combinazione di stringhe e non stringhe in un array di tipi di oggetto. È meglio avere un dtype dedicato.

  2. objectdtype interrompe operazioni specifiche del dtype come DataFrame.select_dtypes(). Non esiste un modo chiaro per selezionare solo il testo escludendo le colonne non di testo ma ancora di tipo oggetto.

  3. Durante la lettura del codice, il contenuto di un objectarray dtype è meno chiaro di 'string'.

Vedi anche la sezione sulle differenze comportamentali tra "string"eobject .

I tipi di estensione (introdotti in 0.24 e formalizzati in 1.0) sono più vicini ai panda che al numpy, il che è positivo perché i tipi numpy non sono abbastanza potenti. Ad esempio NumPy non ha alcun modo di rappresentare i dati mancanti in dati interi (poiché type(NaN) == float). Ma i panda possono usare le colonne Nullable Integer .


Perché dovrei smettere di usarlo?

Miscelazione accidentale di tipi di dati
Il primo motivo, come indicato nei documenti, è che è possibile archiviare accidentalmente dati non testuali nelle colonne degli oggetti.

# 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.

Sfidare a differenziare stringhe e altri oggetti in pitone
Un altro esempio ovvio è che è più difficile distinguere tra "stringhe" e "oggetti". Gli oggetti sono essenzialmente il tipo di coperta per qualsiasi tipo che non supporta operazioni vettorializzabili .

Tener conto di,

# 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

Fino ai panda 0.25, praticamente non c'era modo di distinguere che "A" e "B" non hanno lo stesso tipo di dati.

# 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

Da Panda 1.0, questo diventa molto più semplice:

# 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

Leggibilità
Si spiega da sé ;-)


OK, quindi dovrei smettere di usarlo adesso?

...No. Al momento della stesura di questa risposta (versione 1.1), non ci sono vantaggi in termini di prestazioni, ma i documenti prevedono miglioramenti futuri per migliorare significativamente le prestazioni e ridurre l'utilizzo della memoria per le "string"colonne rispetto agli oggetti. Detto questo, tuttavia, non è mai troppo presto per formare buone abitudini!


-1

L'utilizzo .apply()con una lambdafunzione di conversione funziona anche in questo caso:

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

Per interi frame di dati è possibile utilizzare .applymap(). (ma in ogni caso probabilmente .astype()è più veloce)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.