Je veux appliquer ma fonction personnalisée (elle utilise une échelle if-else) à ces six colonnes (ERI_Hispanic
, ERI_AmerInd_AKNatv
, ERI_Asian
, ERI_Black_Afr.Amer
, ERI_HI_PacIsl
, ERI_White
) dans chaque ligne de mon dataframe.
J’ai essayé différentes méthodes provenant d’autres questions mais je n’ai toujours pas trouvé la bonne réponse à mon problème. L'élément critique est que si la personne est considérée comme hispanique, elle ne peut pas être considérée comme autre chose. Même si elle a un "1" ; dans une autre colonne d'ethnicité, elle est toujours comptée comme hispanique et non comme une personne de deux races ou plus. De même, si la somme de toutes les colonnes ERI est supérieure à 1, ils sont comptés comme deux races ou plus et ne peuvent pas être comptés comme une seule ethnie (sauf hispanique). J'espère que tout cela a un sens. Toute aide sera grandement appréciée.
C'est presque comme si l'on effectuait une boucle for à travers chaque ligne et que si chaque enregistrement répond à un critère, il est ajouté à une liste et éliminé de la première.
À partir du cadre de données ci-dessous, je dois calculer une nouvelle colonne basée sur la spécification suivante en SQL :
========================= CRITERIA ===============================
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”
Commentaire : Si le drapeau ERI pour Hispanique est Vrai (1), l'employé est classé comme "Hispanique".
Commentaire : Si plus d'un drapeau ERI non hispanique est vrai, renvoyer "Deux ou plus".
====================== DATAFRAME ===========================
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
OK, il y a deux étapes à suivre : la première consiste à écrire une fonction qui effectue la traduction que vous souhaitez. J'ai créé un exemple à partir de votre pseudo-code :
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'
Vous voudrez peut-être le revoir, mais il semble faire l'affaire - remarquez que le paramètre entrant dans la fonction est considéré comme un objet Series étiqueté "row" ;.
Ensuite, utilisez la fonction apply de pandas pour appliquer la fonction, par exemple
df.apply (lambda row: label_race(row), axis=1)
Notez le spécificateur axis=1, qui signifie que l'application est effectuée au niveau de la ligne, plutôt que de la colonne. Les résultats sont ici :
0 White
1 Hispanic
2 White
3 White
4 Other
5 White
6 Two Or More
7 White
8 Haw/Pac Isl.
9 White
Si vous êtes satisfait de ces résultats, exécutez à nouveau l'application, en enregistrant les résultats dans une nouvelle colonne de votre cadre de données d'origine.
df['race_label'] = df.apply (lambda row: label_race(row), axis=1)
Le cadre de données résultant ressemble à ceci (faites défiler vers la droite pour voir la nouvelle colonne) :
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
Puisqu'il s'agit du premier résultat Google pour 'pandas new column from others' ;, voici un exemple simple :
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
Si vous obtenez le SettingWithCopyWarning
, vous pouvez aussi le faire de cette façon :
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'
Source : https://stackoverflow.com/a/12555510/243392
Et si le nom de votre colonne comprend des espaces, vous pouvez utiliser une syntaxe comme celle-ci :
df = df.assign(**{'some column name': col.values})
Et voici la documentation pour [apply][1], et [assign][2].
[1] : https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.apply.html [2] : https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.assign.html
.apply()
prend une fonction comme premier paramètre ; passez la fonction label_race
comme tel :
df['race_label'] = df.apply(label_race, axis=1)
Vous n'avez pas besoin de créer une fonction lambda pour passer une fonction.