Anwenden einer Funktion mit mehreren Argumenten zum Erstellen einer neuen Pandas-Spalte

165

Ich möchte eine neue Spalte in einem pandasDatenrahmen erstellen, indem ich eine Funktion auf zwei vorhandene Spalten anwende. Nach dieser Antwort konnte ich eine neue Spalte erstellen, wenn ich nur eine Spalte als Argument benötige:

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)

Ich kann jedoch nicht herausfinden, wie ich dasselbe tun soll, wenn die Funktion mehrere Argumente erfordert. Wie erstelle ich beispielsweise eine neue Spalte, indem ich Spalte A und Spalte B an die folgende Funktion übergebe?

def fxy(x, y):
    return x * y
Michael
quelle

Antworten:

136

Alternativ können Sie die zugrunde liegende Funktion numpy verwenden:

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

oder beliebige Funktion im allgemeinen Fall vektorisieren:

>>> 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
quelle
2
Danke für die Antwort! Ich bin neugierig, ist das die schnellste Lösung?
MV23
6
Die vektorisierte Version mit np.vectorize()ist erstaunlich schnell. Danke dir.
stackoverflowuser2010
Dies ist eine nützliche Lösung. Wenn die Größe der Eingabeargumente für die Funktion x und y nicht gleich ist, wird eine Fehlermeldung angezeigt. In diesem Fall funktioniert die @ RomanPekar-Lösung problemlos. Ich habe die Leistung nicht verglichen.
Ehsan Sadr
Ich weiß, dass dies eine alte Antwort ist, aber: Ich habe einen Randfall, in dem np.vectorizees nicht funktioniert. Der Grund ist, dass eine der Spalten vom Typ ist pandas._libs.tslibs.timestamps.Timestamp, der numpy.datetime64durch die Vektorisierung in den Typ umgewandelt wird. Die beiden Typen sind nicht austauschbar, wodurch sich die Funktion schlecht verhält. Irgendwelche Vorschläge dazu? (Anders als .applydies anscheinend zu vermeiden ist)
ElRudi
Tolle Lösung! falls sich jemand wundert, funktioniert vectorize auch für String-Vergleichsfunktionen gut und superschnell.
Infiniteloop
226

Sie können mit dem Beispiel @greenAfrican fortfahren, wenn Sie Ihre Funktion neu schreiben können. Wenn Sie Ihre Funktion jedoch nicht neu schreiben möchten, können Sie sie wie folgt in eine anonyme Funktion in apply einbinden:

>>> 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
quelle
4
Dies ist ein großartiger Tipp, und die Spaltenreferenzen bleiben in der Nähe des Apply-Aufrufs (tatsächlich darin). Ich habe diesen Tipp und den mehrspaltigen Ausgabetipp @toto_tico verwendet, um eine 3-Spalten-In- und 4-Spalten-Out-Funktion zu generieren! Funktioniert super!
RufusVS
7
Wow, es scheint, dass Sie der einzige sind, der sich nicht auf das minimale Beispiel von OP konzentriert, sondern das ganze Problem anspricht, danke, genau das, was ich brauchte! :)
Matt
38

Dies löst das Problem:

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

Sie könnten auch tun:

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

df['newcolumn'] = df.apply(fab, axis=1)
greenafrican
quelle
10
Diese Antwort löst dieses Spielzeugbeispiel und reicht aus, um meine eigentliche Funktion neu zu schreiben. Sie behandelt jedoch nicht, wie eine zuvor definierte Funktion angewendet wird, ohne sie in Referenzspalten umzuschreiben.
Michael
23

Wenn Sie mehrere Spalten gleichzeitig erstellen müssen :

  1. Erstellen Sie den Datenrahmen:

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

    def fab(row):                                                  
        return row['A'] * row['B'], row['A'] + row['B']
  3. Weisen Sie die neuen Spalten zu:

    df['newcolumn'], df['newcolumn2'] = zip(*df.apply(fab, axis=1))
toto_tico
quelle
1
Ich habe mich gefragt, wie ich mit einer Bewerbung mehrere Spalten generieren kann! Ich habe dies mit der Antwort von @Roman Pekar verwendet, um eine 3-Spalten-In- und 4-Spalten-Out-Funktion zu generieren! Funktioniert super!
RufusVS
14

Noch eine saubere Syntax im Diktatstil:

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

oder,

df["new_column"] = df["A"] * df["B"]
Surya
quelle