El título de la pregunta formulada es general, pero el caso de uso de los autores indicado en el cuerpo de la pregunta es específico. Por lo tanto, se pueden utilizar otras respuestas.
Pero para responder completamente a la pregunta del título , debe aclararse que parece que todos los enfoques pueden fallar en algunos casos y requerir un poco de revisión. Los revisé todos (y algunos adicionales) para disminuir el orden de confiabilidad (en mi opinión):
1. Comparación de tipos directamente a través de ==
(respuesta aceptada).
A pesar del hecho de que esta es una respuesta aceptada y tiene la mayoría de los votos a favor, creo que este método no debería usarse en absoluto. Porque, de hecho, este enfoque se desaconseja en Python como se menciona varias veces aquí .
Pero si todavía lo quieren usar - debe ser consciente de algunas dtypes pandas-específicos como pd.CategoricalDType
, pd.PeriodDtype
o pd.IntervalDtype
. Aquí hay que usar extra type( )
para reconocer dtype correctamente:
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
Otra advertencia aquí es que ese tipo debe señalarse con precisión:
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()
enfoque.
Este método no se ha mencionado en las respuestas hasta ahora.
Así que si la comparación directa de los tipos no es una buena idea - vamos a tratar función integrada de Python para este propósito, a saber - isinstance()
.
Falla solo al principio, porque supone que tenemos algunos objetos, pero pd.Series
o pd.DataFrame
podemos usarlos como contenedores vacíos con dtype
objetos predefinidos pero sin ningún objeto:
s = pd.Series([], dtype=bool)
s
>>> Series([], dtype: bool)
Pero si de alguna manera se supera este problema y quiere acceder a cada objeto, por ejemplo, en la primera fila y comprueba su tipo de letra de esta manera:
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')
Será engañoso en el caso de un tipo mixto de datos en una sola columna:
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')
Y por último, pero no menos importante: este método no puede reconocer directamente Category
dtype. Como se indica en los documentos :
Devolver un solo artículo de datos categóricos también devolverá el valor, no un categórico de longitud "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')
Entonces este método también es casi inaplicable.
3. df.dtype.kind
enfoque.
Este método aún puede funcionar con vacío pd.Series
o pd.DataFrames
tiene otros problemas.
Primero: no puede diferir algunos 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
En segundo lugar, lo que en realidad todavía no está claro para mí, incluso regresa en algunos tipos . Ninguno .
4. df.select_dtypes
enfoque.
Esto es casi lo que queremos. Este método está diseñado dentro de los pandas para que maneje la mayoría de los casos de esquina mencionados anteriormente: marcos de datos vacíos, difiere bien los tipos de numpy o específicos de pandas. Funciona bien con un solo tipo de letra .select_dtypes('bool')
. Puede usarse incluso para seleccionar grupos de columnas basados en 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')
Así, como se indica en los 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
Puede pensar que aquí vemos los primeros resultados inesperados (solía ser para mí: pregunta ) - TimeDelta
se incluye en la salida DataFrame
. Pero, como se respondió al contrario, debería ser así, pero uno debe ser consciente de ello. Tenga en cuenta que bool
se omite dtype, que también puede ser indeseable para alguien, pero se debe bool
y number
está en diferentes " subárboles " de dtypes numpy. En caso de bool, podemos usar test.select_dtypes(['bool'])
aquí.
La siguiente restricción de este método es que para la versión actual de pandas (0.24.2), este código: test.select_dtypes('period')
se elevará NotImplementedError
.
Y otra cosa es que no puede diferenciar cadenas de otros objetos:
test.select_dtypes('object')
>>> str obj
>>> 0 s1 [1, 2, 3]
>>> 1 s2 [5435, 35, -52, 14]
Pero esto es, primero, ya mencionado en los documentos. Y segundo, no es el problema de este método, sino la forma en que se almacenan las cadenas DataFrame
. Pero de todos modos este caso tiene que tener algún procesamiento posterior.
5. df.api.types.is_XXX_dtype
enfoque.
Se supone que esta es la forma más robusta y nativa de lograr el reconocimiento de dtype (supongo que la ruta del módulo donde residen las funciones dice). Y funciona casi perfectamente, pero todavía tiene al menos una advertencia y aún tiene que distinguir de alguna manera las columnas de cadena .
Además, esto puede ser subjetivo, pero este enfoque también tiene más number
procesamiento de grupos de tipos de dty 'comprensibles para humanos ' en comparación con .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
No timedelta
y bool
está incluido. Perfecto.
Mi canalización explota exactamente esta funcionalidad en este momento, más un poco de procesamiento manual posterior.
Salida.
Espero haber podido argumentar el punto principal: que todos los enfoques discutidos pueden usarse, pero solo pd.DataFrame.select_dtypes()
y pd.api.types.is_XXX_dtype
realmente deberían considerarse como los aplicables.
string
no es un dtype