O título da pergunta feita é geral, mas o caso de uso dos autores indicado no corpo da pergunta é específico. Portanto, qualquer outra resposta pode ser usada.
Mas, para responder totalmente à pergunta do título , deve ser esclarecido que parece que todas as abordagens podem falhar em alguns casos e exigir algum retrabalho. Eu revi todos eles (e alguns adicionais) na diminuição da ordem de confiabilidade (na minha opinião):
1. Comparando tipos diretamente via ==(resposta aceita).
Apesar do fato de essa resposta ser aceita e ter mais votos positivos, acho que esse método não deve ser usado. Porque, de fato, essa abordagem é desencorajada em python, como mencionado várias vezes aqui .
Mas se alguém ainda quiser usá-lo - deve estar ciente de alguns tipos específicos de pandas pd.CategoricalDType, como pd.PeriodDtype, ou pd.IntervalDtype. Aqui é preciso usar extra type( )para reconhecer o dtype corretamente:
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
Outra ressalva aqui é que esse tipo deve ser apontado com precisão:
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()abordagem.
Este método não foi mencionado nas respostas até agora.
Portanto, se a comparação direta de tipos não é uma boa idéia - vamos tentar a função python interna para esse fim, a saber - isinstance().
Ele não apenas no início, porque assume que temos alguns objetos, mas pd.Seriesou pd.DataFramepode ser usado como apenas recipientes vazios com pré-definidos dtype, mas não objetos nele:
s = pd.Series([], dtype=bool)
s
>>> Series([], dtype: bool)
Mas se alguém de alguma forma superar esse problema, e quiser acessar cada objeto, por exemplo, na primeira linha e verificar seu dtype da seguinte forma:
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')
Isso será enganoso no caso de dados mistos em coluna única:
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')
E por último mas não menos importante - esse método não pode reconhecer diretamente o Categorytipo. Conforme declarado nos documentos :
A devolução de um único item a partir de dados categóricos também retornará o valor, não uma categórica de comprimento "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')
Portanto, esse método também é quase inaplicável.
3. df.dtype.kindabordagem.
Esse método ainda pode funcionar com vazio pd.Seriesou pd.DataFramescom outros problemas.
Primeiro - não é possível diferenciar alguns tipos:
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
Segundo, o que ainda não está claro para mim, ele ainda retorna com alguns tipos Não .
4. df.select_dtypesabordagem.
Isso é quase o que queremos. Esse método foi desenvolvido dentro dos pandas para lidar com a maioria dos casos de canto mencionados anteriormente - DataFrames vazios, difere bem os tipos numpy ou específicos de pandas. Funciona bem com um tipo único .select_dtypes('bool'). Pode ser usado mesmo para selecionar grupos de colunas com base no 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')
Assim, conforme declarado nos documentos :
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
Podemos pensar que aqui vemos os primeiros resultados inesperados (costumava ser para mim: pergunta ) - TimeDeltasão incluídos na saída DataFrame. Mas, como respondido em contrário, deve ser assim, mas é preciso estar ciente disso. Observe que o booldtype é ignorado, o que também pode ser indesejável para alguém, mas é devido a boole numberestá em " subárvores " diferentes de tipos numpy. No caso de bool, podemos usar test.select_dtypes(['bool'])aqui.
A próxima restrição desse método é que, para a versão atual do pandas (0.24.2), esse código: test.select_dtypes('period')será gerado NotImplementedError.
E outra coisa é que não é possível diferenciar strings de outros objetos:
test.select_dtypes('object')
>>> str obj
>>> 0 s1 [1, 2, 3]
>>> 1 s2 [5435, 35, -52, 14]
Mas este é o primeiro - já mencionado na documentação. E segundo - não é o problema desse método, mas a maneira como as strings são armazenadas DataFrame. Mas de qualquer maneira, este caso precisa ter algum pós-processamento.
5. df.api.types.is_XXX_dtypeabordagem.
Este pretende ser a maneira mais robusta e nativa de obter reconhecimento de tipo (caminho do módulo em que as funções residem diz por si só), como suponho. E funciona quase perfeitamente, mas ainda tem pelo menos uma ressalva e ainda precisa distinguir de alguma forma as colunas de string .
Além disso, isso pode ser subjetivo, mas essa abordagem também possui um numberprocessamento de grupo de tipos de tipo 'compreensível ao ser humano' comparado com .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
Não timedeltae boolestá incluído. Perfeito.
Meu pipeline explora exatamente essa funcionalidade nesse momento, além de um pouco de processamento pós-mão.
Resultado.
Espero ter conseguido argumentar sobre o ponto principal - que todas as abordagens discutidas possam ser usadas, mas apenas pd.DataFrame.select_dtypes()e pd.api.types.is_XXX_dtypedevem ser realmente consideradas como as aplicáveis.
stringnão é um tipo