cara memeriksa dtype kolom di python pandas

134

Saya perlu menggunakan fungsi yang berbeda untuk menangani kolom numerik dan kolom string. Apa yang saya lakukan sekarang benar-benar bodoh:

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

Apakah ada cara yang lebih elegan untuk melakukan ini? Misalnya

for y in agg.columns:
    if(dtype(agg[y]) == 'string'):
          treat_str(agg[y])
    elif(dtype(agg[y]) != 'string'):
          treat_numeric(agg[y])
James Bond
sumber
2
stringbukan dtype
David Robinson

Jawaban:

124

Anda dapat mengakses tipe data kolom dengan 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])
David Robinson
sumber
1
Hai David, Bisakah Anda berkomentar mengapa Anda menyertakan == np.float64? Bukankah kita mencoba untuk mengubahnya menjadi pelampung? Terima kasih.
Ryan Chase
@RyanChase OP dalam pertanyaan ini tidak pernah mengatakan dia mengubah menjadi float, dia hanya perlu tahu apakah akan menggunakan fungsi (tidak ditentukan) treat_numeric. Karena dia dimasukkan agg.dtypes==np.float64sebagai opsi, saya juga melakukannya.
David Robinson
3
Ada lebih banyak tipe numerik di numpy daripada keduanya, semuanya ada di numbersini: docs.scipy.org/doc/numpy-1.13.0/reference/arrays.scalars.html Solusi umumnya adalahis_numeric_dtype(agg[y])
Attila Tanyi
96

Dalam pandas 0.20.2Anda dapat melakukan:

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

Jadi kode Anda menjadi:

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])
danthelion
sumber
1
Apakah ada alternatif untuk versi panda yang lebih lama? Saya mendapatkan kesalahan: Tidak ada modul bernama api.types.
rph
2
pandas.core.common.is_numeric_dtypetelah ada sejak Pandas 0.13, dan itu melakukan hal yang sama, tapi saya rasa sudah usang dan mendukung pandas.api.types.is_numeric_dtypedi 0.19, saya pikir
Migwell
Itu adalah jawaban yang paling asli. Tetapi orang harus menyadari beberapa peringatan di sini.
BeforeFlight
46

Saya tahu ini sedikit dari utas lama tetapi dengan panda 19.02, Anda dapat melakukan:

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

Mike
sumber
1
jawaban yang bagus meskipun saya mungkin akan melakukannya include[np.number](untuk juga memasukkan int dan 32 bit float) untuk baris pertama dan exclude[object]baris kedua. String adalah objek sejauh dtypes diperhatikan. Faktanya, memasukkan 'string' dengan objek memberi saya kesalahan.
JohnE
1
tampaknya "string" tidak lagi didukung, "objek" harus digunakan sebagai gantinya. Tapi pasti jawaban yang benar :)
Bertrand
Juga harus diperhatikan bahwa 'period'dtype meningkat NotImplementedErroruntuk saat ini (pandas 0.24.2). Jadi seseorang mungkin membutuhkan beberapa pemrosesan pos buatan tangan.
BeforeFlight
21

Judul pertanyaan yang ditanyakan bersifat umum, tetapi kasus penggunaan penulis yang tertera di badan pertanyaan bersifat spesifik. Jadi jawaban lain dapat digunakan.

Tetapi untuk sepenuhnya menjawab pertanyaan judul , harus diklarifikasi bahwa tampaknya semua pendekatan mungkin gagal dalam beberapa kasus dan memerlukan beberapa pengerjaan ulang. Saya meninjau semuanya (dan beberapa tambahan) dalam penurunan urutan keandalan (menurut saya):

1. Membandingkan tipe secara langsung melalui ==(jawaban yang diterima).

Terlepas dari kenyataan bahwa ini adalah jawaban yang diterima dan memiliki jumlah suara positif terbanyak, saya pikir metode ini tidak boleh digunakan sama sekali. Karena sebenarnya pendekatan ini tidak dianjurkan pada python seperti yang disebutkan beberapa kali di sini .
Tetapi jika salah satu masih ingin menggunakannya - harus menyadari beberapa dtypes panda-spesifik seperti pd.CategoricalDType, pd.PeriodDtype, atau pd.IntervalDtype. Di sini seseorang harus menggunakan ekstra type( )untuk mengenali dtype dengan benar:

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

Peringatan lain di sini adalah jenis itu harus ditunjukkan dengan tepat:

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()pendekatan.

Metode ini belum disebutkan dalam jawaban sejauh ini.

Jadi jika membandingkan tipe secara langsung bukanlah ide yang baik - mari coba fungsi python built-in untuk tujuan ini, yaitu - isinstance().
Ini gagal hanya pada awalnya, karena mengasumsikan bahwa kita memiliki beberapa objek, tetapi pd.Seriesatau pd.DataFramedapat digunakan hanya sebagai wadah kosong dengan yang telah ditentukan dtypetetapi tidak ada objek di dalamnya:

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

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

Tetapi jika seseorang mengatasi masalah ini, dan ingin mengakses setiap objek, misalnya, di baris pertama dan memeriksa dtype-nya seperti itu:

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

Ini akan menyesatkan dalam kasus jenis data campuran dalam satu kolom:

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

Dan yang tak kalah pentingnya - metode ini tidak dapat langsung mengenali Categorydtype. Seperti yang dinyatakan dalam dokumen :

Mengembalikan satu item dari data kategori juga akan mengembalikan nilai, bukan kategori dengan panjang "1".

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

Jadi metode ini juga hampir tidak bisa diterapkan.

3. df.dtype.kindpendekatan.

Metode ini mungkin berfungsi dengan kosong pd.Seriesatau pd.DataFramestetapi memiliki masalah lain.

Pertama - tidak dapat membedakan beberapa tipe dt:

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

Kedua, apa yang sebenarnya masih belum jelas bagi saya, bahkan mengembalikan beberapa dtypes None .

4. df.select_dtypespendekatan.

Ini hampir seperti yang kita inginkan. Metode ini dirancang di dalam pandas sehingga menangani sebagian besar kasus sudut yang disebutkan sebelumnya - DataFrames kosong, berbeda dengan baik jenis dtype numpy atau pandas tertentu. Ia bekerja dengan baik dengan tipe dtype tunggal seperti .select_dtypes('bool'). Ini dapat digunakan bahkan untuk memilih kelompok kolom berdasarkan dtype:

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

Seperti itu, seperti yang dinyatakan dalam dokumen :

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

Pada mungkin berpikir bahwa di sini kita melihat hasil tak terduga pertama (dulu bagi saya: pertanyaan ) - TimeDeltadimasukkan ke dalam output DataFrame. Tetapi seperti yang dijawab sebaliknya, seharusnya demikian, tetapi orang harus menyadarinya. Perhatikan bahwa booldtype dilewati, yang mungkin juga tidak diinginkan oleh seseorang, tetapi hal itu disebabkan booldan numberberada dalam " subpohon " yang berbeda dari dtypes numpy. Dalam kasus dengan bool, kami dapat menggunakan di test.select_dtypes(['bool'])sini.

Batasan selanjutnya dari metode ini adalah untuk versi panda saat ini (0.24.2), kode ini: test.select_dtypes('period')akan muncul NotImplementedError.

Dan hal lainnya adalah ia tidak dapat membedakan string dari objek lain:

test.select_dtypes('object')

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

Tapi ini, pertama - sudah disebutkan di dokumen. Dan kedua - bukan masalah metode ini, melainkan cara string disimpan DataFrame. Tapi bagaimanapun kasus ini harus memiliki beberapa proses pasca.

5. df.api.types.is_XXX_dtypependekatan.

Yang ini dimaksudkan untuk menjadi cara yang paling kuat dan asli untuk mencapai pengenalan dtype (jalur modul tempat fungsi berada mengatakan dengan sendirinya) seperti yang saya kira. Dan itu bekerja hampir sempurna, tetapi masih memiliki setidaknya satu peringatan dan masih harus membedakan kolom string .

Selain itu, ini mungkin subjektif, tetapi pendekatan ini juga memiliki numberpemrosesan kelompok tipe yang lebih 'dapat dimengerti manusia' dibandingkan dengan .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

Tidak timedeltadan booldisertakan. Sempurna.

Pipeline saya mengeksploitasi fungsi ini dengan tepat pada saat ini, ditambah sedikit pemrosesan pasca tangan.

Keluaran.

Harapan saya dapat menjelaskan poin utama - bahwa semua pendekatan yang dibahas dapat digunakan, tetapi hanya pd.DataFrame.select_dtypes()dan pd.api.types.is_XXX_dtypeharus benar-benar dianggap sebagai pendekatan yang dapat diterapkan.

BeforeFlight
sumber
1
Jawaban yang bagus dan dirumuskan dengan baik. :-)
Oliver
8

Jika Anda ingin menandai tipe kolom dataframe sebagai string, Anda dapat melakukan:

df['A'].dtype.kind

Sebuah contoh:

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

Jawaban untuk kode Anda:

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])
Tom
sumber
4

Untuk cukup mencetak tipe data kolom

Untuk memeriksa tipe data setelah, misalnya, impor dari file

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

Keluaran ilustratif:

Type     Column Name                    Example Value
-----------------------------------------------------
int64    Age                            49
object   Attrition                      No
object   BusinessTravel                 Travel_Frequently
float64  DailyRate                      279.0
ePi272314
sumber