Gấu trúc thay thế có điều kiện


123

Tôi có DataFrame và tôi muốn thay thế các giá trị trong một cột cụ thể vượt quá giá trị bằng 0. Tôi đã nghĩ rằng đây là một cách để đạt được điều này:

df[df.my_channel > 20000].my_channel = 0

Nếu tôi sao chép kênh vào một khung dữ liệu mới thì rất đơn giản:

df2 = df.my_channel 

df2[df2 > 20000] = 0

Điều này thực hiện chính xác những gì tôi muốn, nhưng dường như không hoạt động với kênh như một phần của DataFrame ban đầu.


Tìm thấy những gì tôi nghĩ bạn đang tìm kiếm ở đây .
feetwet

Câu trả lời:


181

.ixtrình lập chỉ mục hoạt động tốt cho phiên bản gấu trúc trước 0.20.0, nhưng vì pandas 0.20.0, trình .ixlập chỉ mục không được dùng nữa , vì vậy bạn nên tránh sử dụng nó. Thay vào đó, bạn có thể sử dụng .lochoặc lập ilocchỉ mục. Bạn có thể giải quyết vấn đề này bằng cách:

mask = df.my_channel > 20000
column_name = 'my_channel'
df.loc[mask, column_name] = 0

Hoặc, trong một dòng,

df.loc[df.my_channel > 20000, 'my_channel'] = 0

maskgiúp bạn lựa chọn các hàng trong đó df.my_channel > 20000True, trong khi df.loc[mask, column_name] = 0bộ giá trị từ 0 đến các hàng chọn nơi maskgiữ trong cột đó tên là column_name.

Cập nhật: Trong trường hợp này, bạn nên sử dụng locvì nếu bạn sử dụng iloc, bạn sẽ nhận được thông báo NotImplementedErrorrằng lập chỉ mục boolean dựa trên iLocation trên một kiểu số nguyên là không khả dụng .


81

Thử

df.loc[df.my_channel > 20000, 'my_channel'] = 0

Lưu ý: Kể từ phiên bản v0.20.0, ix đã không được chấp nhận thay vì loc/ iloc.


8
Cảm ơn bạn. Tôi cũng đã tìm thấy giải pháp của riêng mình, đó là: df.my_channel [df.my_channel> 20000] = 0
BMichell

2
@BMichell Tôi nghĩ rằng giải pháp của bạn có thể bắt đầu đưa ra cảnh báo cho bạn trong 0,13, chưa có cơ hội để thử
lowtech

lỗi năng suất: /opt/anaconda3/envs/python35/lib/python3.5/site-packages/ipykernel_launcher.py:1: SettingWithCopyWarning: Một giá trị đang cố gắng được đặt trên bản sao của một lát từ DataFrame Xem cảnh báo trong tài liệu: pandas.pydata.org/pandas-docs/stable/... "" "Entry điểm cho tung ra một kernel IPython.
Rutger Hofste

@RutgerHofste cảm ơn vì đã đề cập đến điều đó, nhưng một đối số khác không bao giờ sử dụng Python3
lowtech 10/1017

34

np.where chức năng hoạt động như sau:

df['X'] = np.where(df['Y']>=50, 'yes', 'no')

Trong trường hợp của bạn, bạn sẽ muốn:

import numpy as np
df['my_channel'] = np.where(df.my_channel > 20000, 0, df.my_channel)

19

Lý do khiến khung dữ liệu ban đầu của bạn không cập nhật là vì việc lập chỉ mục theo chuỗi có thể khiến bạn sửa đổi bản sao thay vì chế độ xem khung dữ liệu của bạn. Các tài liệu đưa ra lời khuyên này:

Khi thiết lập các giá trị trong một đối tượng gấu trúc, phải cẩn thận để tránh những gì được gọi là lập chỉ mục chuỗi.

Bạn có một số lựa chọn thay thế: -

loc + Lập chỉ mục Boolean

loc có thể được sử dụng để thiết lập giá trị và hỗ trợ mặt nạ Boolean:

df.loc[df['my_channel'] > 20000, 'my_channel'] = 0

mask + Lập chỉ mục Boolean

Bạn có thể chỉ định cho chuỗi của mình:

df['my_channel'] = df['my_channel'].mask(df['my_channel'] > 20000, 0)

Hoặc bạn có thể cập nhật chuỗi của mình tại chỗ:

df['my_channel'].mask(df['my_channel'] > 20000, 0, inplace=True)

np.where + Lập chỉ mục Boolean

Bạn có thể sử dụng NumPy bằng cách gán chuỗi ban đầu của mình khi điều kiện của bạn không được thỏa mãn; tuy nhiên, hai giải pháp đầu tiên sạch hơn vì chúng chỉ thay đổi rõ ràng các giá trị được chỉ định.

df['my_channel'] = np.where(df['my_channel'] > 20000, 0, df['my_channel'])

0

Tôi sẽ sử dụng lambdahàm trên Seriesmột DataFramenhư thế này:

f = lambda x: 0 if x>100 else 1
df['my_column'] = df['my_column'].map(f)

Tôi không khẳng định rằng đây là một cách hiệu quả, nhưng nó hoạt động tốt.


3
Điều này không hiệu quả và không được khuyến khích vì nó liên quan đến vòng lặp cấp Python trong một hoạt động khôn ngoan theo hàng.
jpp

Cảm ơn bạn, tôi đoán chúng ta có thể sử dụng locở đây, giống như df.loc[: , 'my_column'] = df['my_column'].map(f). Không biết có nhanh như các bạn bổ sung bên dưới không.
Ozkan Serttas

2
Không, vẫn chậm vì bạn vẫn đang vận hành theo hàng hơn là theo cột.
jpp

0

Thử cái này:

df.my_channel = df.my_channel.where(df.my_channel <= 20000, other= 0)

hoặc là

df.my_channel = df.my_channel.mask(df.my_channel > 20000, other= 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.