Название задаваемого вопроса является общим, но авторы используют конкретный вариант использования, указанный в теле вопроса. Так что можно использовать любые другие ответы.
Но для того, чтобы полностью ответить на заглавный вопрос, следует уточнить, что, похоже, в некоторых случаях все подходы могут дать сбой и потребовать некоторой доработки. Я просмотрел все (и некоторые дополнительные) в порядке уменьшения надежности (на мой взгляд):
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')
И последнее, но не менее важное - этот метод не может напрямую распознавать Category
dtype. Как указано в документах :
При возврате одного элемента из категориальных данных также будет возвращено значение, а не категориальное значение длины «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
. Но , как ответил в наоборот это должно быть так, но один должен знать об этом. Обратите внимание , что bool
DTYPE пропускается, что может быть также нежелателен для кого - то, но это из - за 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
должны действительно рассматриваться как применимые.
string
не dtype