NumPy cách
Dưới đây là một NumPy cách vectorized sử dụng advanced indexing
-
# Extract array data
In [10]: a = df.values
# Get integer based column IDs
In [11]: col_idx = np.searchsorted(df.columns, columns_to_select)
# Use NumPy's advanced indexing to extract relevant elem per row
In [12]: a[np.arange(len(col_idx)), col_idx]
Out[12]: array([ 10, 2, 3, 400])
Nếu tên cột của df
không sắp xếp, chúng ta cần phải sử dụng sorter
tranh cãi với np.searchsorted
. Mã này để trích xuất col_idx
cho ví dụ một generic df
sẽ là:
# https://stackoverflow.com/a/38489403/ @Divakar
def column_index(df, query_cols):
cols = df.columns.values
sidx = np.argsort(cols)
return sidx[np.searchsorted(cols,query_cols,sorter=sidx)]
Vì vậy, col_idx
sẽ thu được như vậy -
col_idx = column_index(df, columns_to_select)
Tiếp tục tối ưu hóa
Profiling nó tiết lộ rằng nút cổ chai đã xử lý các chuỗi với np.searchsorted
, điểm yếu NumPy thông thường không quá lớn với các chuỗi. Vì vậy, để khắc phục điều đó và sử dụng trường hợp đặc biệt của các tên cột là các chữ cái đơn, chúng ta có thể nhanh chóng chuyển đổi chúng thành các chữ số và sau đó chuyển chúng thành searchsorted
để xử lý nhanh hơn nhiều.
Do đó, một phiên bản được tối ưu hóa để nhận các ID cột số nguyên dựa, cho trường hợp các tên cột là chữ duy nhất và được sắp xếp, sẽ là -
def column_index_singlechar_sorted(df, query_cols):
c0 = np.fromstring(''.join(df.columns), dtype=np.uint8)
c1 = np.fromstring(''.join(query_cols), dtype=np.uint8)
return np.searchsorted(c0, c1)
này, cho chúng ta một phiên bản sửa đổi của giải pháp , như vậy -
Thời gian -
In [149]: # Setup df with 26 uppercase column letters and many rows
...: import string
...: df = pd.DataFrame(np.random.randint(0,9,(1000000,26)))
...: s = list(string.uppercase[:df.shape[1]])
...: df.columns = s
...: idx = np.random.randint(0,df.shape[1],len(df))
...: columns_to_select = np.take(s, idx).tolist()
# With df.lookup from @MaxU's soln
In [150]: %timeit pd.Series(df.lookup(df.index, columns_to_select))
10 loops, best of 3: 76.7 ms per loop
# With proposed one from this soln
In [151]: %%timeit
...: a = df.values
...: col_idx = column_index_singlechar_sorted(df, columns_to_select)
...: out = pd.Series(a[np.arange(len(col_idx)), col_idx])
10 loops, best of 3: 59 ms per loop
cho rằng df.lookup
giải quyết cho một trường hợp chung chung, đó có thể là một lựa chọn tốt hơn, nhưng tối ưu hóa khác có thể được hiển thị trong bài đăng này cũng có thể hữu ích!
một giây phía sau bạn. ;-) – Wen
@Wen, vâng, tôi biết cảm giác này - xin lỗi :) – MaxU
@MaxU Đây chính xác là những gì tôi đang tìm kiếm. Cảm ơn bạn! –