Pandalar'daki sütunların veri türünü değiştirme


804

Liste listesi olarak temsil edilen bir tabloyu a dönüştürmek istiyorum Pandas DataFrame. Son derece basitleştirilmiş bir örnek olarak:

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

Sütunları uygun türlere, bu durumda 2 ve 3 sütunlarını kayan noktaya dönüştürmenin en iyi yolu nedir? DataFrame'e dönüştürürken türleri belirtmenin bir yolu var mı? Yoksa önce DataFrame oluşturmak ve sonra her bir sütunun türünü değiştirmek için sütunlar arasında geçiş yapmak daha mı iyi? İdeal olarak bunu dinamik bir şekilde yapmak istiyorum çünkü yüzlerce sütun olabilir ve tam olarak hangi sütunların hangi tipte olduğunu belirtmek istemiyorum. Garanti edebileceğim tek şey, her bir sütunun aynı türde değerler içermesidir.


Her sütunu dönüştürmek için yaklaşımlar gördüm ve özellikle adlandırılmış sütunları dönüştürmek için yaklaşımlar gördüm, ancak bir kerede dönüştürmek istediğiniz 100 sütunu listeleyemediğinizde belirli bir koşulu karşılayan belirli sütunlara ne dersiniz? Örneğin tüm float64 -> float32 veya diğer bellek tasarrufu taktiklerini düşünüyorum.
demongolem

@demongolem: df.apply(pd.to_numeric, downcast="integer", errors="ignore")tamsayı sütunlarını değerleri tutacak en küçük (tamsayı) türüne sürmek gibi bir şey yapabilirsiniz .
Alex Riley

Yanıtlar:


1190

Pandalarda türleri dönüştürmek için üç ana seçeneğiniz vardır:

  1. to_numeric()- sayısal olmayan türleri (ör. dizeler) uygun bir sayısal türe güvenli bir şekilde dönüştürmek için işlevsellik sağlar. (Ayrıca bkz . to_datetime()Ve to_timedelta().)

  2. astype()- herhangi bir türü (neredeyse) başka herhangi bir türe dönüştürmek (neredeyse mantıklı olmasa bile). Ayrıca kategorik türlere dönüştürmenize izin verir (çok yararlı).

  3. infer_objects() - mümkünse Python nesnelerini tutan nesne sütunlarını panda türüne dönüştürmek için bir yardımcı yöntem.

Bu yöntemlerin her birinin daha ayrıntılı açıklaması ve kullanımı için okumaya devam edin.


1. to_numeric()

Bir DataFrame sütununun bir veya daha fazla sütununu sayısal değerlere dönüştürmenin en iyi yolu kullanmaktır pandas.to_numeric().

Bu işlev, sayısal olmayan nesneleri (dizeler gibi) tamsayılara veya kayan nokta sayılarına uygun şekilde değiştirmeye çalışır.

Temel kullanım

Girilen girdi to_numeric()bir Seri veya DataFrame öğesinin tek sütunudur.

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

Gördüğünüz gibi yeni bir Seri geri döndü. Bu çıktıyı kullanmaya devam etmek için bir değişkene veya sütun adına atamayı unutmayın:

# convert Series
my_series = pd.to_numeric(my_series)

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

Bu apply()yöntemi kullanarak bir DataFrame öğesinin birden çok sütununu dönüştürmek için de kullanabilirsiniz :

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

Değerlerinizin tümü dönüştürülebildiği sürece, muhtemelen ihtiyacınız olan şey budur.

Hata yönetimi

Ancak, bazı değerler sayısal bir türe dönüştürülemezse ne olur?

to_numeric()ayrıca errorssayısal olmayan değerlerin zorlanmasını NaNveya yalnızca bu değerleri içeren sütunları yok saymanızı sağlayan bir anahtar kelime bağımsız değişkeni de alır .

İşte sdtype nesnesine sahip bir dizi Dizeyi kullanan bir örnek :

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

Varsayılan davranış, bir değeri dönüştüremezse yükseltmektir. Bu durumda, 'pandalar' dizesiyle baş edemez:

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

Başarısız olmak yerine, 'pandaların' eksik / hatalı sayısal değer olarak kabul edilmesini isteyebiliriz. Anahtar kelime bağımsız değişkenini NaNkullanarak geçersiz değerleri aşağıdaki gibi zorlayabiliriz errors:

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

Üçüncü seçenek errors, geçersiz bir değerle karşılaşıldığında işlemi yoksaymaktır:

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

Bu son seçenek özellikle tüm DataFrame'inizi dönüştürmek istediğinizde yararlıdır, ancak hangi sütunlarımızın güvenilir bir şekilde sayısal bir türe dönüştürülebileceğini bilmiyorum. Bu durumda şunu yazın:

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

İşlev, DataFrame öğesinin her sütununa uygulanır. Sayısal bir türe dönüştürülebilen sütunlar dönüştürülürken (örneğin, rakam olmayan dizeler veya tarihler içerir) sütunlar tek başına bırakılır.

downcasting

Varsayılan olarak, ile dönüşüm to_numeric()size bir int64veyafloat64 dtype (veya platformunuz için yerel olan tamsayı genişliği) verir.

Genellikle istediğiniz şey budur, ancak ya biraz bellek kaydetmek ve daha kompakt bir tür kullanmak isterseniz float32, ya da int8?

to_numeric()size 'tamsayı', 'imzalı', 'imzasız', 'kayan' öğelerine yer değiştirme seçeneği sunar. Basit bir stamsayı serisi serisine örnek :

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

'İnteger' değerine küçültme değerleri tutabilen mümkün olan en küçük tamsayıyı kullanır:

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

'Şamandıra' için alt çizgi aynı şekilde normal yüzer tipten daha küçük alır:

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

2. astype()

astype()Yöntem size DataFrame veya Serisi istiyorum d_type hakkında açık olmasını sağlar. Bir türden diğerine geçmeyi denemeniz çok yönlüdür.

Temel kullanım

Sadece bir tür seçin: NumPy dtype (ör. np.int16 ), Bazı Python türleri (örneğin bool) veya pandalara özgü türler (kategorik dtype gibi) kullanabilirsiniz.

Dönüştürmek istediğiniz nesnenin yöntemini çağırın ve sizin için dönüştürmeye astype()çalışın:

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

"Denemek" dedim - astype()Seri veya DataFrame bir değeri nasıl dönüştürüleceğini bilmiyorsanız, bir hata ortaya çıkarır. Örneğin, bir NaNveyainf değeriniz varsa, bunu bir tamsayıya dönüştürmeye çalışırken bir hata alırsınız.

Pandalar 0.20.0'dan itibaren, bu hata iletilerek bastırılabilir errors='ignore' . Orijinal nesnenize dokunulmaz.

Dikkatli ol

astype()güçlüdür, ancak bazen değerleri "yanlış" dönüştürür. Örneğin:

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

Bunlar küçük tamsayılardır, bu yüzden bellek tasarrufu yapmak için işaretsiz bir 8 bit tipine dönüştürmeye ne dersiniz?

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

Dönüştürme işe yaradı, ancak -7 249 olacak şekilde sarıldı (yani 2 8 - 7)!

pd.to_numeric(s, downcast='unsigned')Bunun yerine kullanarak indirmeye çalışmak bu hatayı önlemeye yardımcı olabilir.


3. infer_objects()

Pandaların 0.21.0 sürümü infer_objects(), bir nesne veri tipine sahip bir DataFrame sütunlarını daha spesifik bir türe (yumuşak dönüşümler) dönüştürmek için bir yöntem getirmiştir.

Örneğin, iki nesne türü sütununa sahip bir DataFrame. Biri gerçek tamsayıları, diğeri tamsayıları temsil eden dizeleri tutar:

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

Kullanarak infer_objects(), 'a' sütununun türünü int64 olarak değiştirebilirsiniz:

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

'B' sütunu, değerleri tamsayı değil dize olduğundan tek başına bırakılmıştır. Her iki sütunun bir tamsayı türüne dönüştürülmesini denemek ve zorlamak istiyorsanız, df.astype(int)bunun yerine kullanabilirsiniz .


8
Ayrıca, .astype (float) 'dan farklı olarak, bir hatayı yükseltmek yerine dizeleri NaN'lere dönüştürür
Rob

11
.convert_objectso zamandan beri 0.17kullanımdan kaldırılıyor - df.to_numericbunun yerine kullan
Matti Lyra

4
Teşekkürler - Bu cevabı güncellemeliyim. Belki de belirtmek gerekir pd.to_numericve yardımcı yöntemleri, aksine, bir kerede yalnızca bir sütun üzerinde çalışacaktır convert_objects. API'deki bir değiştirme işlevi hakkında tartışma devam etmektedir ; Umarım çok yararlı olduğu için tüm DataFrame üzerinde çalışan bir yöntem kalır.
Alex Riley

Eğer şu anda diyelim ki tüm sütunları dönüştürmek en iyi yolu nedir int64için int32?
RoyalTS

4
@RoyalTS: muhtemelen en iyisi astype(diğer cevapta olduğu gibi), yani .astype(numpy.int32).
Alex Riley

447

Buna ne dersin?

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

10
Evet! aradığınız w / yapmanıza izin verebilecek pd.DataFramebir dtypeargüman var. df = pd.DataFrame (a, sütunlar = ['bir', 'iki', 'üç'], dtype = float) [2] 'de: df.dtypes Out [2]: bir nesne iki float64 üç float64 dtype: nesne
hernamesbarbara

17
Önerildiği gibi çalıştığımda bir uyarı alıyorum SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_index,col_indexer] = value instead. Bu pandaların daha yeni bir versiyonunda tanıtılmış olabilir ve sonuç olarak yanlış bir şey görmüyorum, ama sadece bu uyarının ne hakkında olduğunu merak ediyorum. Herhangi bir fikir?
turuncu

2
@orange uyarısı, kullanıcıları zincirleme işlemlerle ve pandaların veri çerçevelerini düzenlemek yerine kopyalarını döndüren potansiyel olarak kafa karıştırıcı davranışa karşı uyarmaktır. bkz. stackoverflow.com/questions/20625582/… ve ilgili.
A.

19
Bu iyi bir yöntem, ancak bir sütunda NaN olduğunda işe yaramaz. Int için şamandıra döküm NaN neden sadece NaN kalamıyorum hakkında hiçbir fikrim yok:ValueError: Cannot convert NA to integer
Vitaly Isaev

7
@GillBates evet, sözlükte. df = pd.DataFrame(a, columns=['one', 'two', 'three'], dtype={'one': str, 'two': int, 'three': float}). Gerçi kabul edilen "dtype" değerleri için şartname bulmakta zorlanıyorum. Bir liste güzel olurdu (şu anda yapıyorum dict(enumerate(my_list))).
FichteFoll

39

Aşağıdaki kod, sütunun veri türünü değiştirecektir.

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

veri türü yerine veri türünüzü verebilirsiniz. str, float, int vb.


Bunu, data_type kullanarak `` `` True '' `` ve `` `` False '' `dizelerini içeren bir sütuna uygularken bool, her şeyin değiştiğini unutmayın True.
H. Vabri

Bu seçenek ayrıca "kategori" türüne dönüştürebilirsiniz
neves

17

Yalnızca belirli sütunları belirtmem gerektiğinde ve açık olmak istediğimde ( DOCS LOCATION başına ) kullandım:

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

Yani, orijinal soruyu kullanarak, ancak ona sütun adları sağlayarak ...

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

15

Burada argümanları bir DataFrame ve bir sütun listesi alan ve sütunlardaki tüm verileri sayılara zorlayan bir işlev var.

# df is the DataFrame, and column_list is a list of columns as strings (e.g ["col1","col2","col3"])
# dependencies: pandas

def coerce_df_columns_to_numeric(df, column_list):
    df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')

Yani, örneğin:

import pandas as pd

def coerce_df_columns_to_numeric(df, column_list):
    df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col1','col2','col3'])

coerce_df_columns_to_numeric(df, ['col2','col3'])

sütun adları yerine sütun dizinleri kullanmak isterseniz ne olur?
jvalenti

8

Her biri sütunları için farklı veri türlerine sahip iki veri çerçevesi oluşturmaya ve sonra bunları birleştirmeye ne dersiniz?

d1 = pd.DataFrame(columns=[ 'float_column' ], dtype=float)
d1 = d1.append(pd.DataFrame(columns=[ 'string_column' ], dtype=str))

Sonuçlar

In[8}:  d1.dtypes
Out[8]: 
float_column     float64
string_column     object
dtype: object

Veri çerçevesi oluşturulduktan sonra, onu 1. sütunda kayan nokta değişkenleri ve 2. sütunda dizeler (veya istediğiniz herhangi bir veri türü) ile doldurabilirsiniz.


4

pandalar> = 1.0

İşte pandalardaki en önemli dönüşümlerden bazılarını özetleyen bir grafik.

resim açıklamasını buraya girin

Dizeye dönüşümler önemsizdir .astype(str) ve şekilde gösterilmemiştir.

"Zor" ve "Yumuşak" dönüşümler

Bu bağlamdaki "dönüşümlerin", metin verilerinin gerçek veri türlerine dönüştürülmesini (sabit dönüşüm) veya nesne sütunlarındaki veriler için (uygun dönüşüm) daha uygun veri türlerinin çıkarılmasını ifade edebileceğini unutmayın. Farkı göstermek için,

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

a    object
b    object
dtype: object

# Actually converts string to numeric - hard conversion
df.apply(pd.to_numeric).dtypes                                             

a    int64
b    int64
dtype: object

# Infers better data types for object data - soft conversion
df.infer_objects().dtypes                                                  

a    object  # no change
b     int64
dtype: object

# Same as infer_objects, but converts to equivalent ExtensionType
df.convert_dtypes().dtypes                                                     

1

Aynı sorunu yaşadığımı sanıyordum ama aslında sorunun çözülmesini kolaylaştıran küçük bir farkım var. Bu soruya bakan diğerleri için giriş listenizin biçimini kontrol etmeye değer. Benim durumumda sayılar başlangıçta soruda olduğu gibi dizeler değil:

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

ancak veri çerçevesini oluşturmadan önce listeyi çok işleyerek türleri kaybederim ve her şey bir dize olur.

Numpy dizisi ile veri çerçevesi oluşturma

df = pd.DataFrame(np.array(a))

df
Out[5]: 
   0    1     2
0  a  1.2   4.2
1  b   70  0.03
2  x    5     0

df[1].dtype
Out[7]: dtype('O')

sütun 1 ve 2'deki girdilerin dize olarak değerlendirildiği, soru ile aynı veri çerçevesini verir. Ancak

df = pd.DataFrame(a)

df
Out[10]: 
   0     1     2
0  a   1.2  4.20
1  b  70.0  0.03
2  x   5.0  0.00

df[1].dtype
Out[11]: dtype('float64')

sütunları doğru biçimde olan bir veri çerçevesi verir


0

Pandalar 1.0.0 başlangıç, biz var pandas.DataFrame.convert_dtypes. Ne tür dönüştürmek için bile kontrol edebilirsiniz!

In [40]: df = pd.DataFrame(
    ...:     {
    ...:         "a": pd.Series([1, 2, 3], dtype=np.dtype("int32")),
    ...:         "b": pd.Series(["x", "y", "z"], dtype=np.dtype("O")),
    ...:         "c": pd.Series([True, False, np.nan], dtype=np.dtype("O")),
    ...:         "d": pd.Series(["h", "i", np.nan], dtype=np.dtype("O")),
    ...:         "e": pd.Series([10, np.nan, 20], dtype=np.dtype("float")),
    ...:         "f": pd.Series([np.nan, 100.5, 200], dtype=np.dtype("float")),
    ...:     }
    ...: )

In [41]: dff = df.copy()

In [42]: df 
Out[42]: 
   a  b      c    d     e      f
0  1  x   True    h  10.0    NaN
1  2  y  False    i   NaN  100.5
2  3  z    NaN  NaN  20.0  200.0

In [43]: df.dtypes
Out[43]: 
a      int32
b     object
c     object
d     object
e    float64
f    float64
dtype: object

In [44]: df = df.convert_dtypes()

In [45]: df.dtypes
Out[45]: 
a      Int32
b     string
c    boolean
d     string
e      Int64
f    float64
dtype: object

In [46]: dff = dff.convert_dtypes(convert_boolean = False)

In [47]: dff.dtypes
Out[47]: 
a      Int32
b     string
c     object
d     string
e      Int64
f    float64
dtype: object
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.