Konversikan kolom menjadi string di Pandas


179

Saya memiliki DataFrame berikut dari kueri SQL:

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

dan saya ingin menggerakkannya seperti ini:

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}

tapi saya ingin memastikan 303 kolom dicor sebagai string, bukan bilangan bulat sehingga saya mendapatkan ini:

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

Dari panda 1.0, dokumentasi merekomendasikan penggunaan astype("string")daripadaastype(str) untuk beberapa alasan yang cukup bagus, lihatlah.
cs95

Jawaban:


333

Salah satu cara untuk mengonversi ke string adalah menggunakan astype :

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

Namun, mungkin Anda mencari to_jsonfungsi tersebut, yang akan mengonversi kunci menjadi json yang valid (dan karenanya kunci Anda menjadi string):

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"}'

Catatan: Anda dapat mengirimkan buffer / file untuk menyimpan ini, bersama dengan beberapa opsi lain ...


3
Saya pikir to_string () lebih disukai karena pelestarian NULLs stackoverflow.com/a/44008334/3647167
Keith

1
Pelestarian @Keith null menarik. tetapi dokumen tersebut mengatakan tujuannya adalah untuk 'Merender DataFrame ke output tabular yang ramah konsol'. Saya ingin seseorang yang berwenang menimbang
3

to_json()mungkin tidak memanggil astype(str)karena meninggalkan datetime64 dan subkelasnya sebagai milidetik sejak zaman.
Sussch

1
@Sussch Saya menduga itu karena json tidak memiliki format datetime yang eksplisit, jadi Anda agak terpaksa menggunakan zaman. Artinya, saya pikir itulah standarnya.
Andy Hayden

50

Jika Anda perlu mengonversi SEMUA kolom menjadi string, Anda cukup menggunakan:

df = df.astype(str)

Ini berguna jika Anda membutuhkan semuanya kecuali beberapa kolom untuk menjadi string / objek, lalu kembali dan ubah yang lain menjadi apa pun yang Anda butuhkan (integer dalam hal ini):

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

28

Ini yang lain, sangat berguna untuk mengonversi banyak kolom menjadi string, bukan hanya satu kolom:

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: Saatnya untuk berhenti menggunakan astype(str)!

Sebelum panda 1.0 (sebenarnya, 0,25 sebenarnya) ini adalah cara defacto untuk mendeklarasikan Seri / kolom sebagai string:

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

Dari panda 1.0 dan seterusnya, pertimbangkan untuk menggunakan "string"tipe .

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

Inilah sebabnya, seperti dikutip oleh dokumen:

  1. Anda dapat secara tidak sengaja menyimpan campuran string dan non-string dalam array objek tipe. Lebih baik memiliki tipe khusus.

  2. objectdtype memecah operasi spesifik seperti dtype DataFrame.select_dtypes(). Tidak ada cara yang jelas untuk memilih hanya teks sambil mengecualikan kolom non-teks tetapi masih objek-dtype.

  3. Saat membaca kode, isi objectarray dtype kurang jelas 'string'.

Lihat juga bagian tentang Perbedaan Perilaku antara "string"danobject .

Jenis ekstensi (diperkenalkan pada 0,24 dan diformalkan dalam 1,0) lebih dekat ke panda daripada numpy, yang baik karena tipe numpy tidak cukup kuat. Misalnya NumPy tidak memiliki cara untuk mewakili data yang hilang dalam data integer (sejak type(NaN) == float). Tetapi panda dapat menggunakan kolom Nullable Integer .


Mengapa saya harus berhenti menggunakannya?

Pencampuran dtypes secara tidak sengaja
Alasan pertama, seperti yang dijelaskan dalam dokumen adalah bahwa Anda dapat secara tidak sengaja menyimpan data non-teks dalam kolom objek.

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

Menantang untuk membedakan string dan objek python
lainnya Contoh contoh nyata lainnya adalah bahwa lebih sulit untuk membedakan antara "string" dan "objek". Objek pada dasarnya adalah tipe selimut untuk semua jenis yang tidak mendukung vectorizable operasi yang dapat di .

Mempertimbangkan,

# 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

Hingga panda 0,25, hampir tidak ada cara untuk membedakan bahwa "A" dan "B" tidak memiliki tipe data yang sama.

# 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

Dari panda 1.0, ini menjadi jauh lebih sederhana:

# 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

Keterbacaan
Ini cukup jelas ;-)


OK, jadi haruskah saya berhenti menggunakannya sekarang?

...Tidak. Pada penulisan jawaban ini (versi 1.1), tidak ada manfaat kinerja tetapi dokumen mengharapkan peningkatan di masa mendatang untuk secara signifikan meningkatkan kinerja dan mengurangi penggunaan memori untuk "string"kolom yang bertentangan dengan objek. Namun demikian, tidak pernah terlalu dini untuk membentuk kebiasaan baik!


-1

Menggunakan .apply()dengan lambdafungsi konversi juga berfungsi dalam hal ini:

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

Untuk seluruh kerangka data yang dapat Anda gunakan .applymap(). (tapi bagaimanapun juga mungkin .astype()lebih cepat)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.