Bandingkan dua kolom menggunakan panda

110

Menggunakan ini sebagai titik awal:

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

Out[8]: 
  one  two three
0   10  1.2   4.2
1   15  70   0.03
2    8   5     0

Saya ingin menggunakan sesuatu seperti ifpernyataan di dalam panda.

if df['one'] >= df['two'] and df['one'] <= df['three']:
    df['que'] = df['one']

Pada dasarnya, periksa setiap baris melalui ifpernyataan, buat kolom baru.

Dokumen mengatakan untuk menggunakan .alltetapi tidak ada contoh ...

Merlin
sumber
Berapa nilai yang seharusnya jika ifpernyataan itu False?
Alex Riley
3
@Merlin: Jika Anda memiliki data numerik dalam kolom, sebaiknya jangan mencampurnya dengan string. Melakukannya akan mengubah jenis kolom menjadi object. Hal ini memungkinkan objek Python yang sewenang-wenang untuk disimpan di kolom, tetapi itu datang dengan biaya komputasi numerik yang lebih lambat. Jadi, jika kolom menyimpan data numerik, lebih disukai menggunakan NaN untuk bukan-bilangan.
unutbu
1
Memiliki bilangan bulat sebagai string dan mencoba untuk melakukan perbandingan pada mereka tampak aneh: a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]. Ini menciptakan hasil yang membingungkan dengan kode "benar": df['que'] = df['one'][(df['one'] >= df['two']) & (df['one'] <= df['three'])] hasil 10untuk baris pertama, sementara itu akan menghasilkan NaNjika masukan adalah bilangan bulat.
Primer

Jawaban:

153

Anda bisa menggunakan np.where . If condadalah array boolean, dan Adan Badalah array, maka

C = np.where(cond, A, B)

mendefinisikan C sama dengan Awhere condadalah True, dan Bwhere condis False.

import numpy as np
import pandas as pd

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

df['que'] = np.where((df['one'] >= df['two']) & (df['one'] <= df['three'])
                     , df['one'], np.nan)

hasil

  one  two three  que
0  10  1.2   4.2   10
1  15   70  0.03  NaN
2   8    5     0  NaN

Jika Anda memiliki lebih dari satu kondisi, maka Anda dapat menggunakan np.select . Misalnya, jika Anda ingin df['que']menyamakan df['two']kapan df['one'] < df['two'], maka

conditions = [
    (df['one'] >= df['two']) & (df['one'] <= df['three']), 
    df['one'] < df['two']]

choices = [df['one'], df['two']]

df['que'] = np.select(conditions, choices, default=np.nan)

hasil

  one  two three  que
0  10  1.2   4.2   10
1  15   70  0.03   70
2   8    5     0  NaN

Jika kita dapat mengasumsikan bahwa df['one'] >= df['two']when df['one'] < df['two']is False, maka kondisi dan pilihan dapat disederhanakan menjadi

conditions = [
    df['one'] < df['two'],
    df['one'] <= df['three']]

choices = [df['two'], df['one']]

(Asumsi tersebut mungkin tidak benar jika df['one']atau df['two']mengandung NaN.)


Catat itu

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

mendefinisikan DataFrame dengan nilai string. Karena terlihat numerik, Anda mungkin lebih baik mengubah string tersebut menjadi float:

df2 = df.astype(float)

Ini mengubah hasil, karena string membandingkan karakter demi karakter, sementara float dibandingkan secara numerik.

In [61]: '10' <= '4.2'
Out[61]: True

In [62]: 10 <= 4.2
Out[62]: False
unutbu
sumber
78

Anda dapat menggunakan .equalsuntuk kolom atau seluruh kerangka data.

df['col1'].equals(df['col2'])

Jika mereka sama, pernyataan itu akan kembali True, jika tidak False.

ccook5760.dll
sumber
24
Catatan: ini hanya membandingkan seluruh kolom dengan yang lain. Ini tidak membandingkan elemen kolom dengan bijaksana
guerda
1
Bagaimana jika Anda ingin melihat apakah satu kolom selalu memiliki nilai "lebih besar dari" atau "lebih kecil dari" kolom lainnya?
rrlamichhane
28

Anda bisa menggunakan apply () dan melakukan sesuatu seperti ini

df['que'] = df.apply(lambda x : x['one'] if x['one'] >= x['two'] and x['one'] <= x['three'] else "", axis=1)

atau jika Anda memilih untuk tidak menggunakan lambda

def que(x):
    if x['one'] >= x['two'] and x['one'] <= x['three']:
        return x['one']
    return ''
df['que'] = df.apply(que, axis=1)
Bob Haffner
sumber
2
Saya menduga ini mungkin sedikit lebih lambat daripada pendekatan lain yang diposting, karena ini tidak memanfaatkan operasi vektor yang diizinkan panda.
Marius
@BobHaffner: lambda tidak dapat dibaca saat menggunakan pernyataan if / then / else yang kompleks.
Merlin
@Merlin Anda dapat menambahkan elseif dan saya setuju dengan Anda tentang lambda dan beberapa kondisi
Bob Haffner
apakah ada cara untuk menggeneralisasi fungsi non lambda sehingga Anda bisa memasukkan kolom dataframe, dan tidak mengubah namanya?
AZhao
@AZhao Anda dapat menggeneralisasi dengan iloc seperti ini df ['que'] = df.apply (lambda x: x.iloc [0] if x.iloc [0]> = x.iloc [1] dan x.iloc [0 ] <= x.iloc [2] else "", axis = 1) Itukah yang Anda maksud? Jelas sekali. Urutan kolom Anda penting
Bob Haffner
9

Salah satu caranya adalah dengan menggunakan deret Boolean untuk mengindeks kolom df['one']. Ini memberi Anda kolom baru di mana Trueentri memiliki nilai yang sama dengan baris yang sama seperti df['one']dan Falsenilainya NaN.

Seri Boolean hanya diberikan oleh ifpernyataan Anda (meskipun ini perlu digunakan &sebagai pengganti and):

>>> df['que'] = df['one'][(df['one'] >= df['two']) & (df['one'] <= df['three'])]
>>> df
    one two three   que
0   10  1.2 4.2      10
1   15  70  0.03    NaN
2   8   5   0       NaN

Jika Anda ingin NaNnilai diganti dengan nilai lain, Anda dapat menggunakan fillnametode di kolom baru que. Saya telah menggunakan 0sebagai pengganti string kosong di sini:

>>> df['que'] = df['que'].fillna(0)
>>> df
    one two three   que
0   10  1.2   4.2    10
1   15   70  0.03     0
2    8    5     0     0
Alex Riley
sumber
5

Bungkus setiap kondisi individu dalam tanda kurung, lalu gunakan &operator untuk menggabungkan ketentuan:

df.loc[(df['one'] >= df['two']) & (df['one'] <= df['three']), 'que'] = df['one']

Anda dapat mengisi baris yang tidak cocok dengan hanya menggunakan ~(operator "bukan") untuk membalikkan kecocokan:

df.loc[~ ((df['one'] >= df['two']) & (df['one'] <= df['three'])), 'que'] = ''

Anda perlu menggunakan &dan ~daripada anddan notkarena operator &and ~bekerja elemen demi elemen.

Hasil akhir:

df
Out[8]: 
  one  two three que
0  10  1.2   4.2  10
1  15   70  0.03    
2   8    5     0  
Marius
sumber
1

Gunakan np.selectjika Anda memiliki beberapa kondisi untuk diperiksa dari dataframe dan keluaran pilihan tertentu di kolom yang berbeda

conditions=[(condition1),(condition2)]
choices=["choice1","chocie2"]

df["new column"]=np.select=(condtion,choice,default=)

Catatan: Tidak ada ketentuan dan tidak ada pilihan yang cocok, ulangi teks yang dipilih jika untuk dua ketentuan berbeda Anda memiliki pilihan yang sama

psn1997
sumber
0

Saya pikir yang paling dekat dengan intuisi OP adalah pernyataan inline if:

df['que'] = (df['one'] if ((df['one'] >= df['two']) and (df['one'] <= df['three'])) 
Nic Scozzaro
sumber
Kode Anda memberi saya kesalahandf['que'] = (df['one'] if ((df['one'] >= df['two']) and (df['one'] <= df['three'])) ^ SyntaxError: unexpected EOF while parsing
vasili111
0

Gunakan ekspresi lambda:

df[df.apply(lambda x: x['col1'] != x['col2'], axis = 1)]
aze45sq6d.dll
sumber