pandas: Calcule el máximo por filas de columnas categóricas

0

Tengo un DataFrame que contiene 2 columnas de datos categóricos ordenados (de la misma categoría). Quiero construir otra columna que contenga el máximo categórico de las primeras 2 columnas. Configuré lo siguiente.

import pandas as pd
from pandas.api.types import CategoricalDtype
import numpy as np

cats = CategoricalDtype(categories=['small', 'normal', 'large'], ordered=True)
data = {
    'A': ['normal', 'small', 'normal', 'large', np.nan],
    'B': ['small', 'normal', 'large', np.nan, 'small'],
    'desired max(A,B)': ['normal', 'normal', 'large', 'large', 'small']
}
df = pd.DataFrame(data).astype(cats)

Las columnas se pueden comparar, aunque los elementos np.nan son problemáticos, como muestra la ejecución del siguiente código.

df['A'] > df['B']

El manual sugiere que max () funciona con datos categóricos, así que trato de definir mi nueva columna de la siguiente manera.

df[['A', 'B']].max(axis=1)

Esto produce una columna de NaN. ¿Por qué?

0

Las columnas A y B son de tipo cadena. Max no tiene forma de entender cuál es el más grande entre ['pequeño', 'mediano', 'grande']. Así que primero debes asignar valores enteros a cada una de estas categorías.

# size string -> integer value mapping
size2int_map = {
    'small': 0, 
    'normal': 1, 
    'large': 2
}

# integer value -> size string mapping
int2size_map = {
    0: 'small', 
    1: 'normal', 
    2: 'large'
}

# create columns containing the integer value for each size string
for c in df:
    df['%s_int' % c] = df[c].map(size2int_map)

# apply the int2size map back to get the string sizes back
print(df[['A_int', 'B_int']].max(axis=1).map(int2size_map))

y deberías conseguir

0    normal
1    normal
2     large
3     large
4     small
dtype: object
0

El siguiente código construye la columna deseada usando la comparabilidad de las columnas categóricas. Todavía no sé por qué max () falla aquí.

dfA = df['A']
dfB = df['B']
conditions = [dfA.isna(), (dfB.isna() | (dfA >= dfB)), True]
cases = [dfB, dfA, dfB]
df['maxAB'] = np.select(conditions, cases)