Tytuł zadawanego pytania jest ogólny, ale przypadek użycia przez autorów podany w treści pytania jest specyficzny. Można więc użyć innych odpowiedzi.
Aby jednak w pełni odpowiedzieć na tytułowe pytanie , należy wyjaśnić, że wydaje się, że wszystkie podejścia mogą w niektórych przypadkach zawodzić i wymagać pewnych poprawek. Przejrzałem je wszystkie (i kilka dodatkowych) w kolejności malejącej wiarygodności (moim zdaniem):
1. Porównywanie typów bezpośrednio przez ==(zaakceptowana odpowiedź).
Pomimo tego, że jest to akceptowana odpowiedź i ma najwięcej głosów pozytywnych, myślę, że ta metoda w ogóle nie powinna być stosowana. Ponieważ w rzeczywistości takie podejście jest odradzane w Pythonie, jak kilkakrotnie wspomniano tutaj .
Ale jeśli nadal chcesz go używać - powinni być świadomi pewnych specyficznych dtypes pandy jak pd.CategoricalDType, pd.PeriodDtypelub pd.IntervalDtype. Tutaj trzeba użyć extra type( ), aby poprawnie rozpoznać 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
Kolejnym zastrzeżeniem jest to, że należy dokładnie wskazać ten typ:
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()podejście.
Do tej pory nie wspomniano o tej metodzie w odpowiedziach.
Jeśli więc bezpośrednie porównywanie typów nie jest dobrym pomysłem - wypróbujmy w tym celu wbudowaną funkcję Pythona, a mianowicie - isinstance().
To zawodzi dopiero na początku, ponieważ zakłada, że mamy jakieś obiekty, ale pd.Serieslub pd.DataFramemogą być używane jako puste pojemniki z predefiniowanymi, dtypeale bez obiektów:
s = pd.Series([], dtype=bool)
s
>>> Series([], dtype: bool)
Ale jeśli ktoś w jakiś sposób przezwycięży ten problem i chce uzyskać dostęp do każdego obiektu, na przykład w pierwszym rzędzie i sprawdza jego typ w ten sposób:
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')
Będzie to mylące w przypadku mieszanego rodzaju danych w jednej kolumnie:
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')
I wreszcie - ta metoda nie może bezpośrednio rozpoznać typu Category. Jak stwierdzono w dokumentach :
Zwrócenie pojedynczego elementu z danych kategorycznych również zwróci wartość, a nie kategorię o długości „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')
Więc ta metoda jest również prawie nie do zastosowania.
3. df.dtype.kindpodejście.
Ta metoda może jednak działać z pustą pd.Serieslub pd.DataFramesma inne problemy.
Po pierwsze - nie jest w stanie rozróżnić niektórych typów:
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
Po drugie, co właściwie nadal jest dla mnie niejasne, powraca nawet w niektórych typach Brak .
4. df.select_dtypespodejście.
To jest prawie to, czego chcemy. Ta metoda została zaprojektowana w pandach, więc obsługuje większość wspomnianych wcześniej przypadków narożnych - puste ramki DataFrames, dobrze różni dtypy specyficzne dla numpy lub pandy. Działa dobrze z pojedynczym typem, takim jak .select_dtypes('bool'). Może służyć nawet do wybierania grup kolumn na podstawie 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')
W ten sposób, jak stwierdzono w dokumentach :
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
Można pomyśleć, że tutaj widzimy pierwsze nieoczekiwane (jak dla mnie było: pytanie ) wyniki - TimeDeltasą uwzględniane w wynikach DataFrame. Ale jak odpowiedziałem przeciwnie, powinno tak być, ale trzeba być tego świadomym. Zauważ, że booldtype jest pomijany, co może być również niepożądane dla kogoś, ale jest to spowodowane booli numberznajduje się w różnych „ poddrzewach ” numpy dtypes. W przypadku bool możemy użyć test.select_dtypes(['bool'])tutaj.
Następnym ograniczeniem tej metody jest to, że dla aktualnej wersji pand (0.24.2) ten kod: test.select_dtypes('period')podniesie NotImplementedError.
Inną rzeczą jest to, że nie jest w stanie odróżnić ciągów od innych obiektów:
test.select_dtypes('object')
>>> str obj
>>> 0 s1 [1, 2, 3]
>>> 1 s2 [5435, 35, -52, 14]
Ale to jest po pierwsze - już wspomniane w dokumentacji. Po drugie - to nie problem tej metody, a raczej sposób, w jaki przechowywane są łańcuchy DataFrame. Ale w każdym razie ten przypadek musi mieć trochę przetwarzania końcowego.
5. df.api.types.is_XXX_dtypepodejście.
Ten ma być najbardziej niezawodnym i natywnym sposobem na rozpoznanie typu (ścieżka modułu, w którym znajdują się funkcje, mówi sama o sobie), jak przypuszczam. I działa prawie idealnie, ale wciąż ma co najmniej jedno zastrzeżenie i nadal trzeba jakoś rozróżniać kolumny ciągów .
Poza tym może to być subiektywne, ale podejście to ma również bardziej „zrozumiałe dla człowieka” numberprzetwarzanie grupowe typów w porównaniu z .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
Nie timedeltai booljest wliczony w cenę. Idealny.
Mój potok wykorzystuje dokładnie tę funkcjonalność w tej chwili, a także trochę przetwarzania ręcznego.
Wynik.
Mam nadzieję, że udało mi się przedstawić główną argumentację - że wszystkie omówione podejścia można wykorzystać, ale tylko pd.DataFrame.select_dtypes()i pd.api.types.is_XXX_dtypenależy je traktować jako mające zastosowanie.
stringnie jest typem