Tworzenie nowej kolumny na podstawie warunku if-elif-else

103

Mam DataFrame df:

    A    B
a   2    2 
b   3    1
c   1    3

Chcę utworzyć nową kolumnę na podstawie następujących kryteriów:

jeśli wiersz A == B: 0

jeśli wierszA > B: 1

jeśli wiersz A < B: -1

więc biorąc pod uwagę powyższą tabelę, powinno być:

    A    B    C
a   2    2    0
b   3    1    1
c   1    3   -1 

W typowych if elseprzypadkach, które robię np.where(df.A > df.B, 1, -1), czy pandy zapewniają specjalną składnię do rozwiązania mojego problemu w jednym kroku (bez konieczności tworzenia 3 nowych kolumn, a następnie łączenia wyniku)?

orzechówka
źródło
Można po prostu zdefiniować funkcję i przekazać to applyi zestaw axis=1będzie działać, nie wiem, mogę myśleć o operacji, która da ci to, co chcesz
EdChum
Twoje rozwiązanie zakłada utworzenie 3 kolumn i połączenie ich w 1 kolumnę, czy masz coś innego na myśli?
orzechowy orzech
Ciągle powtarzasz „tworzę 3 kolumny”, ale nie jestem pewien, o czym mówisz.
DSM,
1
@DSM odpowiedział na to pytanie, ale miałem na myśli coś takiego, df['C']=df.apply(myFunc(row), axis=1)gdzie myFunc robi to, co chcesz, nie obejmuje to tworzenia
``

Odpowiedzi:

152

Aby sformalizować niektóre z podejść przedstawionych powyżej:

Utwórz funkcję, która działa na wierszach ramki danych, w następujący sposób:

def f(row):
    if row['A'] == row['B']:
        val = 0
    elif row['A'] > row['B']:
        val = 1
    else:
        val = -1
    return val

Następnie zastosuj go do swojej ramki danych przekazując axis=1opcję:

In [1]: df['C'] = df.apply(f, axis=1)

In [2]: df
Out[2]:
   A  B  C
a  2  2  0
b  3  1  1
c  1  3 -1

Oczywiście nie jest to wektoryzowane, więc wydajność może nie być tak dobra po skalowaniu do dużej liczby rekordów. Mimo to uważam, że jest znacznie bardziej czytelny. Zwłaszcza z przeszłością SAS.

Edytować

Oto wersja zwektoryzowana

df['C'] = np.where(
    df['A'] == df['B'], 0, np.where(
    df['A'] >  df['B'], 1, -1)) 
Żelazny7
źródło
1
Dziękuję, zaczynam od pand i to było bardzo pomocne +1
nutship
4
A jeśli chcę przekazać inny parametr wraz z wierszem w funkcji? Jeśli tak, jest napisane, że wiersz nie został zdefiniowany ...
prashanth manohar
3
Musisz użyć argsparametru .applyfunkcji: pandas.pydata.org/pandas-docs/stable/generated/…
Zelazny7
1
Jestem starym użytkownikiem SAS, uczącym się Pythona i na pewno jest krzywa uczenia się! :-) Na przykład powyższy kod można zapisać w SAS jako: data df; set df; if A=B then C=0; else if A>B then C=1; else C=-1; run;Bardzo elegancki i prosty.
RobertF
1
Dobrze zdefiniowana odpowiedź
Sahil Nagpal
54
df.loc[df['A'] == df['B'], 'C'] = 0
df.loc[df['A'] > df['B'], 'C'] = 1
df.loc[df['A'] < df['B'], 'C'] = -1

Łatwe do rozwiązania za pomocą indeksowania. Pierwsza linia kodu brzmi tak, jeśli kolumna Ajest równa kolumnie, Ba następnie utwórz i ustaw kolumnę Crówną 0.

Brian
źródło
17

W przypadku tej konkretnej relacji możesz użyć np.sign:

>>> df["C"] = np.sign(df.A - df.B)
>>> df
   A  B  C
a  2  2  0
b  3  1  1
c  1  3 -1
DSM
źródło
6

wprowadź opis obrazu tutaj

Powiedzmy, że powyżej jest oryginalna ramka danych i chcesz dodać nową kolumnę „stara”

Jeśli wiek przekracza 50 lat, uważamy, że jest starszy = tak, w przeciwnym razie Fałsz

krok 1: pobierz indeksy wierszy, których wiek jest większy niż 50

row_indexes=df[df['age']>=50].index

krok 2: za pomocą .loc możemy przypisać nową wartość do kolumny

df.loc[row_indexes,'elderly']="yes"

to samo dla wieku poniżej 50 lat

row_indexes=df[df['age']<50].index

df[row_indexes,'elderly']="no"

Ravi
źródło
1

Kiedy masz wiele if warunków, numpy.selectjest najlepszy sposób:

In [4102]: import numpy as np
In [4098]: conditions = [df.A.eq(df.B), df.A.gt(df.B), df.A.lt(df.B)]
In [4096]: choices = [0, 1, -1]

In [4100]: df['C'] = np.select(conditions, choices)

In [4101]: df
Out[4101]: 
   A  B  C
a  2  2  0
b  3  1  1
c  1  3 -1
Mayank Porwal
źródło