Il titolo della domanda è generale, ma il caso d'uso dell'autore indicato nel corpo della domanda è specifico. Quindi qualsiasi altra risposta può essere utilizzata.
Ma per rispondere in modo completo alla domanda del titolo , dovrebbe essere chiarito che sembra che tutti gli approcci possano fallire in alcuni casi e richiedere qualche rielaborazione. Li ho esaminati tutti (e alcuni aggiuntivi) in ordine decrescente di affidabilità (a mio parere):
1. Confronto dei tipi direttamente tramite ==(risposta accettata).
Nonostante il fatto che questa sia una risposta accettata e abbia il maggior numero di voti positivi, penso che questo metodo non dovrebbe essere utilizzato affatto. Perché in effetti questo approccio è sconsigliato in Python come menzionato più volte qui .
Ma se si vuole ancora di usarlo - dovrebbe essere a conoscenza di alcune dtypes panda-specifici come pd.CategoricalDType, pd.PeriodDtypeo pd.IntervalDtype. Qui è necessario utilizzare extra type( )per riconoscere correttamente 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
Un altro avvertimento qui è che il tipo dovrebbe essere sottolineato con precisione:
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()approccio.
Finora questo metodo non è stato menzionato nelle risposte.
Quindi, se il confronto diretto dei tipi non è una buona idea, proviamo la funzione Python incorporata per questo scopo, vale a dire - isinstance().
Fallisce solo all'inizio, perché presume che abbiamo alcuni oggetti, ma pd.Serieso pd.DataFramepuò essere usato come solo contenitori vuoti con predefiniti dtypema nessun oggetto al suo interno:
s = pd.Series([], dtype=bool)
s
>>> Series([], dtype: bool)
Ma se in qualche modo si supera questo problema e si desidera accedere a ciascun oggetto, ad esempio, nella prima riga e controllare il suo dtype in questo modo:
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')
Sarebbe fuorviante nel caso di dati di tipo misto in una singola colonna:
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, ultimo ma non meno importante, questo metodo non è in grado di riconoscere direttamente Categorydtype. Come indicato nei documenti :
Anche la restituzione di un singolo elemento da dati categoriali restituirà il valore, non un categorico di lunghezza "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')
Quindi anche questo metodo è quasi inapplicabile.
3. df.dtype.kind approccio.
Questo metodo può ancora funzionare con vuoto pd.Serieso pd.DataFramesma presenta altri problemi.
Primo: non è in grado di differire alcuni dtypes:
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
In secondo luogo, ciò che in realtà non è ancora chiaro per me, ritorna anche su alcuni tipi Nessuno .
4. df.select_dtypesapproccio.
Questo è quasi quello che vogliamo. Questo metodo è stato progettato all'interno dei panda in modo da gestire la maggior parte dei casi d'angolo menzionati in precedenza: DataFrame vuoti, differisce bene dai dtypes specifici di numpy o panda. Funziona bene con un singolo dtype come .select_dtypes('bool'). Può essere utilizzato anche per selezionare gruppi di colonne in base a 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')
In questo modo, come indicato nei documenti :
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
On può pensare che qui vediamo i primi risultati inaspettati (in passato per me: domanda ) - TimeDeltaè incluso nell'output DataFrame. Ma come risposta contraria dovrebbe essere così, ma bisogna esserne consapevoli. Nota che booldtype viene saltato, che potrebbe anche essere indesiderato per qualcuno, ma è dovuto boole numbersi trova in diversi " sottoalberi " di numpy dtypes. In caso di bool, possiamo usare test.select_dtypes(['bool'])qui.
La prossima restrizione di questo metodo è che per la versione corrente di panda (0.24.2), questo codice: test.select_dtypes('period')aumenterà NotImplementedError.
E un'altra cosa è che non è in grado di differenziare le stringhe da altri oggetti:
test.select_dtypes('object')
>>> str obj
>>> 0 s1 [1, 2, 3]
>>> 1 s2 [5435, 35, -52, 14]
Ma questo è il primo - già menzionato nei documenti. E secondo, non è il problema di questo metodo, piuttosto il modo in cui le stringhe vengono memorizzate DataFrame. Ma comunque questo caso deve avere un po 'di post-elaborazione.
5. df.api.types.is_XXX_dtypeapproccio.
Questo è inteso per essere il modo più robusto e nativo per ottenere il riconoscimento di dtype (il percorso del modulo in cui risiedono le funzioni dice da solo) come suppongo. E funziona quasi perfettamente, ma ha ancora almeno un avvertimento e deve ancora distinguere in qualche modo le colonne delle stringhe .
Inoltre, questo può essere soggettivo, ma questo approccio ha anche numberun'elaborazione di gruppo di tipi più ` ` comprensibili dall'uomo '' rispetto a .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 timedeltaed boolè incluso. Perfetto.
La mia pipeline sfrutta esattamente questa funzionalità in questo momento, oltre a un po 'di elaborazione post-manuale.
Produzione.
Spero di essere stato in grado di argomentare il punto principale - che tutti gli approcci discussi possono essere utilizzati, ma solo pd.DataFrame.select_dtypes()e pd.api.types.is_XXX_dtypedovrebbero essere realmente considerati come quelli applicabili.
stringnon è un dtype