cách kiểm tra loại cột trong trăn gấu trúc


133

Tôi cần sử dụng các hàm khác nhau để xử lý cột số và cột chuỗi. Những gì tôi đang làm bây giờ thực sự ngớ ngẩn:

allc = list((agg.loc[:, (agg.dtypes==np.float64)|(agg.dtypes==np.int)]).columns)
for y in allc:
    treat_numeric(agg[y])    

allc = list((agg.loc[:, (agg.dtypes!=np.float64)&(agg.dtypes!=np.int)]).columns)
for y in allc:
    treat_str(agg[y])    

Có cách nào thanh lịch hơn để làm điều này không? Ví dụ

for y in agg.columns:
    if(dtype(agg[y]) == 'string'):
          treat_str(agg[y])
    elif(dtype(agg[y]) != 'string'):
          treat_numeric(agg[y])

2
stringkhông phải là một dtype
David Robinson

Câu trả lời:


124

Bạn có thể truy cập kiểu dữ liệu của một cột bằng dtype:

for y in agg.columns:
    if(agg[y].dtype == np.float64 or agg[y].dtype == np.int64):
          treat_numeric(agg[y])
    else:
          treat_str(agg[y])

1
Xin chào David, Bạn có thể nhận xét tại sao bạn bao gồm == np.float64 không? Không phải chúng ta đang cố gắng chuyển đổi thành float sao? Cảm ơn.
Ryan Chase

@RyanChase OP trong câu hỏi này chưa bao giờ nói rằng anh ấy đang chuyển đổi thành float, anh ấy chỉ cần biết có nên sử dụng một hàm (không xác định) hay không treat_numeric. Vì anh ấy bao gồm agg.dtypes==np.float64như một lựa chọn, tôi cũng vậy.
David Robinson

3
Có nhiều loại số nhiều trong NumPy hơn hai này, tất cả mọi thứ dưới numberđây: docs.scipy.org/doc/numpy-1.13.0/reference/arrays.scalars.html Các giải pháp chung làis_numeric_dtype(agg[y])
Attila Tanyi

96

Trong pandas 0.20.2bạn có thể làm:

from pandas.api.types import is_string_dtype
from pandas.api.types import is_numeric_dtype

is_string_dtype(df['A'])
>>>> True

is_numeric_dtype(df['B'])
>>>> True

Vì vậy, mã của bạn trở thành:

for y in agg.columns:
    if (is_string_dtype(agg[y])):
        treat_str(agg[y])
    elif (is_numeric_dtype(agg[y])):
        treat_numeric(agg[y])

1
Có bất kỳ thay thế nào cho các phiên bản gấu trúc cũ hơn không? Tôi gặp lỗi: Không có mô-đun nào có tên api.types.
rph

2
pandas.core.common.is_numeric_dtypeđã tồn tại kể từ Pandas 0,13 và nó cũng làm điều tương tự, nhưng nó không được chấp nhận nữa để có lợi cho pandas.api.types.is_numeric_dtype0,19, tôi nghĩ
Migwell

Đó là câu trả lời bản địa nhất. Nhưng người ta nên biết một số lưu ý ở đây.
BeforeFlight

46

Tôi biết đây là một chủ đề hơi cũ nhưng với pandas 19.02, bạn có thể làm:

df.select_dtypes(include=['float64']).apply(your_function)
df.select_dtypes(exclude=['string','object']).apply(your_other_function)

http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.select_dtypes.html


1
câu trả lời tốt mà tôi có thể sẽ làm include[np.number](bao gồm cả int và 32 bit float) cho dòng đầu tiên và exclude[object]cho dòng thứ hai. Chuỗi là các đối tượng liên quan đến loại dtypes. Trên thực tế, việc bao gồm 'chuỗi' với đối tượng khiến tôi gặp lỗi.
JohnE

1
dường như "string" không được hỗ trợ nữa, "object" phải được sử dụng thay thế. Nhưng chắc chắn là câu trả lời đúng :)
Bertrand

Cũng cần lưu ý rằng 'period'dtype hiện đang được nuôi dưỡng NotImplementedError(gấu trúc 0,24.2). Vì vậy, một người có thể cần một số xử lý bài thủ công.
BeforeFlight

21

Tiêu đề câu hỏi được hỏi là chung chung, nhưng trường hợp sử dụng của tác giả nêu trong nội dung câu hỏi là cụ thể. Vì vậy, bất kỳ câu trả lời nào khác có thể được sử dụng.

Nhưng để trả lời đầy đủ câu hỏi tiêu đề , cần làm rõ rằng có vẻ như tất cả các cách tiếp cận có thể thất bại trong một số trường hợp và yêu cầu một số công việc lại. Tôi đã xem xét tất cả chúng (và một số bổ sung) theo thứ tự giảm dần độ tin cậy (theo ý kiến ​​của tôi):

1. So sánh các loại trực tiếp qua ==(câu trả lời được chấp nhận).

Mặc dù thực tế rằng đây là câu trả lời được chấp nhận và có hầu hết số phiếu ủng hộ, tôi nghĩ rằng phương pháp này hoàn toàn không nên được sử dụng. Vì trên thực tế cách làm này không được khuyến khích ở python như đã nói nhiều lần ở đây .
Nhưng nếu ta vẫn muốn sử dụng nó - nên lưu ý một số dtypes gấu trúc cụ thể như pd.CategoricalDType, pd.PeriodDtypehoặc pd.IntervalDtype. Ở đây người ta phải sử dụng thêm type( )để nhận ra dtype một cách chính xác:

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

Một lưu ý khác ở đây là loại đó nên được chỉ ra một cách chính xác:

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()cách tiếp cận.

Phương pháp này vẫn chưa được đề cập trong các câu trả lời cho đến nay.

Vì vậy, nếu so sánh trực tiếp các kiểu không phải là một ý tưởng hay - hãy thử hàm python tích hợp sẵn cho mục đích này, cụ thể là - isinstance().
Nó không thành công ngay từ đầu, bởi vì giả định rằng chúng ta có một số đối tượng, nhưng pd.Serieshoặc pd.DataFramecó thể được sử dụng chỉ như các vùng chứa rỗng với định sẵn dtypenhưng không có đối tượng nào trong đó:

s = pd.Series([], dtype=bool)
s

>>> Series([], dtype: bool)

Nhưng nếu ai đó bằng cách nào đó khắc phục được vấn đề này và muốn truy cập vào từng đối tượng, chẳng hạn như ở hàng đầu tiên và kiểm tra loại dtype của nó như một cái gì đó tương tự:

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')

Nó sẽ gây hiểu nhầm trong trường hợp loại dữ liệu hỗn hợp trong một cột:

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')

Và cuối cùng nhưng không kém phần quan trọng - phương pháp này không thể trực tiếp nhận dạng Categorydtype. Như đã nêu trong tài liệu :

Việc trả lại một mục từ dữ liệu phân loại cũng sẽ trả về giá trị, không phải là một phân loại có độ dài “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')

Vì vậy phương pháp này cũng gần như không thể áp dụng được.

3. df.dtype.kindcách tiếp cận.

Phương pháp này có thể hoạt động với trống pd.Serieshoặc pd.DataFramesnhưng có vấn đề khác.

Đầu tiên - nó không thể khác biệt một số kiểu:

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

Thứ hai, điều gì thực sự vẫn chưa rõ ràng đối với tôi, nó thậm chí còn trả về trên một số loại Không có .

4. df.select_dtypescách tiếp cận.

Đây gần như là những gì chúng tôi muốn. Phương pháp này được thiết kế bên trong gấu trúc để nó xử lý hầu hết các trường hợp góc được đề cập trước đó - DataFrames trống, khác với các kiểu dtype đặc trưng cho gấu trúc hoặc không rõ ràng. Nó hoạt động tốt với loại đơn như .select_dtypes('bool'). Nó có thể được sử dụng ngay cả để chọn nhóm cột dựa trên loại:

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')

Như vậy, như đã nêu trong tài liệu :

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 có thể nghĩ rằng ở đây chúng ta thấy kết quả bất ngờ đầu tiên (thường là đối với tôi: câu hỏi ) - TimeDeltađược đưa vào đầu ra DataFrame. Nhưng như đã trả lời ngược lại, nó phải là như vậy, nhưng người ta phải nhận thức được nó. Lưu ý rằng booldtype bị bỏ qua, điều đó cũng có thể không mong muốn đối với một người nào đó, nhưng nó do boolnumbernằm trong các " cây con " khác nhau của các loại numpy. Trong trường hợp với bool, chúng tôi có thể sử dụng test.select_dtypes(['bool'])ở đây.

Hạn chế tiếp theo của phương pháp này là đối với phiên bản hiện tại của gấu trúc (0.24.2), mã này: test.select_dtypes('period')sẽ tăng lên NotImplementedError.

Và một điều nữa là nó không thể khác các chuỗi với các đối tượng khác:

test.select_dtypes('object')

>>>     str     obj
>>> 0    s1     [1, 2, 3]
>>> 1    s2     [5435, 35, -52, 14]

Nhưng điều này, trước tiên - đã được đề cập trong tài liệu. Và thứ hai - không phải là vấn đề của phương pháp này, mà là cách các chuỗi được lưu trữ trong đó DataFrame. Nhưng dù sao trường hợp này cũng phải có một số bài xử lý.

5. df.api.types.is_XXX_dtypecách tiếp cận.

Điều này được dự định là cách mạnh mẽ nhất và nguyên bản để đạt được nhận dạng dtype (đường dẫn của mô-đun nơi các hàm cư trú tự nó nói) như tôi cho là vậy. Và nó hoạt động gần như hoàn hảo, nhưng vẫn có ít nhất một cảnh báo và bằng cách nào đó vẫn phải phân biệt các cột chuỗi .

Bên cạnh đó, điều này có thể là chủ quan, nhưng cách tiếp cận này cũng có nhiều numberxử lý nhóm kiểu 'con người có thể hiểu được' hơn so với .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

Không timedeltaboolđược bao gồm. Hoàn hảo.

Đường dẫn của tôi khai thác chính xác chức năng này tại thời điểm này, cộng với một chút xử lý bài đăng.

Đầu ra.

Hy vọng tôi có thể lập luận về điểm chính - rằng tất cả các phương pháp đã thảo luận có thể được sử dụng, nhưng chỉ pd.DataFrame.select_dtypes()pd.api.types.is_XXX_dtypenên được thực sự coi là những phương pháp có thể áp dụng.


1
Câu trả lời tuyệt vời và công thức tốt. :-)
Oliver

8

Nếu bạn muốn đánh dấu loại cột khung dữ liệu là một chuỗi, bạn có thể thực hiện:

df['A'].dtype.kind

Một ví dụ:

In [8]: df = pd.DataFrame([[1,'a',1.2],[2,'b',2.3]])
In [9]: df[0].dtype.kind, df[1].dtype.kind, df[2].dtype.kind
Out[9]: ('i', 'O', 'f')

Câu trả lời cho mã của bạn:

for y in agg.columns:
    if(agg[y].dtype.kind == 'f' or agg[y].dtype.kind == 'i'):
          treat_numeric(agg[y])
    else:
          treat_str(agg[y])

4

Để in đẹp các kiểu dữ liệu cột

Ví dụ: để kiểm tra các kiểu dữ liệu sau khi nhập từ một tệp

def printColumnInfo(df):
    template="%-8s %-30s %s"
    print(template % ("Type", "Column Name", "Example Value"))
    print("-"*53)
    for c in df.columns:
        print(template % (df[c].dtype, c, df[c].iloc[1]) )

Đầu ra minh họa:

Type     Column Name                    Example Value
-----------------------------------------------------
int64    Age                            49
object   Attrition                      No
object   BusinessTravel                 Travel_Frequently
float64  DailyRate                      279.0
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.