как проверить dtype столбца в python pandas


135

Мне нужно использовать разные функции для обработки числовых и строковых столбцов. То, что я делаю сейчас, действительно глупо:

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не dtype
— Дэвид Робинсон

Ответы:


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 OP в этом вопросе никогда не говорил, что он преобразовывает в числа с плавающей запятой, ему просто нужно было знать, использовать ли (неуказанную) 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.
— рф 02

2
pandas.core.common.is_numeric_dtypeсуществует с Pandas 0.13, и он делает то же самое, но pandas.api.types.is_numeric_dtype, я думаю , он устарел в пользу
— версии

Это самый родной ответ. Но здесь следует помнить о некоторых оговорках .
— BeforeFlight 02

46

Я знаю, что это немного старая тема, но с pandas 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](чтобы также включить целые числа и 32-битные числа с плавающей запятой) для первой строки и exclude[object]для второй строки. Строки являются объектами в том, что касается типов. Фактически, включение строки с объектом дает мне ошибку.
— JohnE

1
кажется, что "строка" больше не поддерживается, вместо нее нужно использовать "объект". Но однозначно правильный ответ :)
— Бертран

Также следует отметить, что 'period'dtype пока растет NotImplementedError(pandas 0.24.2). Так что может потребоваться ручная постобработка.
— BeforeFlight 02

22

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

Но для того, чтобы полностью ответить на заглавный вопрос, следует уточнить, что, похоже, в некоторых случаях все подходы могут дать сбой и потребовать некоторой доработки. Я просмотрел все (и некоторые дополнительные) в порядке уменьшения надежности (на мой взгляд):

1. Сравнение типов напрямую через ==(принятый ответ).

Несмотря на то, что это принятый ответ и наибольшее количество положительных голосов, я думаю, что этот метод не следует использовать вообще. Потому что на самом деле этот подход не рекомендуется в Python, как упоминалось здесь несколько раз .
Но если один все еще хотите использовать его - должны быть осведомлены о некоторых панды специфических dtypes , как pd.CategoricalDType, pd.PeriodDtypeили pd.IntervalDtype. Здесь нужно использовать extra 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)

Но если кто-то как-то преодолеет эту проблему и захочет получить доступ к каждому объекту, например, в первой строке, и проверит его dtype примерно так:

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

Во-вторых, что для меня на самом деле все еще неясно, это даже возвращается на некоторых типах dtypes None .

4. df.select_dtypesподход.

Это почти то, что мы хотим. Этот метод разработан внутри pandas, поэтому он обрабатывает большинство угловых случаев, упомянутых ранее - пустые DataFrames, хорошо различаются dtypes numpy или pandas. Он хорошо работает с одиночным типом dtype .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'])здесь.

Следующее ограничение этого метода заключается в том, что для текущей версии pandas (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подход.

Предполагается, что это самый надежный и собственный способ достижения распознавания dtype (путь к модулю, в котором находятся функции, говорит сам по себе), как я полагаю. И он работает почти идеально, но все же имеет как минимум одно предостережение и все же нужно как-то различать строковые столбцы .

Кроме того, это может быть субъективным, но этот подход также имеет более «понятную для numberчеловека» групповую обработку dtypes по сравнению с .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.