Panda Pengganti Bersyarat

123

Saya memiliki DataFrame, dan saya ingin mengganti nilai di kolom tertentu yang melebihi nilai dengan nol. Saya pikir ini adalah cara untuk mencapai ini:

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

Jika saya menyalin saluran ke dalam bingkai data baru, itu sederhana:

df2 = df.my_channel 

df2[df2 > 20000] = 0

Ini persis seperti yang saya inginkan, tetapi tampaknya tidak berfungsi dengan saluran sebagai bagian dari DataFrame asli.

BMichell
sumber
Menemukan apa yang menurut saya Anda cari di sini .
feetwet

Jawaban:

181

.ixpengindeks berfungsi dengan baik untuk versi pandas sebelum 0.20.0, tetapi karena pandas 0.20.0, .ixpengindeks tidak digunakan lagi , jadi Anda harus menghindari penggunaannya. Sebagai gantinya, Anda dapat menggunakan .locatau ilocpengindeks. Anda dapat mengatasi masalah ini dengan:

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

Atau, dalam satu baris,

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

maskmembantu Anda untuk memilih baris yang df.my_channel > 20000merupakan True, sedangkan df.loc[mask, column_name] = 0set nilai 0 ke baris yang dipilih mana maskmemegang di kolom yang namanya column_name.

Pembaruan: Dalam hal ini, Anda harus menggunakan lockarena jika Anda menggunakan iloc, Anda akan mendapatkan pemberitahuanNotImplementedError bahwa pengindeksan boolean berbasis iLocation pada tipe integer tidak tersedia .

lmiguelvargasf
sumber
82

Mencoba

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

Catatan: Sejak v0.20.0, ix sudah tidak digunakan lagi karena mendukung loc/ iloc.

teknologi rendah
sumber
8
Terima kasih. Saya juga menemukan solusi saya sendiri, yaitu: df.my_channel [df.my_channel> 20000] = 0
BMichell
2
@BMichell Saya pikir solusi Anda mungkin mulai memberi Anda peringatan di 0,13, belum memiliki kesempatan untuk mencoba
lowtech
kesalahan hasil: /opt/anaconda3/envs/python35/lib/python3.5/site-packages/ipykernel_launcher.py:1: SettingWithCopyWarning: Sebuah nilai mencoba untuk disetel pada salinan potongan dari DataFrame Lihat peringatan di dokumentasi: pandas.pydata.org/pandas-docs/stable/… "" "Titik masuk untuk meluncurkan kernel IPython.
Rutger Hofste
@RutgerHofste terima kasih telah menyebutkan itu, argumen lain tidak pernah menggunakan Python3
lowtech
34

np.where fungsi berfungsi sebagai berikut:

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

Dalam kasus Anda, Anda ingin:

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

Alasan bingkai data asli Anda tidak diperbarui adalah karena pengindeksan berantai dapat menyebabkan Anda mengubah salinan daripada tampilan bingkai data Anda. The docs memberikan nasihat ini:

Saat menetapkan nilai dalam objek pandas, kehati-hatian harus dilakukan untuk menghindari apa yang disebut pengindeksan berantai.

Anda memiliki beberapa alternatif: -

loc + Pengindeksan Boolean

loc dapat digunakan untuk menyetel nilai dan mendukung topeng Boolean:

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

mask + Pengindeksan Boolean

Anda dapat menetapkan ke seri Anda:

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

Atau Anda dapat memperbarui serial Anda di tempat:

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

np.where + Pengindeksan Boolean

Anda dapat menggunakan NumPy dengan menetapkan rangkaian asli Anda saat kondisi Anda tidak memuaskan; Namun, dua solusi pertama lebih bersih karena hanya mengubah nilai yang ditentukan secara eksplisit.

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

Saya akan menggunakan lambdafungsi pada Seriesa DataFrameseperti ini:

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

Saya tidak menegaskan bahwa ini adalah cara yang efisien, tetapi berfungsi dengan baik.

Ozkan Serttas
sumber
3
Ini tidak efisien dan tidak disarankan karena melibatkan loop level Python dalam operasi baris-bijaksana.
jpp
Terima kasih, saya kira kita bisa gunakan di locsini, seperti df.loc[: , 'my_column'] = df['my_column'].map(f). Saya tidak tahu apakah itu cepat seperti yang Anda tambahkan di bawah.
Ozkan Serttas
2
Tidak, masih lambat karena Anda masih beroperasi berdasarkan baris daripada kolom.
jpp
0

Coba ini:

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

atau

df.my_channel = df.my_channel.mask(df.my_channel > 20000, other= 0)

R. Shams
sumber