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 ...


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

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.


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)

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

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  

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


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'])) 

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)]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.