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

Merlinie
źródło
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
unutbu
źródło
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.

ccook5760
źródło
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)
Bob Haffner
źródło
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
Alex Riley
źródło
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  
Marius
źródło
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

psn1997
źródło
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'])) 
Nic Scozzaro
źródło
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)]
aze45sq6d
źródło