Có một số cách để chọn hàng từ khung dữ liệu gấu trúc:
- Lập chỉ mục Boolean (
df[df['col'] == value
])
- Lập chỉ mục vị trí (
df.iloc[...]
)
- Lập chỉ mục nhãn (
df.xs(...)
)
df.query(...)
API
Dưới đây tôi chỉ cho bạn ví dụ về từng ví dụ, với lời khuyên khi sử dụng các kỹ thuật nhất định. Giả sử tiêu chí của chúng tôi là cột 'A'
=='foo'
(Lưu ý về hiệu suất: Đối với mỗi loại cơ sở, chúng tôi có thể giữ mọi thứ đơn giản bằng cách sử dụng API gấu trúc hoặc chúng tôi có thể mạo hiểm bên ngoài API, thường vào numpy
và tăng tốc mọi thứ.)
Thiết lập
Điều đầu tiên chúng ta cần là xác định một điều kiện sẽ đóng vai trò là tiêu chí của chúng tôi để chọn hàng. Chúng ta sẽ bắt đầu với trường hợp của OP column_name == some_value
và bao gồm một số trường hợp sử dụng phổ biến khác.
Vay từ @unutbu:
import pandas as pd, numpy as np
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
'B': 'one one two three two two one three'.split(),
'C': np.arange(8), 'D': np.arange(8) * 2})
1. Lập chỉ mục Boolean
... Lập chỉ mục Boolean yêu cầu tìm giá trị thực của 'A'
cột của mỗi hàng bằng 'foo'
, sau đó sử dụng các giá trị thật đó để xác định hàng nào sẽ giữ. Thông thường, chúng tôi sẽ đặt tên cho loạt bài này, một loạt các giá trị thật , mask
. Chúng tôi sẽ làm như vậy ở đây là tốt.
mask = df['A'] == 'foo'
Sau đó chúng ta có thể sử dụng mặt nạ này để cắt hoặc lập chỉ mục khung dữ liệu
df[mask]
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Đây là một trong những cách đơn giản nhất để thực hiện nhiệm vụ này và nếu hiệu suất hoặc trực giác không phải là vấn đề, thì đây nên là phương pháp bạn chọn. Tuy nhiên, nếu hiệu suất là một mối quan tâm, thì bạn có thể muốn xem xét một cách khác để tạo mask
.
2. Lập chỉ mục vị trí
Lập chỉ mục vị trí ( df.iloc[...]
) có các trường hợp sử dụng, nhưng đây không phải là một trong số chúng. Để xác định vị trí cắt lát, trước tiên chúng ta cần thực hiện phân tích boolean tương tự mà chúng ta đã làm ở trên. Điều này khiến chúng tôi thực hiện thêm một bước để hoàn thành nhiệm vụ tương tự.
mask = df['A'] == 'foo'
pos = np.flatnonzero(mask)
df.iloc[pos]
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
3. Lập chỉ mục nhãn
Lập chỉ mục nhãn có thể rất tiện dụng, nhưng trong trường hợp này, chúng tôi lại làm nhiều việc hơn mà không có lợi
df.set_index('A', append=True, drop=False).xs('foo', level=1)
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
4. df.query()
API
pd.DataFrame.query
là một cách rất thanh lịch / trực quan để thực hiện nhiệm vụ này, nhưng thường chậm hơn. Tuy nhiên , nếu bạn chú ý đến thời gian bên dưới, đối với dữ liệu lớn, truy vấn rất hiệu quả. Hơn cả cách tiếp cận tiêu chuẩn và có độ lớn tương tự như gợi ý tốt nhất của tôi.
df.query('A == "foo"')
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Sở thích của tôi là sử dụng Boolean
mask
Cải tiến thực tế có thể được thực hiện bằng cách sửa đổi cách chúng tôi tạo ra Boolean
mask
.
mask
thay thế 1
Sử dụng numpy
mảng cơ bản và bỏ qua việc tạo ra một mảng khácpd.Series
mask = df['A'].values == 'foo'
Cuối cùng, tôi sẽ hiển thị các bài kiểm tra thời gian hoàn chỉnh hơn, nhưng hãy xem mức tăng hiệu suất mà chúng tôi có được bằng cách sử dụng khung dữ liệu mẫu. Đầu tiên, chúng tôi xem xét sự khác biệt trong việc tạo ramask
%timeit mask = df['A'].values == 'foo'
%timeit mask = df['A'] == 'foo'
5.84 µs ± 195 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
166 µs ± 4.45 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Đánh giá mask
với numpy
mảng nhanh hơn ~ 30 lần. Điều này một phần là do numpy
đánh giá thường nhanh hơn. Điều này cũng một phần do thiếu chi phí cần thiết để xây dựng một chỉ mục và một pd.Series
đối tượng tương ứng .
Tiếp theo, chúng ta sẽ xem xét thời gian để cắt với cái này mask
so với cái kia.
mask = df['A'].values == 'foo'
%timeit df[mask]
mask = df['A'] == 'foo'
%timeit df[mask]
219 µs ± 12.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
239 µs ± 7.03 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Hiệu suất đạt được không như phát âm. Chúng tôi sẽ xem nếu điều này giữ qua thử nghiệm mạnh mẽ hơn.
mask
thay thế 2
Chúng ta cũng có thể xây dựng lại khung dữ liệu. Có một sự cảnh báo lớn khi xây dựng lại một dataframe Bạn phải chăm sóc dtypes
khi làm như vậy!
Thay vì df[mask]
chúng tôi sẽ làm điều này
pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes)
Nếu khung dữ liệu là loại hỗn hợp, ví dụ của chúng tôi là, thì khi chúng tôi nhận được df.values
mảng kết quả là dtype
object
và do đó, tất cả các cột của khung dữ liệu mới sẽ là dtype
object
. Do đó đòi hỏi astype(df.dtypes)
và giết chết bất kỳ hiệu suất tiềm năng.
%timeit df[m]
%timeit pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes)
216 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
1.43 ms ± 39.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Tuy nhiên, nếu khung dữ liệu không phải là loại hỗn hợp, đây là một cách rất hữu ích để làm điều đó.
Được
np.random.seed([3,1415])
d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE'))
d1
A B C D E
0 0 2 7 3 8
1 7 0 6 8 6
2 0 2 0 4 9
3 7 3 2 4 3
4 3 6 7 7 4
5 5 3 7 5 9
6 8 7 6 4 7
7 6 2 6 6 5
8 2 8 7 5 8
9 4 7 6 1 5
%%timeit
mask = d1['A'].values == 7
d1[mask]
179 µs ± 8.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Đấu với
%%timeit
mask = d1['A'].values == 7
pd.DataFrame(d1.values[mask], d1.index[mask], d1.columns)
87 µs ± 5.12 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Chúng tôi cắt thời gian một nửa.
mask
thay thế 3
@unutbu cũng chỉ cho chúng tôi cách sử dụng pd.Series.isin
để tính toán cho từng yếu tố df['A']
tồn tại trong một tập hợp các giá trị. Điều này ước tính cho cùng một điều nếu tập hợp các giá trị của chúng tôi là một tập hợp của một giá trị, cụ thể là 'foo'
. Nhưng nó cũng khái quát để bao gồm các bộ giá trị lớn hơn nếu cần. Hóa ra, điều này vẫn còn khá nhanh mặc dù nó là một giải pháp tổng quát hơn. Sự mất mát thực sự duy nhất là ở trực giác cho những người không quen thuộc với khái niệm này.
mask = df['A'].isin(['foo'])
df[mask]
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Tuy nhiên, như trước đây, chúng ta có thể sử dụng numpy
để cải thiện hiệu suất trong khi hy sinh hầu như không có gì. Chúng tôi sẽ sử dụngnp.in1d
mask = np.in1d(df['A'].values, ['foo'])
df[mask]
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Thời gian
tôi sẽ bao gồm các khái niệm khác được đề cập trong các bài viết khác để tham khảo.
Mã dưới đây
Mỗi Cột trong bảng này biểu thị một khung dữ liệu có độ dài khác nhau mà chúng tôi kiểm tra từng chức năng. Mỗi cột hiển thị thời gian tương đối được thực hiện, với chức năng nhanh nhất được cung cấp một chỉ số cơ bản là 1.0
.
res.div(res.min())
10 30 100 300 1000 3000 10000 30000
mask_standard 2.156872 1.850663 2.034149 2.166312 2.164541 3.090372 2.981326 3.131151
mask_standard_loc 1.879035 1.782366 1.988823 2.338112 2.361391 3.036131 2.998112 2.990103
mask_with_values 1.010166 1.000000 1.005113 1.026363 1.028698 1.293741 1.007824 1.016919
mask_with_values_loc 1.196843 1.300228 1.000000 1.000000 1.038989 1.219233 1.037020 1.000000
query 4.997304 4.765554 5.934096 4.500559 2.997924 2.397013 1.680447 1.398190
xs_label 4.124597 4.272363 5.596152 4.295331 4.676591 5.710680 6.032809 8.950255
mask_with_isin 1.674055 1.679935 1.847972 1.724183 1.345111 1.405231 1.253554 1.264760
mask_with_in1d 1.000000 1.083807 1.220493 1.101929 1.000000 1.000000 1.000000 1.144175
Bạn sẽ nhận thấy rằng thời gian nhanh nhất dường như được chia sẻ giữa mask_with_values
vàmask_with_in1d
res.T.plot(loglog=True)
Chức năng
def mask_standard(df):
mask = df['A'] == 'foo'
return df[mask]
def mask_standard_loc(df):
mask = df['A'] == 'foo'
return df.loc[mask]
def mask_with_values(df):
mask = df['A'].values == 'foo'
return df[mask]
def mask_with_values_loc(df):
mask = df['A'].values == 'foo'
return df.loc[mask]
def query(df):
return df.query('A == "foo"')
def xs_label(df):
return df.set_index('A', append=True, drop=False).xs('foo', level=-1)
def mask_with_isin(df):
mask = df['A'].isin(['foo'])
return df[mask]
def mask_with_in1d(df):
mask = np.in1d(df['A'].values, ['foo'])
return df[mask]
Kiểm tra
res = pd.DataFrame(
index=[
'mask_standard', 'mask_standard_loc', 'mask_with_values', 'mask_with_values_loc',
'query', 'xs_label', 'mask_with_isin', 'mask_with_in1d'
],
columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
dtype=float
)
for j in res.columns:
d = pd.concat([df] * j, ignore_index=True)
for i in res.index:a
stmt = '{}(d)'.format(i)
setp = 'from __main__ import d, {}'.format(i)
res.at[i, j] = timeit(stmt, setp, number=50)
Thời gian đặc biệt
Nhìn vào trường hợp đặc biệt khi chúng ta có một đối tượng duy nhất dtype
cho toàn bộ khung dữ liệu.
Mã dưới đây
spec.div(spec.min())
10 30 100 300 1000 3000 10000 30000
mask_with_values 1.009030 1.000000 1.194276 1.000000 1.236892 1.095343 1.000000 1.000000
mask_with_in1d 1.104638 1.094524 1.156930 1.072094 1.000000 1.000000 1.040043 1.027100
reconstruct 1.000000 1.142838 1.000000 1.355440 1.650270 2.222181 2.294913 3.406735
Hóa ra, việc tái thiết không đáng để vượt qua vài trăm hàng.
spec.T.plot(loglog=True)
Chức năng
np.random.seed([3,1415])
d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE'))
def mask_with_values(df):
mask = df['A'].values == 'foo'
return df[mask]
def mask_with_in1d(df):
mask = np.in1d(df['A'].values, ['foo'])
return df[mask]
def reconstruct(df):
v = df.values
mask = np.in1d(df['A'].values, ['foo'])
return pd.DataFrame(v[mask], df.index[mask], df.columns)
spec = pd.DataFrame(
index=['mask_with_values', 'mask_with_in1d', 'reconstruct'],
columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
dtype=float
)
Kiểm tra
for j in spec.columns:
d = pd.concat([df] * j, ignore_index=True)
for i in spec.index:
stmt = '{}(d)'.format(i)
setp = 'from __main__ import d, {}'.format(i)
spec.at[i, j] = timeit(stmt, setp, number=50)