Porównaj dwie kolumny za pomocą pand


110

Używając tego jako punktu wyjścia:

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

Chcę użyć czegoś w rodzaju ifoświadczenia w pandach.

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

Zasadniczo sprawdź każdy wiersz za pomocą ifinstrukcji, utwórz nową kolumnę.

Dokumenty mówią, że należy używać, .allale nie ma przykładu ...


Jaka powinna być wartość, jeśli ifinstrukcja jest False?
Alex Riley,

3
@Merlin: Jeśli masz dane liczbowe w kolumnie, najlepiej nie mieszać ich z ciągami. Spowoduje to zmianę typu kolumny na object. Pozwala to na przechowywanie dowolnych obiektów Pythona w kolumnie, ale odbywa się to kosztem wolniejszych obliczeń numerycznych. Tak więc, jeśli kolumna przechowuje dane liczbowe, preferowane jest użycie NaN dla nie-liczb.
unutbu

1
Mając całkowitymi jak ciągi i próbuje zrobić porównanie na nich wygląda dziwnie: a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]. Tworzy to mylące wyniki z „poprawnym” kodem: df['que'] = df['one'][(df['one'] >= df['two']) & (df['one'] <= df['three'])] daje wyniki 10w pierwszym wierszu, podczas gdy powinno dać wynik, NaNgdyby dane wejściowe były liczbami całkowitymi.
Primer

Odpowiedzi:


153

Możesz użyć np.where . Jeśli condjest tablicą logiczną, a Ai Bsą tablicami, to

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

definiuje C jako równe Agdzie condjest True, a Bgdzie condjest 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)

plony

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

Jeśli masz więcej niż jeden warunek, możesz zamiast tego użyć np.select . Na przykład, jeśli chcesz df['que']wyrównać df['two']kiedy df['one'] < df['two'], to

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)

plony

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

Jeśli możemy założyć, że df['one'] >= df['two']kiedy df['one'] < df['two']jest fałszywe, to warunki i wybory można uprościć do

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

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

(Założenie może nie być prawdziwe, jeśli df['one']lub df['two']zawierają NaN).


Zwróć na to uwagę

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

definiuje DataFrame z wartościami ciągów. Ponieważ wyglądają na numeryczne, może lepiej byłoby przekonwertować te ciągi na liczby zmiennoprzecinkowe:

df2 = df.astype(float)

Zmienia to jednak wyniki, ponieważ łańcuchy porównują znak po znaku, podczas gdy liczby zmiennoprzecinkowe są porównywane numerycznie.

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

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

78

Możesz użyć .equalsdla kolumn lub całych ramek danych.

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

Jeśli są równe, ta instrukcja zwróci True, w przeciwnym razie False.


24
Uwaga: to tylko porównuje całą kolumnę z inną. To nie porównuje pod względem elementu
kolumny

1
Co powiesz na to, że chcesz sprawdzić, czy jedna kolumna ma zawsze wartość „większa niż” lub „mniejsza niż” inne kolumny?
rrlamichhane

28

Możesz użyć apply () i zrobić coś takiego

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

lub jeśli wolisz nie używać lambdy

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
Podejrzewam, że jest to prawdopodobnie nieco wolniejsze niż inne opublikowane podejścia, ponieważ nie wykorzystuje operacji wektoryzacji, na które pozwalają pandy.
Marius

@BobHaffner: lambda nie są czytelne w przypadku stosowania złożonych instrukcji if / then / else.
Merlin,

@Merlin, możesz dodać elseif i zgodziłbym się z tobą w sprawie lambd i wielu warunków
Bob Haffner,

czy istnieje sposób na uogólnienie funkcji innej niż lambda, tak aby można było przekazywać kolumny dataframe i nie zmieniać nazwy?
AZhao,

@AZhao możesz uogólniać za pomocą iloc w ten sposób df ['que'] = df.apply (lambda x: x.iloc [0] if x.iloc [0]> = x.iloc [1] i x.iloc [0 ] <= x.iloc [2] else "", axis = 1) Czy to masz na myśli? Oczywiście. kolejność kolumn ma znaczenie
Bob Haffner

9

Jednym ze sposobów jest użycie serii boolowskiej do indeksowania kolumny df['one']. Daje to nową kolumnę, w której Truewpisy mają taką samą wartość, jak ten sam wiersz, co df['one']i Falsewartości NaN.

Szereg boolowski jest po prostu podany przez twoje ifoświadczenie (chociaż konieczne jest użycie &zamiast 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

Jeśli chcesz, aby NaNwartości zostały zastąpione innymi wartościami, możesz użyć fillnametody w nowej kolumnie que. Użyłem tutaj 0zamiast pustego ciągu:

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

Umieść każdy warunek w nawiasach, a następnie &połącz warunki za pomocą operatora:

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

Możesz wypełnić niepasujące wiersze, używając po prostu ~operatora („nie”), aby odwrócić dopasowanie:

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

Musisz użyć &i ~zamiast andi, notponieważ operatory &i ~działają element po elemencie.

Wynik końcowy:

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

1

Użyj, np.selectjeśli masz wiele warunków do sprawdzenia z ramki danych i wyprowadzisz konkretny wybór w innej kolumnie

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

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

Uwaga: Żaden z warunków i żadna z opcji nie powinny pasować, powtórz wybrany tekst, jeśli dla dwóch różnych warunków masz takie same możliwości


0

Myślę, że najbliższe intuicji OP jest stwierdzenie inline if:

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

Twój kod daje mi błąddf['que'] = (df['one'] if ((df['one'] >= df['two']) and (df['one'] <= df['three'])) ^ SyntaxError: unexpected EOF while parsing
vasili111

0

Użyj wyrażenia lambda:

df[df.apply(lambda x: x['col1'] != x['col2'], axis = 1)]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.