Lựa chọn với tiêu chí phức tạp từ pandas.DataFrame


234

Ví dụ tôi có DF đơn giản:

import pandas as pd
from random import randint

df = pd.DataFrame({'A': [randint(1, 9) for x in xrange(10)],
                   'B': [randint(1, 9)*10 for x in xrange(10)],
                   'C': [randint(1, 9)*100 for x in xrange(10)]})

Tôi có thể chọn các giá trị từ 'A' trong đó các giá trị tương ứng cho 'B' sẽ lớn hơn 50 và cho 'C' - không bằng 900, sử dụng các phương thức và thành ngữ của Pandas không?


df.querypd.evalcó vẻ như phù hợp với trường hợp sử dụng này. Để biết thông tin về pd.eval()họ các hàm, tính năng và trường hợp sử dụng của chúng, vui lòng truy cập Đánh giá biểu thức động trong gấu trúc bằng pd.eval () .
cs95

Cũng có thể kiểm tra câu trả lời của @Gecko trong: stackoverflow.com/questions/13611065/iêu
Nicholas Humphrey

Câu trả lời:


390

Chắc chắn rồi! Thiết lập:

>>> import pandas as pd
>>> from random import randint
>>> df = pd.DataFrame({'A': [randint(1, 9) for x in range(10)],
                   'B': [randint(1, 9)*10 for x in range(10)],
                   'C': [randint(1, 9)*100 for x in range(10)]})
>>> df
   A   B    C
0  9  40  300
1  9  70  700
2  5  70  900
3  8  80  900
4  7  50  200
5  9  30  900
6  2  80  700
7  2  80  400
8  5  80  300
9  7  70  800

Chúng ta có thể áp dụng các hoạt động cột và nhận các đối tượng Sê-ri boolean:

>>> df["B"] > 50
0    False
1     True
2     True
3     True
4    False
5    False
6     True
7     True
8     True
9     True
Name: B
>>> (df["B"] > 50) & (df["C"] == 900)
0    False
1    False
2     True
3     True
4    False
5    False
6    False
7    False
8    False
9    False

[Cập nhật, để chuyển sang kiểu mới .loc]:

Và sau đó chúng ta có thể sử dụng chúng để lập chỉ mục vào đối tượng. Để truy cập đọc, bạn có thể xâu chuỗi các chỉ số:

>>> df["A"][(df["B"] > 50) & (df["C"] == 900)]
2    5
3    8
Name: A, dtype: int64

nhưng bạn có thể gặp rắc rối vì sự khác biệt giữa chế độ xem và bản sao thực hiện việc này để truy cập ghi. Bạn có thể sử dụng .locthay thế:

>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"]
2    5
3    8
Name: A, dtype: int64
>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"].values
array([5, 8], dtype=int64)
>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"] *= 1000
>>> df
      A   B    C
0     9  40  300
1     9  70  700
2  5000  70  900
3  8000  80  900
4     7  50  200
5     9  30  900
6     2  80  700
7     2  80  400
8     5  80  300
9     7  70  800

Lưu ý rằng tôi đã vô tình gõ == 900và không != 900, hoặc ~(df["C"] == 900), nhưng tôi quá lười để sửa nó. Bài tập cho người đọc. : ^)


5
Về .loccập nhật - sẽ tốt hơn nếu bạn làm rõ nơi chúng tôi nhận được một bản sao và nơi xem.
Gill Bates

3
có thể lọc một khung dữ liệu gấu trúc và sử dụng toán tử OR. Ví dụ: nếu có một tháng cột, bạn có thể nói df = data ['tháng' == JAN HOẶC 'tháng' == FEB] không? Và có thể bao gồm một cột thứ hai làm cho truy vấn trở nên phức tạp hơn, newdf trong đó col_month = jan HOẶC feb AND col_day = MONDAY hoặc WENDNESDAY
yoshiserry

7
@yoshiserry: vui lòng hỏi như một câu hỏi riêng biệt. Không ai sẽ thấy nó ở đây trong các ý kiến ​​về một câu trả lời cũ.
DSM

2
Đừng quên các dấu ngoặc đơn - bạn sẽ gặp các lỗi lạ như{TypeError}cannot compare a dtyped [int64] array with a scalar of type [bool]
Mr_and_Mrs_D

Việc sử dụng dấu ngoặc đơn này có dẫn đến các phép tính trong toàn bộ chuỗi không? Điều gì xảy ra nếu chúng ta muốn tập hợp con nhiều lần cho hiệu quả?
ifly6

56

Một giải pháp khác là sử dụng phương thức truy vấn :

import pandas as pd

from random import randint
df = pd.DataFrame({'A': [randint(1, 9) for x in xrange(10)],
                   'B': [randint(1, 9) * 10 for x in xrange(10)],
                   'C': [randint(1, 9) * 100 for x in xrange(10)]})
print df

   A   B    C
0  7  20  300
1  7  80  700
2  4  90  100
3  4  30  900
4  7  80  200
5  7  60  800
6  3  80  900
7  9  40  100
8  6  40  100
9  3  10  600

print df.query('B > 50 and C != 900')

   A   B    C
1  7  80  700
2  4  90  100
4  7  80  200
5  7  60  800

Bây giờ nếu bạn muốn thay đổi các giá trị được trả về trong cột A, bạn có thể lưu chỉ mục của chúng:

my_query_index = df.query('B > 50 & C != 900').index

.... và sử dụng .ilocđể thay đổi chúng tức là:

df.iloc[my_query_index, 0] = 5000

print df

      A   B    C
0     7  20  300
1  5000  80  700
2  5000  90  100
3     4  30  900
4  5000  80  200
5  5000  60  800
6     3  80  900
7     9  40  100
8     6  40  100
9     3  10  600

12

Và nhớ sử dụng dấu ngoặc đơn!

Hãy nhớ rằng &toán tử được ưu tiên hơn các toán tử như >hoặc <vv. Đó là lý do tại sao

4 < 5 & 6 > 4

đánh giá để False. Do đó, nếu bạn đang sử dụng pd.loc, bạn cần đặt dấu ngoặc quanh các câu lệnh logic của mình, nếu không bạn sẽ gặp lỗi. Đó là lý do tại sao:

df.loc[(df['A'] > 10) & (df['B'] < 15)]

thay vì

df.loc[df['A'] > 10 & df['B'] < 15]

mà sẽ dẫn đến

TypeError: không thể so sánh một mảng [float64] đã bị loại bỏ với một vô hướng loại [bool]


3

Bạn có thể sử dụng gấu trúc nó có một số chức năng được xây dựng để so sánh. Vì vậy, nếu bạn muốn chọn các giá trị của "A" được đáp ứng bởi các điều kiện của "B" và "C" (giả sử bạn muốn quay lại một đối tượng gấu trúc DataFrame)

df[['A']][df.B.gt(50) & df.C.ne(900)]

df[['A']] sẽ cung cấp cho bạn cột A ở định dạng DataFrame.

Hàm 'gt' của gấu trúc sẽ trả về các vị trí của cột B lớn hơn 50 và 'ne' sẽ trả về các vị trí không bằng 900.

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.