python pandalarında bir sütunun dtype'ı nasıl kontrol edilir


135

Sayısal sütunları ve dize sütunlarını işlemek için farklı işlevler kullanmam gerekiyor. Şu an yaptığım şey gerçekten aptalca:

allc = list((agg.loc[:, (agg.dtypes==np.float64)|(agg.dtypes==np.int)]).columns)
for y in allc:
    treat_numeric(agg[y])    

allc = list((agg.loc[:, (agg.dtypes!=np.float64)&(agg.dtypes!=np.int)]).columns)
for y in allc:
    treat_str(agg[y])    

Bunu yapmanın daha zarif bir yolu var mı? Örneğin

for y in agg.columns:
    if(dtype(agg[y]) == 'string'):
          treat_str(agg[y])
    elif(dtype(agg[y]) != 'string'):
          treat_numeric(agg[y])

2
stringbir dtype değil
David Robinson

Yanıtlar:


124

Bir sütunun veri türüne şu şekilde erişebilirsiniz dtype:

for y in agg.columns:
    if(agg[y].dtype == np.float64 or agg[y].dtype == np.int64):
          treat_numeric(agg[y])
    else:
          treat_str(agg[y])

1
Merhaba David, == np.float64'ü neden dahil ettiğiniz konusunda yorum yapabilir misiniz? Şamandıralara dönüştürmeye çalışmıyor muyuz? Teşekkürler.
Ryan Chase

@RyanChase Bu sorudaki OP, kayan noktalara dönüştürüldüğünü hiç söylemedi, sadece (belirtilmemiş) bir treat_numericişlev kullanıp kullanmayacağını bilmesi gerekiyordu . O agg.dtypes==np.float64bir seçenek olarak dahil ettiğinden ben de yaptım.
David Robinson

3
Numpy'de bu ikisinden daha fazla sayısal tür var, her şey numberburada: docs.scipy.org/doc/numpy-1.13.0/reference/arrays.scalars.html Genel çözümis_numeric_dtype(agg[y])
Attila Tanyi

96

Gelen pandas 0.20.2yapabileceğiniz:

from pandas.api.types import is_string_dtype
from pandas.api.types import is_numeric_dtype

is_string_dtype(df['A'])
>>>> True

is_numeric_dtype(df['B'])
>>>> True

Böylece kodunuz şöyle olur:

for y in agg.columns:
    if (is_string_dtype(agg[y])):
        treat_str(agg[y])
    elif (is_numeric_dtype(agg[y])):
        treat_numeric(agg[y])

1
Daha eski pandalar için herhangi bir alternatif var mı? Şu hatayı alıyorum: api.types adlı modül yok.
rph

2
pandas.core.common.is_numeric_dtypePandalar 0.13'ten beri var ve aynı şeyi yapıyor, ancak pandas.api.types.is_numeric_dtype
0.19'da

En doğal cevap bu. Ancak burada bazı uyarıların farkında olunmalıdır .
BeforeFlight

46

Bunun biraz eski bir konu olduğunu biliyorum ama 19.02 pandaları ile şunları yapabilirsiniz:

df.select_dtypes(include=['float64']).apply(your_function)
df.select_dtypes(exclude=['string','object']).apply(your_other_function)

http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.select_dtypes.html


1
iyi cevap, muhtemelen include[np.number]ilk satır ve exclude[object]ikinci satır için (aynı zamanda girişler ve 32 bit kayan sayıları da dahil etmek için) yapsam da . Dizeler, dtype söz konusu olduğunda nesnelerdir. Aslında, nesneye 'dizge' eklemek bana bir hata veriyor.
Johne

1
"string" artık desteklenmiyor gibi görünüyor, bunun yerine "nesne" kullanılmalı. Ama kesinlikle doğru cevap :)
Bertrand

Ayrıca 'period'dtype'ın şimdilik yükselmekte olduğuna dikkat edilmelidir NotImplementedError(pandalar 0.24.2). Bu nedenle, bazı el yapımı post işlemlere ihtiyaç duyulabilir.
BeforeFlight

22

Sorulan soru başlığı geneldir, ancak yazarlar sorunun gövdesinde belirtilen kullanım durumu özeldir. Bu nedenle başka herhangi bir cevap kullanılabilir.

Ancak başlık sorusuna tam olarak cevap verebilmek için, tüm yaklaşımların bazı durumlarda başarısız olabileceği ve biraz yeniden çalışma gerektirebileceği açıklığa kavuşturulmalıdır . Güvenilirlik sırasını düşürmek için hepsini (ve bazı eklerini) gözden geçirdim (bence):

1. Türleri doğrudan ==(kabul edilen yanıt) aracılığıyla karşılaştırma .

Bunun kabul edilmiş bir cevap olmasına ve çoğu olumlu oyu dikkate almasına rağmen, bu yöntemin hiç kullanılmaması gerektiğini düşünüyorum. Çünkü aslında bu yaklaşım olduğunu cesaretini defalarca belirtildiği gibi Python burada .
Biri hala kullanmak istiyorsanız - gibi bazı pandalar özgü dtypes farkında olmalı pd.CategoricalDType, pd.PeriodDtypeya da pd.IntervalDtype. Burada type( )dtype'ı doğru tanımak için ekstra kullanmak gerekir :

s = pd.Series([pd.Period('2002-03','D'), pd.Period('2012-02-01', 'D')])
s
s.dtype == pd.PeriodDtype   # Not working
type(s.dtype) == pd.PeriodDtype # working 

>>> 0    2002-03-01
>>> 1    2012-02-01
>>> dtype: period[D]
>>> False
>>> True

Buradaki bir başka uyarı, bu tipin tam olarak belirtilmesi gerektiğidir:

s = pd.Series([1,2])
s
s.dtype == np.int64 # Working
s.dtype == np.int32 # Not working

>>> 0    1
>>> 1    2
>>> dtype: int64
>>> True
>>> False

2. isinstance()yaklaşım.

Şu ana kadar cevaplarda bu yöntemden bahsedilmemiştir.

Dolayısıyla, türlerin doğrudan karşılaştırılması iyi bir fikir değilse - bu amaç için yerleşik python işlevini deneyelim, yani - isinstance().
Başlangıçta başarısız olur, çünkü bazı nesnelerimiz olduğunu varsayar, ancak önceden tanımlanmış ancak içinde hiç nesne olmayan boş kaplar olarak kullanılabilir pd.Seriesveya pd.DataFramekullanılabilir dtype:

s = pd.Series([], dtype=bool)
s

>>> Series([], dtype: bool)

Ancak biri bir şekilde bu sorunun üstesinden gelirse ve her nesneye örneğin ilk satırda erişmek isterse ve dtype benzer şekilde kontrol ederse:

df = pd.DataFrame({'int': [12, 2], 'dt': [pd.Timestamp('2013-01-02'), pd.Timestamp('2016-10-20')]},
                  index = ['A', 'B'])
for col in df.columns:
    df[col].dtype, 'is_int64 = %s' % isinstance(df.loc['A', col], np.int64)

>>> (dtype('int64'), 'is_int64 = True')
>>> (dtype('<M8[ns]'), 'is_int64 = False')

Tek sütunda karışık veri türü olması durumunda yanıltıcı olacaktır:

df2 = pd.DataFrame({'data': [12, pd.Timestamp('2013-01-02')]},
                  index = ['A', 'B'])
for col in df2.columns:
    df2[col].dtype, 'is_int64 = %s' % isinstance(df2.loc['A', col], np.int64)

>>> (dtype('O'), 'is_int64 = False')

Ve son fakat en az değil - bu yöntem Categorydtype'ı doğrudan tanıyamaz . Dokümanlarda belirtildiği gibi :

Kategorik verilerden tek bir öğe döndürmek, "1" uzunluğunun kategorikini değil, değeri de döndürecektir.

df['int'] = df['int'].astype('category')
for col in df.columns:
    df[col].dtype, 'is_int64 = %s' % isinstance(df.loc['A', col], np.int64)

>>> (CategoricalDtype(categories=[2, 12], ordered=False), 'is_int64 = True')
>>> (dtype('<M8[ns]'), 'is_int64 = False')

Yani bu yöntem de neredeyse uygulanamaz.

3. df.dtype.kindyaklaşım.

Bu yöntem henüz boş çalışabilir pd.Seriesveya pd.DataFramesancak başka sorunları olabilir.

Birincisi - bazı tipleri ayırt edemez:

df = pd.DataFrame({'prd'  :[pd.Period('2002-03','D'), pd.Period('2012-02-01', 'D')],
                   'str'  :['s1', 's2'],
                   'cat'  :[1, -1]})
df['cat'] = df['cat'].astype('category')
for col in df:
    # kind will define all columns as 'Object'
    print (df[col].dtype, df[col].dtype.kind)

>>> period[D] O
>>> object O
>>> category O

İkincisi, benim için hala belirsiz olan şey, hatta bazı dtype'lerde geri dönüyor Hiçbiri .

4. df.select_dtypesyaklaşım.

Bu neredeyse istediğimiz şey. Bu yöntem, pandaların içinde tasarlandı, böylece daha önce bahsedilen köşe durumlarının çoğunu idare eder - boş DataFrame'ler, uyuşuk veya pandalara özgü dtiplerden farklıdır. Tek dtype benzeri ile iyi çalışır .select_dtypes('bool'). Dtype'a göre sütun gruplarını seçmek için bile kullanılabilir:

test = pd.DataFrame({'bool' :[False, True], 'int64':[-1,2], 'int32':[-1,2],'float': [-2.5, 3.4],
                     'compl':np.array([1-1j, 5]),
                     'dt'   :[pd.Timestamp('2013-01-02'), pd.Timestamp('2016-10-20')],
                     'td'   :[pd.Timestamp('2012-03-02')- pd.Timestamp('2016-10-20'),
                              pd.Timestamp('2010-07-12')- pd.Timestamp('2000-11-10')],
                     'prd'  :[pd.Period('2002-03','D'), pd.Period('2012-02-01', 'D')],
                     'intrv':pd.arrays.IntervalArray([pd.Interval(0, 0.1), pd.Interval(1, 5)]),
                     'str'  :['s1', 's2'],
                     'cat'  :[1, -1],
                     'obj'  :[[1,2,3], [5435,35,-52,14]]
                    })
test['int32'] = test['int32'].astype(np.int32)
test['cat'] = test['cat'].astype('category')

Tıpkı belgelerde belirtildiği gibi :

test.select_dtypes('number')

>>>     int64   int32   float   compl   td
>>> 0      -1      -1   -2.5    (1-1j)  -1693 days
>>> 1       2       2    3.4    (5+0j)   3531 days

On, burada ilk beklenmedik (eskiden benim için: soru ) sonuçları gördüğümüzü düşünebilir - TimeDeltaçıktıya dahil edilir DataFrame. Ama tersine yanıtlandığı gibi , öyle olmalı, ancak kişi bunun farkında olmalı. Not o boolda birisi için istenmeyen olabileceğini, atlanır d_type, ancak nedeniyle olduğunu boolve numberfarklı "olan alt ağaçlar numpy dtypes arasında". Bool durumunda, test.select_dtypes(['bool'])burada kullanabiliriz .

Bu yöntemin bir sonraki kısıtlayıcı pandalarıyla mevcut versiyonu (0.24.2) için, bu kod olmasıdır test.select_dtypes('period')yükseltecektir NotImplementedError.

Ve başka bir şey de dizeleri diğer nesnelerden ayırt edememesidir:

test.select_dtypes('object')

>>>     str     obj
>>> 0    s1     [1, 2, 3]
>>> 1    s2     [5435, 35, -52, 14]

Ancak bu, ilk olarak - daha önce belgelerde bahsedilmiştir . Ve ikincisi - bu yöntemin sorunu değil, dizelerin depolanma şeklidir DataFrame. Ama yine de bu davada bazı sonradan işlemlerin yapılması gerekiyor.

5. df.api.types.is_XXX_dtypeyaklaşım.

Bunun, tahmin ettiğim gibi, dtype tanıma (işlevlerin bulunduğu modülün yolu kendi kendine söyler) elde etmenin en sağlam ve doğal yolu olması amaçlanmıştır. Ve neredeyse mükemmel çalışıyor, ancak yine de en az bir uyarısı var ve yine de bir şekilde dize sütunlarını ayırt etmesi gerekiyor .

Ayrıca, bu öznel olabilir, ancak bu yaklaşım aynı zamanda aşağıdakilere numberkıyasla daha 'insan tarafından anlaşılabilir' dtype grup işlemesine sahiptir .select_dtypes('number'):

for col in test.columns:
    if pd.api.types.is_numeric_dtype(test[col]):
        print (test[col].dtype)

>>> bool
>>> int64
>>> int32
>>> float64
>>> complex128

Hayır timedeltave booldahildir. Mükemmel.

Ardışık düzenim, şu anda tam olarak bu işlevsellikten ve ayrıca bir miktar el sonrası işlemden yararlanıyor.

Çıktı.

Umarım ana noktayı tartışabilmişimdir - tartışılan tüm yaklaşımlar kullanılabilir, ancak sadece pd.DataFrame.select_dtypes()ve pd.api.types.is_XXX_dtypegerçekten uygulanabilir olanlar olarak düşünülmelidir.


1
Harika ve iyi formüle edilmiş cevap. :-)
Oliver

8

Bir veri çerçevesi sütununun türünü bir dize olarak işaretlemek istiyorsanız, şunları yapabilirsiniz:

df['A'].dtype.kind

Bir örnek:

In [8]: df = pd.DataFrame([[1,'a',1.2],[2,'b',2.3]])
In [9]: df[0].dtype.kind, df[1].dtype.kind, df[2].dtype.kind
Out[9]: ('i', 'O', 'f')

Kodunuzun cevabı:

for y in agg.columns:
    if(agg[y].dtype.kind == 'f' or agg[y].dtype.kind == 'i'):
          treat_numeric(agg[y])
    else:
          treat_str(agg[y])

4

Sütun veri türlerini güzel yazdırmak için

Örneğin bir dosyadan içe aktarma işleminden sonra veri türlerini kontrol etmek için

def printColumnInfo(df):
    template="%-8s %-30s %s"
    print(template % ("Type", "Column Name", "Example Value"))
    print("-"*53)
    for c in df.columns:
        print(template % (df[c].dtype, c, df[c].iloc[1]) )

Açıklayıcı çıktı:

Type     Column Name                    Example Value
-----------------------------------------------------
int64    Age                            49
object   Attrition                      No
object   BusinessTravel                 Travel_Frequently
float64  DailyRate                      279.0
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.