Encuentra el máximo de dos o más columnas con pandas

101

Tengo una trama de datos con columnas A, B. Necesito crear una columna de Cmodo que para cada registro / fila:

C = max(A, B).

¿Cómo debo hacer esto?

Navneet
fuente

Respuestas:

191

Puede obtener el máximo de esta manera:

>>> import pandas as pd
>>> df = pd.DataFrame({"A": [1,2,3], "B": [-2, 8, 1]})
>>> df
   A  B
0  1 -2
1  2  8
2  3  1
>>> df[["A", "B"]]
   A  B
0  1 -2
1  2  8
2  3  1
>>> df[["A", "B"]].max(axis=1)
0    1
1    8
2    3

y entonces:

>>> df["C"] = df[["A", "B"]].max(axis=1)
>>> df
   A  B  C
0  1 -2  1
1  2  8  8
2  3  1  3

Si sabe que "A" y "B" son las únicas columnas, incluso podría salirse con la suya.

>>> df["C"] = df.max(axis=1)

Y a ti .apply(max, axis=1)también te vendría bien , supongo.

DSM
fuente
1
.apply(max, axis=1)es mucho más lento que.max(axis=1)
RajeshM
28

La respuesta de @ DSM está perfectamente bien en casi cualquier escenario normal. Pero si usted es el tipo de programador que quiere ir un poco más profundo que el nivel de la superficie, es posible que le interese saber que es un poco más rápido llamar a funciones numpy en la matriz subyacente .to_numpy()(o .valuespara <0.24) en lugar de directamente llamando a las funciones (cythonized) definidas en los objetos DataFrame / Series.

Por ejemplo, puede utilizar a lo ndarray.max()largo del primer eje.

# Data borrowed from @DSM's post.
df = pd.DataFrame({"A": [1,2,3], "B": [-2, 8, 1]})
df
   A  B
0  1 -2
1  2  8
2  3  1

df['C'] = df[['A', 'B']].values.max(1)
# Or, assuming "A" and "B" are the only columns, 
# df['C'] = df.values.max(1) 
df

   A  B  C
0  1 -2  1
1  2  8  8
2  3  1  3 

Si sus datos tienen NaNs, necesitará numpy.nanmax:

df['C'] = np.nanmax(df.values, axis=1)
df

   A  B  C
0  1 -2  1
1  2  8  8
2  3  1  3 

También puede utilizar numpy.maximum.reduce. numpy.maximumes una ufunc (función universal) , y cada ufunc tiene unreduce :

df['C'] = np.maximum.reduce(df['A', 'B']].values, axis=1)
# df['C'] = np.maximum.reduce(df[['A', 'B']], axis=1)
# df['C'] = np.maximum.reduce(df, axis=1)
df

   A  B  C
0  1 -2  1
1  2  8  8
2  3  1  3

ingrese la descripción de la imagen aquí

np.maximum.reducey np.maxparecen ser más o menos iguales (para la mayoría de DataFrames de tamaño normal), y resultan ser un poco más rápidos que DataFrame.max. Me imagino que esta diferencia permanece aproximadamente constante y se debe a la sobrecarga interna (alineación de indexación, manejo de NaN, etc.).

El gráfico se generó usando perfplot . Código de evaluación comparativa, como referencia:

import pandas as pd
import perfplot

np.random.seed(0)
df_ = pd.DataFrame(np.random.randn(5, 1000))

perfplot.show(
    setup=lambda n: pd.concat([df_] * n, ignore_index=True),
    kernels=[
        lambda df: df.assign(new=df.max(axis=1)),
        lambda df: df.assign(new=df.values.max(1)),
        lambda df: df.assign(new=np.nanmax(df.values, axis=1)),
        lambda df: df.assign(new=np.maximum.reduce(df.values, axis=1)),
    ],
    labels=['df.max', 'np.max', 'np.maximum.reduce', 'np.nanmax'],
    n_range=[2**k for k in range(0, 15)],
    xlabel='N (* len(df))',
    logx=True,
    logy=True)
cs95
fuente
Pequeño error tipográfico: "df ['C'] = np.maximum.reduce (df ['A', 'B']]. Valores, eje = 1)" debe ser "df ['C'] = np.maximum. reduce (df [['A', 'B']]. valores, eje = 1) "
Velizar VESSELINOV