Cree una nueva columna basada en valores de otras columnas / aplique una función de varias columnas, en filas en Pandas

16 minutos de lectura

Avatar de usuario de Dave
dave

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 etnicidad, todavía se cuentan como hispanos, no como dos o más razas. De manera similar, 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 única etnia (excepto para los hispanos).

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.

Desde el marco de datos a continuación, 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 Hispano 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”

MARCO DE DATOS

     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

  • Para esta tarea, apply parece obvio pero no úselo porque es solo un bucle sobre las filas. Hay mejores maneras de hacerlo. Ejemplos: aquí, aquí, aquí.

    – rabo de algodón

    17 de noviembre a las 21:37

Avatar de usuario de Thomas Kimber
Tomas Kimber

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 funcionar: observe que el parámetro que ingresa a la función se considera un objeto Serie etiquetado como “fila”.

A continuación, use la función de aplicación 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, lo que 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, vuelva a ejecutarlo y guarde 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 se ve así (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

Avatar de usuario de Brian Burns
Brian quema

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 obtienes el SettingWithCopyWarning puedes hacerlo de esta manera también:

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})

Y aquí está la documentación para solicitary asignar.

  • Respuesta muy interesante. Una pregunta, ¿cómo podemos hacer df.apply(lambda row: row.a + row.b, axis=1) pero también involucrando la siguiente fila? Tengo una pregunta sobre esto aquí stackoverflow.com/questions/74792731/…

    – Robot Kansai

    14 de diciembre a las 2:45

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

Porque deberia numpy.select ser usado 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)

Usando numpy.select Nos da vastamente rendimiento mejorado, y la discrepancia solo aumentará a medida que crezcan los datos.

Avatar de usuario de Gabrielle Simard-Moore
Gabrielle Simard-Moore

.apply() toma una función como primer parámetro; pasar en el label_race funcionar como tal:

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

No necesita hacer una función lambda para pasar una función.

Avatar de usuario de Mohamed Thasin ah
Mohamed Thasin ah

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 

usar .loc en vez de apply.

mejora la vectorización.

.loc funciona de manera simple, enmascara filas según la condición, aplica valores a las filas congeladas.

para más detalles visita, documentos .loc

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 bucle (media ± desviación estándar de 7 ejecuciones, 1 bucle 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)

avatar de usuario de cottontail
conejo

Si inspeccionamos su código fuente, apply() es un azúcar sintáctico para un bucle for de Python (a través de la apply_series_generator() metodo de la FrameApply clase). Debido a que tiene los pandas por encima, por lo general es Más lento que un bucle de Python.

Utilice métodos optimizados (vectorizados) siempre que sea posible. Si tiene que usar un bucle, use @numba.jit decorador.

1. No use apply() para una escalera if-else

df.apply() es casi la forma más lenta de hacer esto en pandas. Como se muestra en las respuestas de user3483203 y Mohamed Thasin ah, según el tamaño del marco de datos, np.select() y df.loc puede ser 50-300 veces más rápido que df.apply() para producir la misma salida.

Da la casualidad de que una implementación de bucle (no muy diferente apply()) con el @jit decorador de numba módulo es (alrededor de 50-60%) más rápido que df.loc y np.select.1

Numba funciona en matrices numpy, así que antes de usar el jit decorador, debe convertir el marco de datos en una matriz numpy. Luego complete los valores en una matriz vacía preinicializada al verificar las condiciones en un bucle. Dado que las matrices numpy no tienen nombres de columna, debe acceder a las columnas por su índice en el bucle. La parte más inconveniente de la escalera if-else en la función jitted sobre la de apply() está accediendo a las columnas por sus índices. De lo contrario, es casi la misma implementación.

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. No use apply() para operaciones numéricas

Si necesita agregar una nueva fila agregando dos columnas, su primer instinto puede ser escribir

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

Pero en lugar de esto, agrega filas usando sum(axis=1) método (o + operador si solo hay un par de columnas):

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

Dependiendo del tamaño del marco de datos, sum(1) puede ser cientos de veces más rápido que apply().

De hecho, casi nunca necesitará apply() para operaciones numéricas en un marco de datos de pandas porque tiene métodos optimizados para la mayoría de las operaciones: adición (sum(1)), resta (sub() o diff()), multiplicación (prod(1)), división (div() o /), poder (pow()), >, >=, ==, %, //, &, | etc. todo se puede realizar en todo el marco de datos sin apply().

Por ejemplo, supongamos que desea crear una nueva columna utilizando la siguiente regla:

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

Usando los métodos optimizados de pandas, esto se puede escribir como

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

el equivalente apply() la solución es:

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

El enfoque que utiliza los métodos optimizados es 250 veces más rápido que el equivalente apply() enfoque para marcos de datos con 20k filas. Esta brecha solo aumenta a medida que aumenta el tamaño de los datos (para un marco de datos con 1 mil filas, es 365 veces más rápido) y la diferencia de tiempo será cada vez más notable.2


1: En el siguiente resultado, muestro el rendimiento de los tres enfoques utilizando un marco de datos con 24 mil filas (este es el marco más grande que puedo construir en mi máquina). Para marcos más pequeños, la función numba-jitted también se ejecuta consistentemente al menos un 50% más rápido que los otros dos (puede comprobarlo usted mismo).

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: En el resultado a continuación, muestro el rendimiento de los dos enfoques utilizando un marco de datos con filas de 20k y nuevamente con filas de 1 mil. Para marcos más pequeños, la brecha es menor porque el enfoque optimizado tiene una sobrecarga mientras que apply() es un bucle. A medida que aumenta el tamaño del marco, el costo general de la vectorización disminuye en comparación con el tiempo de ejecución general del código, mientras que apply() sigue siendo un bucle sobre el marco.

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)

Avatar de usuario de Sai Pardhu
Sai Pardhu

Como señaló @ user3483203, numpy.select es el mejor enfoque

Almacene sus declaraciones condicionales y las acciones correspondientes en dos listas

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']

Ahora puede usar np.select usando estas listas como sus argumentos

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

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

¿Ha sido útil esta solución?