Pandas: Wie kann ich die Funktion apply () für eine einzelne Spalte verwenden?

257

Ich habe einen Pandas-Datenrahmen mit zwei Spalten. Ich muss die Werte der ersten Spalte ändern, ohne die zweite zu beeinflussen, und den gesamten Datenrahmen mit nur geänderten Werten der ersten Spalte zurückerhalten. Wie kann ich das mit bewerben in Pandas machen?

Amani
quelle
4
Bitte posten Sie einige Eingabebeispieldaten und die gewünschte Ausgabe.
Fabio Lamanna
Sie sollten applyin einer solchen Situation fast nie verwenden . Bearbeiten Sie die Spalte stattdessen direkt.
Ted Petrou
Vermeiden Sie, applywie Ted Petrou sagte, so viel wie möglich zu verwenden. Wenn Sie nicht sicher sind, ob Sie es verwenden müssen, tun Sie es wahrscheinlich nicht. Ich empfehle einen Blick auf Wann sollte ich jemals pandas apply () in meinem Code verwenden wollen? .
CS95
Die Frage ist nicht ganz klar: Wendet sie eine Funktion auf jedes Element einer Spalte an oder wendet sie eine Funktion auf die gesamte Spalte an (zum Beispiel: Umkehren der Spalte)?
Pierre ALBARÈDE

Antworten:

336

Bei einem Beispieldatenrahmen wie folgt df:

a,b
1,2
2,3
3,4
4,5

was Sie wollen ist:

df['a'] = df['a'].apply(lambda x: x + 1)

das gibt zurück:

   a  b
0  2  2
1  3  3
2  4  4
3  5  5
Fabio Lamanna
quelle
9
applysollte niemals in einer
Ted Petrou
5
@ TedPetrou Sie haben vollkommen recht, es war nur ein Beispiel dafür, wie eine allgemeine Funktion auf eine einzelne Spalte angewendet wird, wie das OP gefragt hat.
Fabio Lamanna
14
Wenn ich dies versuche, erhalte ich die folgende Warnung: "Ein Wert versucht, auf einer Kopie eines Slice aus einem DataFrame festgelegt zu werden. Versuchen Sie stattdessen, .loc [row_indexer, col_indexer] = value zu verwenden"
dagrun
24
Aus Neugier: Warum sollte in dieser Situation nicht angewendet werden? Wie ist die Situation genau?
Onkel Ben Ben
19
@UncleBenBen verwendet im Allgemeinen applyeine interne Schleife über Zeilen, die weitaus langsamer ist als vektorisierte Funktionen, wie z. B. df.a = df.a / 2(siehe Antwort von Mike Muller).
Fabio Lamanna
66

Für eine einzelne Spalte besser zu verwenden map(), wie folgt:

df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9



df['a'] = df['a'].map(lambda a: a / 2.)

      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9
George Petrov
quelle
78
Warum ist map()besser als apply()für eine einzelne Spalte?
ChaimG
2
Das war sehr nützlich. Ich habe es verwendet, um Dateinamen aus Pfaden zu extrahieren, die in einer Spalte gespeichert sinddf['file_name'] = df['Path'].map(lambda a: os.path.basename(a))
mmann1123
46
map () ist für Serien (dh einzelne Spalten) und wird jeweils für eine Zelle ausgeführt, während apply () für DataFrame und jeweils für eine ganze Zeile ausgeführt wird.
jpcgt
3
@jpcgt Bedeutet das, dass die Karte schneller ist als in diesem Fall?
Viragos
@ChaimG Ich sehe, dass dieses Betriebssystem
象 嘉 道
40

Sie brauchen überhaupt keine Funktion. Sie können direkt an einer ganzen Spalte arbeiten.

Beispieldaten:

>>> df = pd.DataFrame({'a': [100, 1000], 'b': [200, 2000], 'c': [300, 3000]})
>>> df

      a     b     c
0   100   200   300
1  1000  2000  3000

Die Hälfte aller Werte in der Spalte a:

>>> df.a = df.a / 2
>>> df

     a     b     c
0   50   200   300
1  500  2000  3000
Mike Müller
quelle
Was ist, wenn ich jedes Element in einer Spalte durch "/" teilen und den ersten Teil übernehmen möchte?
K47
12

Obwohl die angegebenen Antworten korrekt sind, ändern sie den anfänglichen Datenrahmen, was nicht immer wünschenswert ist (und angesichts des OP, das nach Beispielen für "using apply" gefragt wurde, möchten sie möglicherweise eine Version, die wie neu einen neuen Datenrahmen zurückgibt apply).

Dies ist möglich mit assign: Es gilt für assignvorhandene Spalten, wie in der Dokumentation angegeben (Schwerpunkt liegt bei mir):

Weisen Sie einem DataFrame neue Spalten zu.

Gibt ein neues Objekt mit allen ursprünglichen Spalten zusätzlich zu den neuen zurück. Bestehende Spalten, die neu zugewiesen werden, werden überschrieben .

Zusamenfassend:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

In [3]: df.assign(a=lambda df: df.a / 2)
Out[3]: 
      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

In [4]: df
Out[4]: 
    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9

Beachten Sie, dass der Funktion der gesamte Datenrahmen übergeben wird, nicht nur die Spalte, die Sie ändern möchten. Sie müssen daher sicherstellen, dass Sie die richtige Spalte in Ihrem Lambda auswählen.

Thibaut Dubernet
quelle
9

Wenn Sie wirklich über die Ausführungsgeschwindigkeit Ihrer Apply-Funktion besorgt sind und über einen großen Datensatz verfügen, an dem Sie arbeiten müssen, können Sie swifter verwenden, um eine schnellere Ausführung zu erzielen. Hier ein Beispiel für swifter on pandas dataframe:

import pandas as pd
import swifter

def fnc(m):
    return m*3+4

df = pd.DataFrame({"m": [1,2,3,4,5,6], "c": [1,1,1,1,1,1], "x":[5,3,6,2,6,1]})

# apply a self created function to a single column in pandas
df["y"] = df.m.swifter.apply(fnc)

Auf diese Weise können alle CPU-Kerne das Ergebnis berechnen, sodass es viel schneller als normale Anwendungsfunktionen ist. Versuchen Sie und lassen Sie mich wissen, ob es für Sie nützlich wird.

durjoy
quelle
1

Lassen Sie mich eine komplexe Berechnung mit datetime und unter Berücksichtigung von Nullen oder Leerzeichen versuchen. Ich reduziere 30 Jahre für eine Datetime-Spalte und verwende die applyMethode sowie das lambdaKonvertieren des Datetime-Formats. Line if x != '' else xkümmert sich entsprechend um alle Leerzeichen oder Nullen.

df['Date'] = df['Date'].fillna('')
df['Date'] = df['Date'].apply(lambda x : ((datetime.datetime.strptime(str(x), '%m/%d/%Y') - datetime.timedelta(days=30*365)).strftime('%Y%m%d')) if x != '' else x)
Harry_pb
quelle