python - reemplazar - los pandas crean una nueva columna basada en valores de otras columnas/aplican una funciĆ³n de varias columnas, en fila
pandas dataframe eliminar columna (5)
Dado que este es el primer resultado de Google para ''pandas nueva columna de otros'', aquí hay un ejemplo 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 obtiene
SettingWithCopyWarning
también puede hacerlo de esta manera:
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''
Fuente: https://stackoverflow.com/a/12555510/243392
Y si el nombre de su columna incluye espacios, puede usar una sintaxis como esta:
df = df.assign(**{''some column name'': col.values})
Quiero aplicar mi función personalizada (usa una escalera if-else) a estas seis columnas (
ERI_Hispanic
,
ERI_AmerInd_AKNatv
,
ERI_Asian
,
ERI_Black_Afr.Amer
,
ERI_HI_PacIsl
,
ERI_White
) en cada fila de mi marco de datos.
He probado diferentes métodos de otras preguntas, pero parece que todavía no puedo encontrar la respuesta correcta para mi problema. La parte crítica de esto es que si la persona se cuenta como hispana, no se puede contar como otra cosa. Incluso si tienen un "1" en otra columna de etnia, todavía se cuentan como hispanos, no dos o más razas. Del mismo modo, si la suma de todas las columnas ERI es mayor que 1, se cuentan como dos o más razas y no se pueden contar como una etnia única (excepto para los hispanos). Esperemos que esto tenga sentido. Cualquier ayuda será apreciada.
Es casi como hacer un ciclo for a través de cada fila y si cada registro cumple con un criterio, se agregan a una lista y se eliminan del original.
Del siguiente marco de datos necesito calcular una nueva columna basada en la siguiente especificación en SQL:
========================= CRITERIOS ======================== =======
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”
Comentario: Si la bandera ERI para hispanos es verdadera (1), el empleado se clasifica como "hispano"
Comentario: si más de 1 bandera ERI no hispana es verdadera, devuelva "Dos o más"
====================== 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
De acuerdo, dos pasos para esto, primero es escribir una función que haga la traducción que desea, he reunido un ejemplo basado en su pseudocódigo:
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''
Es posible que desee repasar esto, pero parece ser el truco: tenga en cuenta que el parámetro que entra en la función se considera un objeto Serie etiquetado como "fila".
Luego, use la función de aplicar en pandas para aplicar la función, por ejemplo
df.apply (lambda row: label_race(row), axis=1)
Tenga en cuenta el especificador axis = 1, eso significa que la aplicación se realiza en una fila, en lugar de un nivel de columna. Los resultados están aquí:
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 está satisfecho con esos resultados, ejecútelos nuevamente, guardando los resultados en una nueva columna en su marco de datos original.
df[''race_label''] = df.apply (lambda row: label_race(row), axis=1)
El marco de datos resultante tiene este aspecto (desplácese hacia la derecha para ver la nueva columna):
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
Las respuestas anteriores son perfectamente válidas, pero existe una solución vectorizada, en forma de
numpy.select
.
Esto le permite definir condiciones, luego definir salidas para esas condiciones, mucho más eficientemente que usar
apply
:
Primero, defina las condiciones:
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,
]
Ahora, defina las salidas correspondientes:
outputs = [
''Hispanic'', ''Two Or More'', ''A/I AK Native'', ''Asian'', ''Black/AA'', ''Haw/Pac Isl.'', ''White''
]
Finalmente, usando
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
¿Por qué debería
numpy.select
sobre
apply
?
Aquí hay algunas comprobaciones de rendimiento:
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)
El uso de
numpy.select
nos brinda un rendimiento
enormemente
mejorado, y la discrepancia solo aumentará a medida que
numpy.select
los datos.
prueba esto,
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
use
.loc
lugar de
apply
.
Mejora la vectorización.
.loc
funciona de manera simple, enmascarar filas según la condición, aplicar valores a las filas congeladas.
para más detalles visite, .loc docs
Métricas de rendimiento:
Respuesta aceptada:
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 por ciclo (media ± estándar de desarrollo de 7 carreras, 1 ciclo cada una)
Mi respuesta propuesta:
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 por bucle (media ± desviación estándar de 7 ejecuciones, 10 bucles cada una)
.apply()
toma una función como primer parámetro;
Pase la función
label_race
la
label_race
manera:
df[''race_label''] = df.apply(label_race, axis=1)
No necesita hacer una función lambda para pasar una función.