Python-Pandas: Wenden Sie eine Funktion mit Argumenten auf eine Reihe an

147

Ich möchte eine Funktion mit Argumenten auf eine Reihe in Python-Pandas anwenden:

x = my_series.apply(my_function, more_arguments_1)
y = my_series.apply(my_function, more_arguments_2)
...

In der Dokumentation wird die Unterstützung einer Apply-Methode beschrieben, es werden jedoch keine Argumente akzeptiert. Gibt es eine andere Methode, die Argumente akzeptiert? Fehlt mir alternativ eine einfache Problemumgehung?

Update (Oktober 2017): Da diese Frage ursprünglich gestellt wurde, wurde Pandas apply()aktualisiert, um Positions- und Schlüsselwortargumente zu verarbeiten. Der obige Dokumentationslink spiegelt dies nun wider und zeigt, wie beide Argumenttypen eingeschlossen werden können.

Abe
quelle
3
Warum nicht einfach benutzen functools.partialoder starmap?
Joel Cornett

Antworten:

170

Neuere Versionen von Pandas tun können Sie zusätzliche Argumente zu übergeben (siehe die neue Dokumentation ). Jetzt können Sie also Folgendes tun:

my_series.apply(your_function, args=(2,3,4), extra_kw=1)

Die Positionsargumente werden nach dem Element der Reihe hinzugefügt .


Für ältere Versionen von Pandas:

Die Dokumentation erklärt dies deutlich. Die Methode apply akzeptiert eine Python-Funktion, die einen einzelnen Parameter haben sollte. Wenn Sie weitere Parameter übergeben möchten, sollten Sie diese verwenden, functools.partialwie von Joel Cornett in seinem Kommentar vorgeschlagen.

Ein Beispiel:

>>> import functools
>>> import operator
>>> add_3 = functools.partial(operator.add,3)
>>> add_3(2)
5
>>> add_3(7)
10

Sie können Schlüsselwortargumente auch mit übergeben partial.

Ein anderer Weg wäre, ein Lambda zu erstellen:

my_series.apply((lambda x: your_func(a,b,c,d,...,x)))

Aber ich denke, die Verwendung partialist besser.

Bakuriu
quelle
12
Für einen DataFrame akzeptiert die Methode apply ein argsArgument, bei dem es sich um ein Tupel handelt, das zusätzliche Positionsargumente oder ** kwds für benannte Argumente enthält. Ich habe ein Problem , das für Series.apply auch haben () github.com/pydata/pandas/issues/1829
Wouter Overmeire
28
Feature wurde implementiert, wird in der kommenden Pandas-Veröffentlichung sein
Wes McKinney
4
Dies ist eine schöne Antwort, aber die ersten 2/3 davon sind jetzt wirklich veraltet. IMO, diese Antwort könnte gut aktualisiert werden, indem sie nur ein Link zur neuen Dokumentation sowie ein kurzes Beispiel für die Verwendung mit Positions- und / oder Schlüsselwortargumenten ist. Nur FWIW und keine Kritik an der ursprünglichen Antwort, würde nur von einem Update IMO profitieren, zumal es sich um eine häufig gelesene Antwort handelt.
JohnE
@watsonic Die Dokumentation wurde inzwischen aktualisiert und das Klicken auf die alten Links führt zur aktuellen Dokumentation, die die Frage nun sehr gut beantwortet.
JohnE
Hinweis: Wenn Sie beispielsweise ein einzelnes Zeichenfolgenargument übergeben 'abc', args=('abc')wird es als drei Argumente ausgewertet ('a', 'b', 'c'). Um dies zu vermeiden, müssen Sie ein Tupel mit der Zeichenfolge übergeben und dazu ein nachfolgendes Komma einfügen:args=('abc',)
Rocky K
82

Schritte:

  1. Erstellen Sie einen Datenrahmen
  2. Erstellen Sie eine Funktion
  3. Verwenden Sie die benannten Argumente der Funktion in der apply-Anweisung.

Beispiel

x=pd.DataFrame([1,2,3,4])  

def add(i1, i2):  
    return i1+i2

x.apply(add,i2=9)

Das Ergebnis dieses Beispiels ist, dass jede Nummer im Datenrahmen zur Nummer 9 hinzugefügt wird.

    0
0  10
1  11
2  12
3  13

Erläuterung:

Die Funktion "Hinzufügen" hat zwei Parameter: i1, i2. Der erste Parameter ist der Wert im Datenrahmen und der zweite ist alles, was wir an die Funktion "Apply" übergeben. In diesem Fall übergeben wir "9" mit dem Schlüsselwortargument "i2" an die Apply-Funktion.

Faust der Wut
quelle
2
Genau das, wonach ich gesucht habe. Dies erfordert insbesondere nicht das Erstellen einer benutzerdefinierten Funktion, um nur eine Serie (oder df) zu verarbeiten. Perfekt!
Connor
Die einzige verbleibende Frage ist: Wie übergebe ich ein Schlüsselwortargument an das erste Argument in add (i1) und iteriere mit i2?
Connor
Ich denke, das ist die beste Antwort
Crypdick
43
Series.apply(func, convert_dtype=True, args=(), **kwds)

args : tuple

x = my_series.apply(my_function, args = (arg1,))
dani_g
quelle
11
Vielen Dank! Können Sie erklären, warum args = (arg1,) nach dem ersten Argument ein Komma benötigt?
DrMisha
21
@MishaTeplitskiy, Sie benötigen das Komma, damit Python versteht, dass der Inhalt der Klammern ein Tupel der Länge 1 ist.
Prooffreader
3
Was ist mit Argumenten für die func. Also, wenn ich mich bewerben möchte, pd.Series.mean(axis=1)wie gebe ich das ein axis=1?
Little Bobby Tables
1
Als Randnotiz können Sie auch ein Schlüsselwortargument hinzufügen, ohne den Parameter <args> zu verwenden (z. B. x = my_series.apply (my_function, keyword_arg = arg1), wobei <keyword_arg> zu den Eingabeparametern von my_function gehört)
lev
1
Diese Antwort ist zu kurz und erklärt nichts
FistOfFury
23

Sie können eine beliebige Anzahl von Argumenten an die Funktion übergeben, applydie entweder über unbenannte Argumente, die als Tupel an den argsParameter übergeben werden, oder über andere Schlüsselwortargumente , die vom Parameter intern als Wörterbuch erfasst werden, aufgerufen wird kwds.

Erstellen wir beispielsweise eine Funktion, die True für Werte zwischen 3 und 6 und andernfalls False zurückgibt.

s = pd.Series(np.random.randint(0,10, 10))
s

0    5
1    3
2    1
3    1
4    6
5    0
6    3
7    4
8    9
9    6
dtype: int64

s.apply(lambda x: x >= 3 and x <= 6)

0     True
1     True
2    False
3    False
4     True
5    False
6     True
7     True
8    False
9     True
dtype: bool

Diese anonyme Funktion ist nicht sehr flexibel. Erstellen wir eine normale Funktion mit zwei Argumenten, um die Min- und Max-Werte zu steuern, die wir in unserer Serie haben möchten.

def between(x, low, high):
    return x >= low and x =< high

Wir können die Ausgabe der ersten Funktion replizieren, indem wir unbenannte Argumente an argsfolgende Adresse übergeben :

s.apply(between, args=(3,6))

Oder wir können die genannten Argumente verwenden

s.apply(between, low=3, high=6)

Oder sogar eine Kombination aus beiden

s.apply(between, args=(3,), high=6)
Ted Petrou
quelle