2014-12-22 19 views
8

Hãy thử điều này cho chính mình:Tại sao DataFrame.loc [[1]] chậm hơn 1,800x so với df.ix [[1]] và 3,500x so với df.loc [1]?

import pandas as pd 
s=pd.Series(xrange(5000000)) 
%timeit s.loc[[0]] # You need pandas 0.15.1 or newer for it to be that slow 
1 loops, best of 3: 445 ms per loop 

Cập nhật: đó là a legitimate bug in pandas rằng có lẽ đã được giới thiệu trong 0.15.1 vào tháng năm 2014 hoặc lâu hơn. Giải pháp thay thế: chờ bản phát hành mới trong khi sử dụng phiên bản cũ của gấu trúc; có được một nhà phát triển tiên tiến. phiên bản từ github; tự sửa đổi một dòng trong bản phát hành pandas; tạm thời sử dụng .ix thay vì .loc.

Tôi có một DataFrame với 4,8 triệu hàng, và chọn một hàng duy nhất sử dụng .iloc[[ id ]] (với một danh sách phần tử đơn) mất 489 mili giây, gần như nửa giây, chậm hơn so với các giống .ix[[ id ]] 1,800x lần, và 3.500 lần chậm hơn.iloc[id] (chuyển id dưới dạng giá trị, không phải dưới dạng danh sách). Để công bằng, .loc[list] mất khoảng thời gian đó bất kể độ dài của danh sách nhưng tôi không muốn chi tiêu 489 ms trên đó, đặc biệt là khi .ix nhanh hơn hàng nghìn lần và tạo kết quả giống nhau. Đó là sự hiểu biết của tôi rằng .ix được cho là chậm hơn, phải không?

Tôi đang sử dụng gấu trúc 0,15,1. Hướng dẫn tuyệt vời trên Indexing and Selecting Data gợi ý rằng .ix bằng cách nào đó tổng quát hơn và có lẽ chậm hơn, so với .loc.iloc. Cụ thể, nó cho biết

Tuy nhiên, khi trục là số nguyên, truy cập dựa trên nhãn duy nhất và không hỗ trợ truy cập vị trí. Do đó, trong các trường hợp như vậy, thường là tốt hơn để rõ ràng và sử dụng .iloc hoặc .loc.

Dưới đây là một phiên ipython với các tiêu chuẩn:

print 'The dataframe has %d entries, indexed by integers that are less than %d' % (len(df), max(df.index)+1) 
    print 'df.index begins with ', df.index[:20] 
    print 'The index is sorted:', df.index.tolist()==sorted(df.index.tolist()) 

    # First extract one element directly. Expected result, no issues here. 
    id=5965356 
    print 'Extract one element with id %d' % id 
    %timeit df.loc[id] 
    %timeit df.ix[id] 
    print hash(str(df.loc[id])) == hash(str(df.ix[id])) # check we get the same result 

    # Now extract this one element as a list. 
    %timeit df.loc[[id]] # SO SLOW. 489 ms vs 270 microseconds for .ix, or 139 microseconds for .loc[id] 
    %timeit df.ix[[id]] 
    print hash(str(df.loc[[id]])) == hash(str(df.ix[[id]])) # this one should be True 
    # Let's double-check that in this case .ix is the same as .loc, not .iloc, 
    # as this would explain the difference. 
    try: 
     print hash(str(df.iloc[[id]])) == hash(str(df.ix[[id]])) 
    except: 
     print 'Indeed, %d is not even a valid iloc[] value, as there are only %d rows' % (id, len(df)) 

    # Finally, for the sake of completeness, let's take a look at iloc 
    %timeit df.iloc[3456789] # this is still 100+ times faster than the next version 
    %timeit df.iloc[[3456789]] 

Output:

The dataframe has 4826616 entries, indexed by integers that are less than 6177817 
df.index begins with Int64Index([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], dtype='int64') 
The index is sorted: True 
Extract one element with id 5965356 
10000 loops, best of 3: 139 µs per loop 
10000 loops, best of 3: 141 µs per loop 
True 
1 loops, best of 3: 489 ms per loop 
1000 loops, best of 3: 270 µs per loop 
True 
Indeed, 5965356 is not even a valid iloc[] value, as there are only 4826616 rows 
10000 loops, best of 3: 98.9 µs per loop 
100 loops, best of 3: 12 ms per loop 
+0

Lưu ý rằng việc sử dụng '[[id]]' và '[id]' không tương đương. '[id]' sẽ trả về một chuỗi, nhưng '[[id]]' sẽ trả về một DataFrame một hàng. – BrenBarn

+0

@BrenBarn, vâng, điều này giải thích sự khác biệt cho '.ix': 141 µs so với 270 µs. Nhưng tại sao '.loc [[id]]' quá chậm? – osa

Trả lời

6

Hình như vấn đề này đã không có mặt trong gấu trúc 0.14. Tôi đã lược tả nó với line_profiler và tôi nghĩ rằng tôi biết điều gì đã xảy ra. Kể từ khi gấu trúc 0.15.1, một KeyError hiện được nâng lên nếu chỉ mục đã cho không có. Có vẻ như khi bạn đang sử dụng cú pháp .loc[list], nó đang thực hiện tìm kiếm toàn diện cho một chỉ mục dọc theo toàn bộ trục, ngay cả khi nó đã được tìm thấy. Tức là, trước tiên, không có chấm dứt sớm trong trường hợp một phần tử được tìm thấy và, thứ hai, tìm kiếm trong trường hợp này là sức mạnh vũ phu.

File: .../anaconda/lib/python2.7/site-packages/pandas/core/indexing.py,

1278              # require at least 1 element in the index 
    1279   1   241 241.0  0.1    idx = _ensure_index(key) 
    1280   1  391040 391040.0  99.9    if len(idx) and not idx.isin(ax).any(): 
    1281           
    1282               raise KeyError("None of [%s] are in the [%s]" % 
4

Pandas indexing là điên chậm, tôi chuyển sang NumPy indexing

df=pd.DataFrame(some_content) 
# takes forever!! 
for iPer in np.arange(-df.shape[0],0,1): 
    x = df.iloc[iPer,:].values 
    y = df.iloc[-1,:].values 
# fast!   
vals = np.matrix(df.values) 
for iPer in np.arange(-vals.shape[0],0,1): 
    x = vals[iPer,:] 
    y = vals[-1,:] 
Các vấn đề liên quan