Stosowanie funkcji z wieloma argumentami w celu utworzenia nowej kolumny pandy

165

Chcę utworzyć nową kolumnę w pandasramce danych, stosując funkcję do dwóch istniejących kolumn. Po tej odpowiedzi udało mi się utworzyć nową kolumnę, gdy potrzebuję tylko jednej kolumny jako argumentu:

import pandas as pd
df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})

def fx(x):
    return x * x

print(df)
df['newcolumn'] = df.A.apply(fx)
print(df)

Jednak nie mogę dowiedzieć się, jak zrobić to samo, gdy funkcja wymaga wielu argumentów. Na przykład, jak utworzyć nową kolumnę, przekazując kolumnę A i kolumnę B do poniższej funkcji?

def fxy(x, y):
    return x * y
Michael
źródło

Odpowiedzi:

136

Alternatywnie możesz użyć podstawowej funkcji numpy:

>>> import numpy as np
>>> df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})
>>> df['new_column'] = np.multiply(df['A'], df['B'])
>>> df
    A   B  new_column
0  10  20         200
1  20  30         600
2  30  10         300

lub wektoryzuj dowolną funkcję w ogólnym przypadku:

>>> def fx(x, y):
...     return x*y
...
>>> df['new_column'] = np.vectorize(fx)(df['A'], df['B'])
>>> df
    A   B  new_column
0  10  20         200
1  20  30         600
2  30  10         300
alko
źródło
2
Dziękuję za odpowiedź! Jestem ciekawy, czy to najszybsze rozwiązanie?
MV23
6
Wersja zwektoryzowana np.vectorize()jest niezwykle szybka. Dziękuję Ci.
stackoverflowuser2010
To przydatne rozwiązanie. Jeśli rozmiar argumentów wejściowych funkcji xiy nie jest równy, pojawi się błąd. W takim przypadku rozwiązanie @RomanPekar działa bez problemu. Nie porównałem wydajności.
Ehsan Sadr
Wiem, że to stara odpowiedź, ale: mam przypadek skrajny, w którym np.vectorizenie działa. Powodem jest to, że jedna z kolumn jest typu pandas._libs.tslibs.timestamps.Timestamp, który zostaje przekształcony w typ numpy.datetime64przez wektoryzację. Te dwa typy nie są zamienne, co powoduje, że funkcja działa źle. Jakieś sugestie w tej sprawie? (Poza .applytym, że najwyraźniej należy tego unikać)
ElRudi
Świetne rozwiązanie! na wypadek, gdyby ktoś się zastanawiał, wektoryzacja działa dobrze i bardzo szybko również dla funkcji porównywania ciągów.
infiniteloop
227

Możesz skorzystać z przykładu @greenAfrican, jeśli możesz przepisać swoją funkcję. Ale jeśli nie chcesz przepisać swojej funkcji, możesz zawinąć ją w anonimową funkcję wewnątrz Apply, na przykład:

>>> def fxy(x, y):
...     return x * y

>>> df['newcolumn'] = df.apply(lambda x: fxy(x['A'], x['B']), axis=1)
>>> df
    A   B  newcolumn
0  10  20        200
1  20  30        600
2  30  10        300
Roman Pekar
źródło
4
To świetna wskazówka, która pozostawia odwołania do kolumn w pobliżu wywołania zastosowania (w rzeczywistości). Użyłem tej wskazówki i wielokolumnowej końcówki wyjściowej @toto_tico dostarczonej do wygenerowania funkcji 3-kolumnowej, 4-kolumnowej! Działa świetnie!
RufusVS
7
Wow, wygląda na to, że jesteś jedyną osobą, która nie koncentruje się na minimalnym przykładzie OP, ale rozwiązuje cały problem, dzięki, dokładnie to, czego potrzebowałem! :)
Matt
38

To rozwiązuje problem:

df['newcolumn'] = df.A * df.B

Możesz też:

def fab(row):
  return row['A'] * row['B']

df['newcolumn'] = df.apply(fab, axis=1)
greenafrican
źródło
10
Ta odpowiedź rozwiązuje ten przykład zabawki i wystarczy, żebym przepisał moją rzeczywistą funkcję, ale nie dotyczy sposobu zastosowania wcześniej zdefiniowanej funkcji bez przepisywania jej na kolumny odniesienia.
Michael
23

Jeśli chcesz utworzyć wiele kolumn jednocześnie :

  1. Utwórz ramkę danych:

    import pandas as pd
    df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})
  2. Utwórz funkcję:

    def fab(row):                                                  
        return row['A'] * row['B'], row['A'] + row['B']
  3. Przypisz nowe kolumny:

    df['newcolumn'], df['newcolumn2'] = zip(*df.apply(fab, axis=1))
toto_tico
źródło
1
Zastanawiałem się, jak mogę wygenerować wiele kolumn za pomocą jednej aplikacji! Użyłem tego z odpowiedzią @Roman Pekar, aby wygenerować funkcję z 3 kolumnami na wejściu i 4 na wyjściu! Działa świetnie!
RufusVS
15

Jeszcze jedna czysta składnia w stylu dyktowania:

df["new_column"] = df.apply(lambda x: x["A"] * x["B"], axis = 1)

lub,

df["new_column"] = df["A"] * df["B"]
Surya
źródło