Pandalar'da sütunları dizeye dönüştür


180

Bir SQL sorgusu aşağıdaki DataFrame var:

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

ve bunu şöyle döndürmek istiyorum:

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}

ama ben bunu elde böylece 303 sütun tamsayılar yerine dizeler olarak döküm emin olmak istiyorum:

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

Pandalar 1.0'dan, belgelerastype("string")astype(str) oldukça iyi nedenler yerine kullanılmasını önerir , bir göz atın.
cs95

Yanıtlar:


333

Dizeye dönüştürmenin bir yolu astype kullanmaktır :

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

Ancak, belki de to_jsonanahtarları geçerli json'a (ve dolayısıyla anahtarlarınızı dizelere dönüştürecek) işlevi arıyorsunuz :

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

Not: Diğer bazı seçeneklerle birlikte bunu kaydetmek için bir arabellek / dosya iletebilirsiniz ...


3
Sanırım to_string (), NULL'ların korunması nedeniyle tercih edilebilir stackoverflow.com/a/44008334/3647167
Keith

1
@Keith null koruma caziptir. ancak doküman amacının 'Konsol dostu bir tablo çıktısına bir DataFrame Oluşturmak' olduğunu söylüyor. tartmak için yetkili biri istiyorum
3pitt 21:18

to_json()muhtemelen astype(str)datetime64 ve alt sınıflarını çağdan beri milisaniye olarak bıraktığı için çağrılamaz .
Sussch

1
@Sussch Bunun nedeni json'un açık bir datetime formatına sahip olmaması, bu yüzden çığır açmak zorundasınız. Yani standart olduğunu düşünüyorum.
Andy Hayden

50

TÜM sütunları dizelere dönüştürmeniz gerekiyorsa, şunları kullanabilirsiniz:

df = df.astype(str)

Dizeler / nesneler olmak için birkaç sütun dışında her şeye ihtiyacınız varsa, geri dönün ve diğerlerini ihtiyacınız olana dönüştürün (bu durumda tamsayı):

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

28

İşte diğeri, özellikle birden çok sütunu tek bir sütun yerine dizeye dönüştürmek için yararlı :

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

pandalar> = 1.0: Kullanmayı bırakmanın zamanı geldi astype(str)!

Panda 1.0'dan önce (aslında, aslında 0.25), bir Diziyi / sütunu dize olarak bildirmenin kesin yoluydu:

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

Panda 1.0'dan itibaren, bunun yerine "string"türü kullanmayı düşünün .

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

Dokümanlar tarafından alıntılandığı gibi, bunun nedeni şudur:

  1. Yanlışlıkla bir dize ve dize olmayan karışımı bir nesne dtype dizisinde saklayabilirsiniz. Özel bir dtype sahip olmak daha iyidir.

  2. objectdtype gibi dtype'ye özgü işlemleri keser DataFrame.select_dtypes(). Metin olmayan, ancak yine de nesne dtype sütunlarını hariç tutarken yalnızca metni seçmenin net bir yolu yoktur.

  3. Kodu okurken, objectdtype dizisinin içeriği daha az açıktır 'string'.

Ayrıca bölümüne bakın arasındaki Davranış Farklılıkları "string"veobject .

Genişletme türleri (0.24'te tanıtılan ve 1.0'da resmileştirilen), sayısal değerlere göre pandalara daha yakındır, bu da iyidir, çünkü numpy türleri yeterince güçlü değildir. Örneğin, NumPy'nin tamsayı verilerinde eksik verileri temsil etmenin bir yolu yoktur (o zamandan beri type(NaN) == float). Ancak pandalar Nullable Integer sütunlarını kullanabilir .


Neden kullanmayı bırakmalıyım?

Türleri yanlışlıkla karıştırma
Dokümanlarda belirtildiği gibi ilk neden, metin dışı verileri yanlışlıkla nesne sütunlarında depolayabilmenizdir.

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

Dizeleri ve diğer python nesnelerini
ayırt etmek zor. Bir diğer bariz örnek, "dizeler" ve "nesneler" arasında ayrım yapmanın daha zor olmasıdır. Nesneler, vektörleştirilebilirliği desteklemeyen herhangi bir tür için temelde battaniye türüdür işlemleri .

Düşünmek,

# 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

Pandalar 0.25'e kadar, "A" ve "B" nin aynı tipte verilere sahip olmadığını ayırt etmenin neredeyse hiçbir yolu yoktu.

# 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

Pandalar 1.0'dan, bu çok daha basit hale gelir:

# 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

Okunabilirlik
Bu açıklayıcıdır ;-)


Tamam, şimdi kullanmayı bırakmalı mıyım?

...Hayır. Bu yanıtı yazdığınızda (sürüm 1.1), hiçbir performans avantajı yoktur ancak dokümanlar gelecekteki geliştirmelerin "string"nesneleri önemli ölçüde iyileştirmesini ve sütunların nesnelerin aksine sütun kullanımını azaltmasını bekler . Bununla birlikte, iyi alışkanlıklar oluşturmak için asla çok erken değildir!


-1

.apply()Bir lambdadönüşüm işleviyle birlikte kullanmak da bu durumda çalışır:

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

Tüm veri çerçeveleri için kullanabilirsiniz .applymap(). (ancak her durumda muhtemelen .astype()daha hızlıdır)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.