So sánh hai cột bằng cách sử dụng gấu trúc


104

Sử dụng điều này làm điểm bắt đầu:

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

Tôi muốn sử dụng một cái gì đó giống như một iftuyên bố trong gấu trúc.

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

Về cơ bản, hãy kiểm tra từng hàng thông qua ifcâu lệnh, tạo cột mới.

Các tài liệu nói để sử dụng .allnhưng không có ví dụ ...


Giá trị phải là bao nhiêu nếu ifcâu lệnh là False?
Alex Riley

3
@Merlin: Nếu bạn có dữ liệu số trong một cột, tốt nhất là không trộn nó với chuỗi. Làm như vậy sẽ thay đổi loại của cột thành object. Điều này cho phép các đối tượng Python tùy ý được lưu trữ trong cột, nhưng nó phải trả giá là tính toán số chậm hơn. Do đó, nếu cột đang lưu trữ dữ liệu số, thì việc sử dụng NaN cho các số không phải là số được ưu tiên hơn.
unutbu

1
Có số nguyên như dây đàn và cố gắng để làm so sánh trên chúng trông lẻ: a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]. Điều này tạo ra kết quả khó hiểu với mã "đúng": df['que'] = df['one'][(df['one'] >= df['two']) & (df['one'] <= df['three'])] mang lại kết quả 10cho dòng đầu tiên, trong khi nó sẽ cho kết quả NaNnếu đầu vào là số nguyên.
Primer

Câu trả lời:


147

Bạn có thể sử dụng np.where . Nếu condlà một mảng boolean và ABlà các mảng, thì

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

định nghĩa C bằng với Ađâu condlà Đúng và Bđâu condlà Sai.

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)

hoa lợi

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

Nếu bạn có nhiều hơn một điều kiện, thì bạn có thể sử dụng np.select để thay thế. Ví dụ: nếu bạn muốn df['que']bằng df['two']khi nào df['one'] < df['two'], thì

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)

hoa lợi

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

Nếu chúng ta có thể giả định rằng df['one'] >= df['two']khi nào df['one'] < df['two']là Sai, thì các điều kiện và lựa chọn có thể được đơn giản hóa thành

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

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

(Giả định có thể không đúng nếu df['one']hoặc df['two']chứa NaN.)


Lưu ý rằng

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

định nghĩa một DataFrame với các giá trị chuỗi. Vì chúng trông bằng số, bạn có thể tốt hơn nên chuyển đổi các chuỗi đó thành float:

df2 = df.astype(float)

Tuy nhiên, điều này làm thay đổi kết quả, vì các chuỗi so sánh từng ký tự, trong khi số thực được so sánh bằng số.

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

In [62]: 10 <= 4.2
Out[62]: False

72

Bạn có thể sử dụng .equalscho các cột hoặc toàn bộ khung dữ liệu.

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

Nếu chúng bằng nhau, câu lệnh đó sẽ trả về True, ngược lại False.


22
Lưu ý: điều này chỉ so sánh toàn bộ cột với một cột khác. Điều này không so sánh yếu tố columsn khôn ngoan
touristda

1
Còn nếu bạn muốn xem một cột luôn có giá trị "lớn hơn" hoặc "nhỏ hơn" các cột khác thì sao?
rrlamichhane

28

Bạn có thể sử dụng apply () và làm như thế này

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

hoặc nếu bạn không muốn sử dụng 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
Tôi nghi ngờ rằng điều này có thể chậm hơn một chút so với các cách tiếp cận khác đã đăng, vì nó không tận dụng được các hoạt động vector hóa mà gấu trúc cho phép.
Marius

@BobHaffner: lambda không thể đọc được khi sử dụng các câu lệnh if / then / else phức tạp.
Merlin

@Merlin bạn có thể thêm một elseif và tôi sẽ đồng ý với bạn về lambdas và nhiều điều kiện
Bob Haffner

có cách nào để tổng quát hóa hàm non lambda để bạn có thể chuyển các cột khung dữ liệu vào và không thay đổi tên không?
AZhao

@AZhao bạn có thể tổng quát hóa bằng iloc như thế này df ['que'] = df.apply (lambda x: x.iloc [0] if x.iloc [0]> = x.iloc [1] and x.iloc [0 ] <= x.iloc [2] else "", axis = 1) Ý bạn là vậy phải không? Chắc chắn. thứ tự các cột của bạn quan trọng
Bob Haffner

9

Một cách là sử dụng chuỗi Boolean để lập chỉ mục cột df['one']. Điều này cung cấp cho bạn một cột mới nơi các Truemục nhập có cùng giá trị với cùng một hàng df['one']Falsegiá trị NaN.

Chuỗi Boolean chỉ được đưa ra bởi ifcâu lệnh của bạn (mặc dù nó là cần thiết để sử dụng &thay vì 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

Nếu bạn muốn các NaNgiá trị được thay thế bằng các giá trị khác, bạn có thể sử dụng fillnaphương pháp trên cột mới que. Tôi đã sử dụng 0thay vì chuỗi trống ở đây:

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

4

Gói từng điều kiện riêng lẻ trong dấu ngoặc đơn, sau đó sử dụng &toán tử để kết hợp các điều kiện:

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

Bạn có thể điền vào các hàng không khớp bằng cách chỉ sử dụng ~(toán tử "not") để đảo ngược dòng so khớp:

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

Bạn cần sử dụng &~thay vì andnotbởi vì các toán tử &~hoạt động theo từng phần tử.

Kết quả cuối cùng:

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

1

Sử dụng np.selectnếu bạn có nhiều điều kiện cần được kiểm tra từ khung dữ liệu và xuất một lựa chọn cụ thể trong một cột khác

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

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

Lưu ý: Không có điều kiện nào và không có lựa chọn nào phải khớp, hãy lặp lại văn bản trong sự lựa chọn nếu đối với hai điều kiện khác nhau, bạn có cùng lựa chọn


0

Tôi nghĩ rằng điều gần nhất với trực giác của OP là câu lệnh if nội tuyến:

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

Mã của bạn khiến tôi bị lỗidf['que'] = (df['one'] if ((df['one'] >= df['two']) and (df['one'] <= df['three'])) ^ SyntaxError: unexpected EOF while parsing
vasili111
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.