як перевірити тип стовпця в пандах python


133

Мені потрібно використовувати різні функції для обробки числових стовпців і рядків. Те, що я зараз роблю, насправді німе:

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

Чи є більш елегантний спосіб це зробити? Напр

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

2
stringне є типом
Девід Робінсон

Відповіді:


124

Ви можете отримати доступ до типу даних стовпця за допомогою 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
Привіт, Девіде, чи можете ви прокоментувати, чому ви включили == np.float64? Хіба ми не намагаємося перетворити на плавки? Дякую.
Райан Чейз

@RyanChase ОП в цьому питанні ніколи не говорив, що він перетворюється на плавки, йому просто потрібно було знати, чи використовувати (не визначену) treat_numericфункцію. Оскільки він включив agg.dtypes==np.float64як варіант, я також зробив це.
Девід Робінсон

3
У numpy є більше числових типів, ніж ці два, все numberтут: docs.scipy.org/doc/numpy-1.13.0/reference/arrays.scalars.html Загальне рішенняis_numeric_dtype(agg[y])
Аттіла Таній

96

У pandas 0.20.2вас можна зробити:

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

Таким чином ваш код стає:

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
Чи є альтернатива для старих версій панд? Я отримую помилку: жоден модуль з назвою api.types.
rph

2
pandas.core.common.is_numeric_dtypeіснує з Панди 0,13, і він робить те ж саме, але його застаріло на користь pandas.api.types.is_numeric_dtypeу 0,19, я думаю
Міґвелл

Це найрідніша відповідь. Але тут слід знати деякі застереження .
Перед польотом

46

Я знаю, що це трохи стара тема, але з пандами 19.02 ви можете:

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
Хороший відповідь, я, мабуть, зробив би include[np.number](включив також int та 32-бітові плавці) для першого та exclude[object]другого рядків. Струни - це об'єкти, що стосуються дитипів. Насправді, включення "string" з об'єктом дає мені помилку.
JohnE

1
Здається, що "string" більше не підтримується, замість нього слід використовувати "object". Але остаточно правильна відповідь :)
Бертран

Також слід зауважити, що 'period'dtype нараховує NotImplementedErrorнаразі (панди 0,24,2). Отож, можливо, знадобиться обробка ручної роботи після публікації.
Перед польотом

21

Назва запитуваного питання загальна, але автори використовують випадок, зазначений в тілі питання, специфічний. Тож будь-які інші відповіді можуть бути використані.

Але для того, щоб повністю відповісти на головне запитання, слід уточнити, що, здається, у всіх випадках всі підходи можуть провалюватися і вимагати певної переробки. Я переглянув усі (та деякі додаткові) в порядку зниження надійності (на мою думку):

1. Порівняння типів безпосередньо через ==(прийнята відповідь).

Незважаючи на те, що ця відповідь прийнята і має більшу кількість підрахунків, я думаю, що цей метод не слід застосовувати взагалі. Тому що насправді цей підхід НЕ рекомендується в пітона , як згадувалося кілька разів тут .
Але якщо один все ще хочете використовувати його - повинні бути інформовані про деякі панди специфічних dtypes , як pd.CategoricalDType, pd.PeriodDtypeабо pd.IntervalDtype. Тут потрібно використовувати додаткові type( )для правильного розпізнавання dtype:

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

Ще одне застереження тут полягає в тому, що тип слід точно вказати:

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()підхід.

Цей метод досі не згадується у відповідях.

Тож якщо пряме порівняння типів не є хорошою ідеєю - давайте спробуємо вбудовану функцію python для цієї мети, а саме - isinstance().
Він зазнає невдачі тільки на самому початку, так як передбачається , що у нас є якісь - то об'єкти, але pd.Seriesі pd.DataFrameможуть бути використані як тільки порожні контейнери з зумовлені , dtypeале без будь - яких об'єктів в ньому:

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

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

Але якщо хтось якось подолати це питання і хоче отримати доступ до кожного об'єкта, наприклад, у першому рядку та перевіряє його тип як-небудь подібне:

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

Це буде вводити в оману у випадку змішаного типу даних в одному стовпчику:

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

І останнє, але не менш важливе - цей метод не може безпосередньо розпізнати Categorydtype. Як зазначено в документах :

Повернення одного елемента з категоричних даних також поверне значення, а не категоричне довжиною "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')

Тож цей метод також майже не застосовується.

3. df.dtype.kind підхід.

Цей метод ще може працювати з порожнім pd.Seriesабо pd.DataFramesмає інші проблеми.

По-перше - він не може відрізняти деякі типи:

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

По-друге, те, що насправді для мене ще незрозуміло, навіть повертається на деякі типи None .

4. df.select_dtypesпідхід.

Це майже те, що ми хочемо. Цей метод, розроблений всередині панд, таким чином обробляє більшість згаданих раніше кутових випадків - порожні DataFrames, добре відрізняються нумеровані або панд-типові типи. Він добре працює з одним типом типу .select_dtypes('bool'). Він може бути використаний навіть для вибору груп стовпців на основі 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')

Так, як зазначено в документах :

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

Подальше може подумати, що тут ми бачимо перші несподівані (колись для мене: питання ) результати - TimeDeltaвключається у вихід DataFrame. Але як відповіли навпаки, це повинно бути так, але треба знати про це. Зверніть увагу , що boolDTYPE пропускається, що може бути також небажаний для кого - то, але це з - за boolі numberв різних « піддерев » з Numpy dtypes. У випадку з bool, ми можемо використовувати test.select_dtypes(['bool'])тут.

Наступним обмеженням цього методу є те, що для поточної версії панд (0.24.2) цей код: test.select_dtypes('period')підвищиться NotImplementedError.

Інша справа, що він не може відрізняти рядки від інших об'єктів:

test.select_dtypes('object')

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

Але це, по-перше, - вже згадується в документах. А друге - не проблема цього методу, скоріше те, як зберігаються рядки DataFrame. Але в будь-якому випадку цей випадок повинен мати деяку поштову обробку.

5. df.api.types.is_XXX_dtypeпідхід.

Цей приклад призначений для найбільш надійного та рідного способу досягнення розпізнавання типу (шлях модуля, де функції знаходяться, говорить сам по собі), як я припускаю. І це працює майже ідеально, але все-таки є хоча б один застереження і все-таки доведеться якось розрізняти рядкові стовпчики .

Крім того, це може бути суб'єктивним, але цей підхід також має більш numberгрупову обробку " типових для людини" груп обробки, порівняно з .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

Ні timedeltaі boolвключено. Ідеально.

Мій трубопровід в даний момент використовує саме цю функціональність, а також трохи опрацювання вручну.

Вихідні дані.

Сподіваюся, що я зміг аргументувати головне - що всі обговорювані підходи можуть використовуватися, але тільки pd.DataFrame.select_dtypes()і pd.api.types.is_XXX_dtypeповинні бути дійсно розглянуті як застосовні.


1
Чудова і добре сформульована відповідь. :-)
Олівер

8

Якщо ви хочете позначити тип стовпця фрейму даних як рядок, ви можете зробити:

df['A'].dtype.kind

Приклад:

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

Відповідь на ваш код:

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

Для гарного друку типів даних стовпців

Щоб перевірити типи даних після, наприклад, імпорту з файлу

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

Ілюстративний результат:

Type     Column Name                    Example Value
-----------------------------------------------------
int64    Age                            49
object   Attrition                      No
object   BusinessTravel                 Travel_Frequently
float64  DailyRate                      279.0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.