Erstellen Sie eine neue Spalte basierend auf Werten aus anderen Spalten / wenden Sie eine Funktion mehrerer Spalten zeilenweise in Pandas an

Lesezeit: 15 Minuten

Daves Benutzeravatar
David

Ich möchte meine benutzerdefinierte Funktion (sie verwendet eine if-else-Leiter) auf diese sechs Spalten anwenden (ERI_Hispanic, ERI_AmerInd_AKNatv, ERI_Asian, ERI_Black_Afr.Amer, ERI_HI_PacIsl, ERI_White) in jeder Zeile meines Datenrahmens.

Ich habe verschiedene Methoden aus anderen Fragen ausprobiert, kann aber immer noch nicht die richtige Antwort auf mein Problem finden. Der entscheidende Punkt dabei ist, dass, wenn die Person als Hispanoamerikaner gezählt wird, sie nicht als irgendetwas anderes gezählt werden kann. Selbst wenn sie eine “1” in einer anderen Ethnizitätsspalte haben, werden sie immer noch als Hispanoamerikaner gezählt, nicht als zwei oder mehr Rassen. Wenn die Summe aller ERI-Spalten größer als 1 ist, werden sie in ähnlicher Weise als zwei oder mehr Rassen gezählt und können nicht als eindeutige ethnische Zugehörigkeit gezählt werden (außer Hispanic).

Es ist fast so, als würde man jede Zeile mit einer for-Schleife durchlaufen, und wenn jeder Datensatz ein Kriterium erfüllt, werden sie zu einer Liste hinzugefügt und aus dem Original entfernt.

Aus dem folgenden Datenrahmen muss ich eine neue Spalte basierend auf der folgenden Spezifikation in SQL berechnen:

KRITERIEN

IF [ERI_Hispanic] = 1 THEN RETURN “Hispanic”
ELSE IF SUM([ERI_AmerInd_AKNatv] + [ERI_Asian] + [ERI_Black_Afr.Amer] + [ERI_HI_PacIsl] + [ERI_White]) > 1 THEN RETURN “Two or More”
ELSE IF [ERI_AmerInd_AKNatv] = 1 THEN RETURN “A/I AK Native”
ELSE IF [ERI_Asian] = 1 THEN RETURN “Asian”
ELSE IF [ERI_Black_Afr.Amer] = 1 THEN RETURN “Black/AA”
ELSE IF [ERI_HI_PacIsl] = 1 THEN RETURN “Haw/Pac Isl.”
ELSE IF [ERI_White] = 1 THEN RETURN “White”

Kommentar: Wenn das ERI-Flag für Hispanic True (1) ist, wird der Mitarbeiter als „Hispanic“ eingestuft.

Kommentar: Wenn mehr als 1 nicht-hispanisches ERI-Flag wahr ist, geben Sie „Zwei oder mehr“ zurück

DATENRAHMEN

     lname          fname       rno_cd  eri_afr_amer    eri_asian   eri_hawaiian    eri_hispanic    eri_nat_amer    eri_white   rno_defined
0    MOST           JEFF        E       0               0           0               0               0               1           White
1    CRUISE         TOM         E       0               0           0               1               0               0           White
2    DEPP           JOHNNY              0               0           0               0               0               1           Unknown
3    DICAP          LEO                 0               0           0               0               0               1           Unknown
4    BRANDO         MARLON      E       0               0           0               0               0               0           White
5    HANKS          TOM         0                       0           0               0               0               1           Unknown
6    DENIRO         ROBERT      E       0               1           0               0               0               1           White
7    PACINO         AL          E       0               0           0               0               0               1           White
8    WILLIAMS       ROBIN       E       0               0           1               0               0               0           White
9    EASTWOOD       CLINT       E       0               0           0               0               0               1           White

  • Für diese Aufgabe apply scheint aber offensichtlich nicht Verwenden Sie es, weil es nur eine Schleife über die Zeilen ist. Es gibt bessere Möglichkeiten, dies zu tun. Beispiele: hier, hier, hier.

    – Baumwollschwanz

    17. November 2022 um 21:37 Uhr

Benutzeravatar von Thomas Kimber
Thomas Kimber

OK, zwei Schritte dazu – zuerst muss eine Funktion geschrieben werden, die die gewünschte Übersetzung durchführt – ich habe ein Beispiel zusammengestellt, das auf Ihrem Pseudocode basiert:

def label_race (row):
   if row['eri_hispanic'] == 1 :
      return 'Hispanic'
   if row['eri_afr_amer'] + row['eri_asian'] + row['eri_hawaiian'] + row['eri_nat_amer'] + row['eri_white'] > 1 :
      return 'Two Or More'
   if row['eri_nat_amer'] == 1 :
      return 'A/I AK Native'
   if row['eri_asian'] == 1:
      return 'Asian'
   if row['eri_afr_amer']  == 1:
      return 'Black/AA'
   if row['eri_hawaiian'] == 1:
      return 'Haw/Pac Isl.'
   if row['eri_white'] == 1:
      return 'White'
   return 'Other'

Vielleicht möchten Sie dies noch einmal durchgehen, aber es scheint zu funktionieren – beachten Sie, dass der Parameter, der in die Funktion geht, als ein Series-Objekt mit der Bezeichnung “Zeile” betrachtet wird.

Verwenden Sie als Nächstes die Apply-Funktion in Pandas, um die Funktion anzuwenden – z

df.apply (lambda row: label_race(row), axis=1)

Beachten Sie den Spezifizierer axis=1, was bedeutet, dass die Anwendung auf Zeilen- und nicht auf Spaltenebene erfolgt. Die Ergebnisse sind hier:

0           White
1        Hispanic
2           White
3           White
4           Other
5           White
6     Two Or More
7           White
8    Haw/Pac Isl.
9           White

Wenn Sie mit diesen Ergebnissen zufrieden sind, führen Sie es erneut aus und speichern Sie die Ergebnisse in einer neuen Spalte in Ihrem ursprünglichen Datenrahmen.

df['race_label'] = df.apply (lambda row: label_race(row), axis=1)

Der resultierende Datenrahmen sieht so aus (scrollen Sie nach rechts, um die neue Spalte zu sehen):

      lname   fname rno_cd  eri_afr_amer  eri_asian  eri_hawaiian   eri_hispanic  eri_nat_amer  eri_white rno_defined    race_label
0      MOST    JEFF      E             0          0             0              0             0          1       White         White
1    CRUISE     TOM      E             0          0             0              1             0          0       White      Hispanic
2      DEPP  JOHNNY    NaN             0          0             0              0             0          1     Unknown         White
3     DICAP     LEO    NaN             0          0             0              0             0          1     Unknown         White
4    BRANDO  MARLON      E             0          0             0              0             0          0       White         Other
5     HANKS     TOM    NaN             0          0             0              0             0          1     Unknown         White
6    DENIRO  ROBERT      E             0          1             0              0             0          1       White   Two Or More
7    PACINO      AL      E             0          0             0              0             0          1       White         White
8  WILLIAMS   ROBIN      E             0          0             1              0             0          0       White  Haw/Pac Isl.
9  EASTWOOD   CLINT      E             0          0             0              0             0          1       White         White

Benutzeravatar von Brian Burns
Brian Burns

Da dies das erste Google-Ergebnis für „pandas neue Spalte von anderen“ ist, hier ein einfaches Beispiel:

import pandas as pd

# make a simple dataframe
df = pd.DataFrame({'a':[1,2], 'b':[3,4]})
df
#    a  b
# 0  1  3
# 1  2  4

# create an unattached column with an index
df.apply(lambda row: row.a + row.b, axis=1)
# 0    4
# 1    6

# do same but attach it to the dataframe
df['c'] = df.apply(lambda row: row.a + row.b, axis=1)
df
#    a  b  c
# 0  1  3  4
# 1  2  4  6

Wenn du die bekommst SettingWithCopyWarning du kannst es auch so machen:

fn = lambda row: row.a + row.b # define a function for the new column
col = df.apply(fn, axis=1) # get column data with an index
df = df.assign(c=col.values) # assign values to column 'c'

Quelle: https://stackoverflow.com/a/12555510/243392

Und wenn Ihr Spaltenname Leerzeichen enthält, können Sie folgende Syntax verwenden:

df = df.assign(**{'some column name': col.values})

Und hier ist die Dokumentation für sich bewerbenund zuordnen.

  • Sehr interessante Antwort. Eine Frage, wie können wir tun df.apply(lambda row: row.a + row.b, axis=1) sondern auch die nächste Reihe mit einbeziehen? Ich habe hier eine Frage dazu stackoverflow.com/questions/74792731/…

    – KansaiRobot

    14. Dezember 2022 um 2:45 Uhr

Die obigen Antworten sind vollkommen gültig, aber es gibt eine vektorisierte Lösung in Form von numpy.select. Auf diese Weise können Sie Bedingungen definieren und dann Ausgaben für diese Bedingungen definieren, viel effizienter als mit apply:


Definieren Sie zunächst Bedingungen:

conditions = [
    df['eri_hispanic'] == 1,
    df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1).gt(1),
    df['eri_nat_amer'] == 1,
    df['eri_asian'] == 1,
    df['eri_afr_amer'] == 1,
    df['eri_hawaiian'] == 1,
    df['eri_white'] == 1,
]

Definieren Sie nun die entsprechenden Ausgänge:

outputs = [
    'Hispanic', 'Two Or More', 'A/I AK Native', 'Asian', 'Black/AA', 'Haw/Pac Isl.', 'White'
]

Endlich verwenden numpy.select:

res = np.select(conditions, outputs, 'Other')
pd.Series(res)

0           White
1        Hispanic
2           White
3           White
4           Other
5           White
6     Two Or More
7           White
8    Haw/Pac Isl.
9           White
dtype: object

Warum soll numpy.select vorbei verwendet werden apply? Hier sind einige Leistungsprüfungen:

df = pd.concat([df]*1000)

In [42]: %timeit df.apply(lambda row: label_race(row), axis=1)
1.07 s ± 4.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [44]: %%timeit
    ...: conditions = [
    ...:     df['eri_hispanic'] == 1,
    ...:     df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1).gt(1),
    ...:     df['eri_nat_amer'] == 1,
    ...:     df['eri_asian'] == 1,
    ...:     df['eri_afr_amer'] == 1,
    ...:     df['eri_hawaiian'] == 1,
    ...:     df['eri_white'] == 1,
    ...: ]
    ...:
    ...: outputs = [
    ...:     'Hispanic', 'Two Or More', 'A/I AK Native', 'Asian', 'Black/AA', 'Haw/Pac Isl.', 'White'
    ...: ]
    ...:
    ...: np.select(conditions, outputs, 'Other')
    ...:
    ...:
3.09 ms ± 17 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Verwenden numpy.select gibt uns erheblich verbesserte Leistung, und die Diskrepanz wird nur größer, wenn die Daten wachsen.

Benutzeravatar von Gabrielle Simard-Moore
Gabrielle Simard-Moore

.apply() nimmt als ersten Parameter eine Funktion an; Pass in die label_race funktionieren so:

df['race_label'] = df.apply(label_race, axis=1)

Sie müssen keine Lambda-Funktion erstellen, um eine Funktion zu übergeben.

Benutzeravatar von Mohamed Thasin ah
Mohamed Thasin ah

Versuche dies,

df.loc[df['eri_white']==1,'race_label'] = 'White'
df.loc[df['eri_hawaiian']==1,'race_label'] = 'Haw/Pac Isl.'
df.loc[df['eri_afr_amer']==1,'race_label'] = 'Black/AA'
df.loc[df['eri_asian']==1,'race_label'] = 'Asian'
df.loc[df['eri_nat_amer']==1,'race_label'] = 'A/I AK Native'
df.loc[(df['eri_afr_amer'] + df['eri_asian'] + df['eri_hawaiian'] + df['eri_nat_amer'] + df['eri_white']) > 1,'race_label'] = 'Two Or More'
df.loc[df['eri_hispanic']==1,'race_label'] = 'Hispanic'
df['race_label'].fillna('Other', inplace=True)

O/P:

     lname   fname rno_cd  eri_afr_amer  eri_asian  eri_hawaiian  \
0      MOST    JEFF      E             0          0             0   
1    CRUISE     TOM      E             0          0             0   
2      DEPP  JOHNNY    NaN             0          0             0   
3     DICAP     LEO    NaN             0          0             0   
4    BRANDO  MARLON      E             0          0             0   
5     HANKS     TOM    NaN             0          0             0   
6    DENIRO  ROBERT      E             0          1             0   
7    PACINO      AL      E             0          0             0   
8  WILLIAMS   ROBIN      E             0          0             1   
9  EASTWOOD   CLINT      E             0          0             0   

   eri_hispanic  eri_nat_amer  eri_white rno_defined    race_label  
0             0             0          1       White         White  
1             1             0          0       White      Hispanic  
2             0             0          1     Unknown         White  
3             0             0          1     Unknown         White  
4             0             0          0       White         Other  
5             0             0          1     Unknown         White  
6             0             0          1       White   Two Or More  
7             0             0          1       White         White  
8             0             0          0       White  Haw/Pac Isl.  
9             0             0          1       White         White 

verwenden .loc anstatt apply.

es verbessert die Vektorisierung.

.loc funktioniert auf einfache Weise, maskiert Zeilen basierend auf der Bedingung, wendet Werte auf die eingefrorenen Zeilen an.

Weitere Informationen finden Sie unter .loc-Dokumente

Leistungsmetriken:

Akzeptierte Antwort:

def label_race (row):
   if row['eri_hispanic'] == 1 :
      return 'Hispanic'
   if row['eri_afr_amer'] + row['eri_asian'] + row['eri_hawaiian'] + row['eri_nat_amer'] + row['eri_white'] > 1 :
      return 'Two Or More'
   if row['eri_nat_amer'] == 1 :
      return 'A/I AK Native'
   if row['eri_asian'] == 1:
      return 'Asian'
   if row['eri_afr_amer']  == 1:
      return 'Black/AA'
   if row['eri_hawaiian'] == 1:
      return 'Haw/Pac Isl.'
   if row['eri_white'] == 1:
      return 'White'
   return 'Other'

df=pd.read_csv('dataser.csv')
df = pd.concat([df]*1000)

%timeit df.apply(lambda row: label_race(row), axis=1)

1,15 s ± 46,5 ms pro Schleife (Mittelwert ± std. Abweichung von 7 Läufen mit je 1 Schleife)

Mein Antwortvorschlag:

def label_race(df):
    df.loc[df['eri_white']==1,'race_label'] = 'White'
    df.loc[df['eri_hawaiian']==1,'race_label'] = 'Haw/Pac Isl.'
    df.loc[df['eri_afr_amer']==1,'race_label'] = 'Black/AA'
    df.loc[df['eri_asian']==1,'race_label'] = 'Asian'
    df.loc[df['eri_nat_amer']==1,'race_label'] = 'A/I AK Native'
    df.loc[(df['eri_afr_amer'] + df['eri_asian'] + df['eri_hawaiian'] + df['eri_nat_amer'] + df['eri_white']) > 1,'race_label'] = 'Two Or More'
    df.loc[df['eri_hispanic']==1,'race_label'] = 'Hispanic'
    df['race_label'].fillna('Other', inplace=True)
df=pd.read_csv('s22.csv')
df = pd.concat([df]*1000)

%timeit label_race(df)

24,7 ms ± 1,7 ms pro Schleife (Mittelwert ± std. Abweichung von 7 Läufen mit jeweils 10 Schleifen)

Benutzeravatar von Cottontail
Baumwollschwanz

Wenn wir es inspizieren Quellcode, apply() ist ein syntaktischer Zucker für eine Python for-Schleife (über die apply_series_generator() Methode der FrameApply Klasse). Weil es die Pandas über Kopf hat, ist es im Allgemeinen Langsamer als eine Python-Schleife.

Verwenden Sie möglichst optimierte (vektorisierte) Methoden. Wenn Sie eine Schleife verwenden müssen, verwenden Sie @numba.jit Dekorateur.

1. Nicht verwenden apply() für eine if-else-Leiter

df.apply() ist so ungefähr der langsamste Weg, dies bei Pandas zu tun. Wie in den Antworten von user3483203 und Mohamed Thasin ah gezeigt, je nach Datenrahmengröße, np.select() und df.loc kann 50-300 mal schneller sein als df.apply() um die gleiche Ausgabe zu erzeugen.

Zufällig ist eine Schleifenimplementierung (nicht unähnlich apply()) mit dem @jit Dekorateur aus numba Modul ist (ca. 50-60%) schneller als df.loc und np.select.1

Numba arbeitet mit numpy Arrays, also bevor Sie die jit decorator müssen Sie den Datenrahmen in ein numpy-Array konvertieren. Füllen Sie dann Werte in ein vorinitialisiertes leeres Array ein, indem Sie die Bedingungen in einer Schleife überprüfen. Da numpy-Arrays keine Spaltennamen haben, müssen Sie in der Schleife über ihren Index auf die Spalten zugreifen. Der unbequemste Teil der If-Else-Leiter in der Jitted-Funktion über der One-In apply() greift auf die Spalten über ihre Indizes zu. Ansonsten ist es fast die gleiche Implementierung.

import numpy as np
import numba as nb
@nb.jit(nopython=True)
def conditional_assignment(arr, res):    
    length = len(arr)
    for i in range(length):
        if arr[i][3] == 1:
            res[i] = 'Hispanic'
        elif arr[i][0] + arr[i][1] + arr[i][2] + arr[i][4] + arr[i][5] > 1:
            res[i] = 'Two Or More'
        elif arr[i][0]  == 1:
            res[i] = 'Black/AA'
        elif arr[i][1] == 1:
            res[i] = 'Asian'
        elif arr[i][2] == 1:
            res[i] = 'Haw/Pac Isl.'
        elif arr[i][4] == 1:
            res[i] = 'A/I AK Native'
        elif arr[i][5] == 1:
            res[i] = 'White'
        else:
            res[i] = 'Other'
    return res

# the columns with the boolean data
cols = [c for c in df.columns if c.startswith('eri_')]
# initialize an empty array to be filled in a loop
# for string dtype arrays, we need to know the length of the longest string
# and use it to set the dtype
res = np.empty(len(df), dtype=f"<U{len('A/I AK Native')}")
# pass the underlying numpy array of `df[cols]` into the jitted function
df['rno_defined'] = conditional_assignment(df[cols].values, res)

2. Nicht verwenden apply() für numerische Operationen

Wenn Sie eine neue Zeile hinzufügen müssen, indem Sie zwei Spalten hinzufügen, ist Ihr erster Instinkt vielleicht, zu schreiben

df['c'] = df.apply(lambda row: row['a'] + row['b'], axis=1)

Fügen Sie stattdessen zeilenweise using hinzu sum(axis=1) Methode (bzw + Operator, wenn es nur ein paar Spalten gibt):

df['c'] = df[['a','b']].sum(axis=1)
# equivalently
df['c'] = df['a'] + df['b']

Abhängig von der Datenrahmengröße, sum(1) kann 100 mal schneller sein als apply().

In der Tat werden Sie fast nie brauchen apply() für numerische Operationen auf einem Pandas-Datenrahmen, da er über optimierte Methoden für die meisten Operationen verfügt: Addition (sum(1)), Subtraktion (sub() oder diff()), Multiplikation (prod(1)), Einteilung (div() oder /), Energie (pow()), >, >=, ==, %, //, &, | usw. können alle auf dem gesamten Datenrahmen ohne ausgeführt werden apply().

Angenommen, Sie möchten eine neue Spalte mit der folgenden Regel erstellen:

IF [colC] > 0 THEN RETURN [colA] * [colB]
ELSE RETURN [colA] / [colB]

Unter Verwendung der optimierten Pandas-Methoden kann dies geschrieben werden als

df['new'] = df[['colA','colB']].prod(1).where(df['colC']>0, df['colA'] / df['colB'])

das Äquivalent apply() Lösung ist:

df['new'] = df.apply(lambda row: row.colA * row.colB if row.colC > 0 else row.colA / row.colB, axis=1)

Der Ansatz mit den optimierten Methoden ist 250-mal schneller als das Äquivalent apply() Ansatz für Datenrahmen mit 20.000 Zeilen. Diese Lücke nimmt nur zu, wenn die Datengröße zunimmt (für einen Datenrahmen mit 1 mil Zeilen ist es 365-mal schneller) und der Zeitunterschied wird immer deutlicher.2


1: Im folgenden Ergebnis zeige ich die Leistung der drei Ansätze unter Verwendung eines Datenrahmens mit 24-Mil-Zeilen (dies ist der größte Rahmen, den ich auf meinem Computer erstellen kann). Bei kleineren Frames läuft die numba-Jitted-Funktion auch durchgehend mindestens 50 % schneller als die anderen beiden (Sie können es selbst überprüfen).

def pd_loc(df):
    df['rno_defined'] = 'Other'
    df.loc[df['eri_nat_amer'] == 1, 'rno_defined'] = 'A/I AK Native'
    df.loc[df['eri_asian'] == 1, 'rno_defined'] = 'Asian'
    df.loc[df['eri_afr_amer'] == 1, 'rno_defined'] = 'Black/AA'
    df.loc[df['eri_hawaiian'] == 1, 'rno_defined'] = 'Haw/Pac Isl.'
    df.loc[df['eri_white'] == 1, 'rno_defined'] = 'White'
    df.loc[df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1) > 1, 'rno_defined'] = 'Two Or More'
    df.loc[df['eri_hispanic'] == 1, 'rno_defined'] = 'Hispanic'
    return df

def np_select(df):
    conditions = [df['eri_hispanic'] == 1,
                  df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1).gt(1),
                  df['eri_nat_amer'] == 1,
                  df['eri_asian'] == 1,
                  df['eri_afr_amer'] == 1,
                  df['eri_hawaiian'] == 1,
                  df['eri_white'] == 1]
    outputs = ['Hispanic', 'Two Or More', 'A/I AK Native', 'Asian', 'Black/AA', 'Haw/Pac Isl.', 'White']
    df['rno_defined'] = np.select(conditions, outputs, 'Other')
    return df


@nb.jit(nopython=True)
def conditional_assignment(arr, res):
    
    length = len(arr)
    for i in range(length):
        if arr[i][3] == 1 :
            res[i] = 'Hispanic'
        elif arr[i][0] + arr[i][1] + arr[i][2] + arr[i][4] + arr[i][5] > 1 :
            res[i] = 'Two Or More'
        elif arr[i][0]  == 1:
            res[i] = 'Black/AA'
        elif arr[i][1] == 1:
            res[i] = 'Asian'
        elif arr[i][2] == 1:
            res[i] = 'Haw/Pac Isl.'
        elif arr[i][4] == 1 :
            res[i] = 'A/I AK Native'
        elif arr[i][5] == 1:
            res[i] = 'White'
        else:
            res[i] = 'Other'
            
    return res

def nb_loop(df):
    cols = [c for c in df.columns if c.startswith('eri_')]
    res = np.empty(len(df), dtype=f"<U{len('A/I AK Native')}")
    df['rno_defined'] = conditional_assignment(df[cols].values, res)
    return df

# df with 24mil rows
n = 4_000_000
df = pd.DataFrame({
    'eri_afr_amer': [0, 0, 0, 0, 0, 0]*n, 
    'eri_asian': [1, 0, 0, 0, 0, 0]*n, 
    'eri_hawaiian': [0, 0, 0, 1, 0, 0]*n, 
    'eri_hispanic': [0, 1, 0, 0, 1, 0]*n, 
    'eri_nat_amer': [0, 0, 0, 0, 1, 0]*n, 
    'eri_white': [0, 0, 1, 1, 0, 0]*n
}, dtype="int8")
df.insert(0, 'name', ['MOST', 'CRUISE', 'DEPP', 'DICAP', 'BRANDO', 'HANKS']*n)

%timeit nb_loop(df)
# 5.23 s ± 45.2 ms per loop (mean ± std. dev. of 10 runs, 10 loops each)

%timeit pd_loc(df)
# 7.97 s ± 28.8 ms per loop (mean ± std. dev. of 10 runs, 10 loops each)

%timeit np_select(df)
# 8.5 s ± 39.6 ms per loop (mean ± std. dev. of 10 runs, 10 loops each)

2: Im folgenden Ergebnis zeige ich die Leistung der beiden Ansätze mit einem Datenrahmen mit 20.000 Zeilen und erneut mit 1 mil Zeilen. Bei kleineren Frames ist die Lücke kleiner, da der optimierte Ansatz einen zusätzlichen Overhead hat apply() ist eine Schleife. Wenn die Größe des Frames zunimmt, verringern sich die Overhead-Kosten der Vektorisierung in Bezug auf die Gesamtlaufzeit des Codes während apply() bleibt eine Schleife über dem Rahmen.

n = 20_000 # 1_000_000
df = pd.DataFrame(np.random.rand(n,3)-0.5, columns=['colA','colB','colC'])

%timeit df[['colA','colB']].prod(1).where(df['colC']>0, df['colA'] / df['colB'])
# n = 20000: 2.69 ms ± 23.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# n = 1000000: 86.2 ms ± 441 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit df.apply(lambda row: row.colA * row.colB if row.colC > 0 else row.colA / row.colB, axis=1)
# n = 20000: 679 ms ± 33.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# n = 1000000: 31.5 s ± 587 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Benutzeravatar von Sai Pardhu
Sai Pardhu

Wie @ user3483203 betonte, ist numpy.select der beste Ansatz

Speichern Sie Ihre bedingten Anweisungen und die entsprechenden Aktionen in zwei Listen

conds = [(df['eri_hispanic'] == 1),(df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1).gt(1)),(df['eri_nat_amer'] == 1),(df['eri_asian'] == 1),(df['eri_afr_amer'] == 1),(df['eri_hawaiian'] == 1),(df['eri_white'] == 1,])

actions = ['Hispanic', 'Two Or More', 'A/I AK Native', 'Asian', 'Black/AA', 'Haw/Pac Isl.', 'White']

Sie können jetzt np.select mit diesen Listen als Argumente verwenden

df['label_race'] = np.select(conds,actions,default="Other")

Bezug: https://numpy.org/doc/stable/reference/generated/numpy.select.html

1440680cookie-checkErstellen Sie eine neue Spalte basierend auf Werten aus anderen Spalten / wenden Sie eine Funktion mehrerer Spalten zeilenweise in Pandas an

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy