python python-3.x pandas dataframe

python - Obtenga el valor máximo comparando varias columnas y devuelva valores específicos



python-3.x pandas (8)

Sin usar hechicería numpy :

  • Primero, hay algunas soluciones realmente buenas para este problema, por otros.
  • Los datos serán los proporcionados en la pregunta, como df

# find the max value in the Duration columns max_value = max(df.filter(like=''Dur'', axis=1).max().tolist()) # get a Boolean match of the dataframe for max_value df_max = df[df == mv] # get the row index max_index = df_max.dropna(how=''all'').index[0] # get the column name max_col = df_max.dropna(axis=1, how=''all'').columns[0] # get column index max_col_index = df.columns.get_loc(max_col) # final df.iloc[max_index, [0, max_col_index, max_col_index + 1]]

Salida:

Sequence 1008 Duration3 981 Value3 82 Name: 7, dtype: int64

Actualizar

  • Anoche, en realidad a las 4 am, descarté una mejor solución, porque estaba demasiado cansada.
    • max_value = max(df.filter(like=''Dur'', axis=1).max().tolist()) , para devolver el valor máximo dentro de las columnas Duration
    • En lugar de max_col_name = df.filter(like=''Dur'', axis=1).max().idxmax() , para devolver el nombre de la columna donde se produce el valor máximo
    • Lo hice porque mi cerebro confundido me dijo que estaba devolviendo el valor máximo de los nombres de columna, en lugar del valor máximo en la columna. Por ejemplo:

test = [''Duration5'', ''Duration2'', ''Duration3''] print(max(test)) >>> ''Duration5''

  • Esta es la razón por la cual estar cansado es una mala condición para resolver problemas
  • Con el sueño y el café, una solución más eficiente.
    • Similar a otros, en el uso de idmax

Solución nueva y mejorada:

# column name with max duration value max_col_name = df.filter(like=''Dur'', axis=1).max().idxmax() # index of max_col_name max_col_idx =df.columns.get_loc(max_col_name) # row index of max value in max_col_name max_row_idx = df[max_col_name].idxmax() # output with .loc df.iloc[max_row_idx, [0, max_col_idx, max_col_idx + 1 ]]

Salida:

Sequence 1008 Duration3 981 Value3 82 Name: 7, dtype: int64

Métodos utilizados:

Tengo un Dataframe como:

Sequence Duration1 Value1 Duration2 Value2 Duration3 Value3 1001 145 10 125 53 458 33 1002 475 20 175 54 652 45 1003 685 57 687 87 254 88 1004 125 54 175 96 786 96 1005 475 21 467 32 526 32 1006 325 68 301 54 529 41 1007 125 97 325 85 872 78 1008 129 15 429 41 981 82 1009 547 47 577 52 543 83 1010 666 65 722 63 257 87

Quiero encontrar el valor máximo de Duración en (Duración1, Duración2, Duración3) y devolver el Valor y la secuencia correspondientes.

Mi salida deseada:

Sequence,Duration3,Value3 1008, 981, 82


Aquí hay otra manera,

m=df.set_index(''Sequence'') #set Sequence as index n=m.filter(like=''Duration'') #gets all columns with the name Duration s=n.idxmax()[n.eq(n.values.max()).any()] #output Duration3 1008 d = dict(zip(m.columns[::2],m.columns[1::2])) #create a mapper dict #{''Duration1'': ''Value1'', ''Duration2'': ''Value2'', ''Duration3'': ''Value3''} final=m.loc[s.values,s.index.union(s.index.map(d))].reset_index()

Sequence Duration3 Value3 0 1008 981 82


Con datos anchos, puede ser más fácil reformar primero con wide_to_long . Esto crea 2 columnas [''Duration'', ''Value''] , y el MultiIndex nos dice qué número era. No se depende de ningún orden de columnas específico.

import pandas as pd df = pd.wide_to_long(df, i=''Sequence'', j=''num'', stubnames=[''Duration'', ''Value'']) df.loc[[df.Duration.idxmax()]] Duration Value Sequence num 1008 3 981 82


Pruebe el siguiente código bastante corto, basado principalmente en Numpy :

vv = df.iloc[:, 1::2].values iRow, iCol = np.unravel_index(vv.argmax(), vv.shape) iCol = iCol * 2 + 1 result = df.iloc[iRow, [0, iCol, iCol + 1]]

El resultado es una serie :

Sequence 1008 Duration3 981 Value3 82 Name: 7, dtype: int64

Si desea "reformarlo" (primero valores de índice, luego valores reales), puede obtener algo como esto ejecutándose:

pd.DataFrame([result.values], columns=result.index)


Puede obtener el índice del valor máximo de una columna usando:

>>> idx = df[''Duration3''].idxmax() >>> idx 7

Y las columnas relevantes solo usan:

>>> df_cols = df[[''Sequence'', ''Duration3'', ''Value3'']] >>> df_cols.loc[idx] Sequence 1008 Duration3 981 Value3 82 Name: 7, dtype: int64

Entonces, simplemente envuelva todo eso en una buena función:

def get_max(df, i): idx = df[f''Duration{i}''].idxmax() df_cols = df[[''Sequence'', f''Duration{i}'', f''Value{i}'']] return df_cols.loc[idx]

Y 1..3 sobre 1..3 :

>>> max_rows = [get_max(i) for i in range(1, 4)] >>> print(''/n/n''.join(map(str, max_rows))) Sequence 1003 Duration1 685 Value1 57 Name: 2, dtype: int64 Sequence 1010 Duration2 722 Value2 63 Name: 9, dtype: int64 Sequence 1008 Duration3 981 Value3 82 Name: 7, dtype: int64

Si desea reducir estos 3 a una sola fila máxima, puede hacer lo siguiente:

>>> pairs = enumerate(max_rows, 1) >>> by_duration = lambda x: x[1][f''Duration{x[0]}''] >>> i, max_row = max(pairs, key=by_duration) >>> max_row Sequence 1008 Duration3 981 Value3 82 Name: 7, dtype: int64


Si entiendo la pregunta correctamente, dado el siguiente marco de datos:

df = pd.DataFrame(data={''Seq'': [1, 2, 3], ''Dur1'': [2, 7, 3],''Val1'': [''x'', ''y'', ''z''],''Dur2'': [3, 5, 1], ''Val2'': [''a'', ''b'', ''c'']}) Seq Dur1 Val1 Dur2 Val2 0 1 2 x 3 a 1 2 7 y 5 b 2 3 3 z 1 c

Estas 5 líneas de código resuelven su problema:

dur_col = [col_name for col_name in df.columns if col_name.startswith(''Dur'')] # [''Dur1'', ''Dur2''] max_dur_name = df.loc[:, dur_col].max().idxmax() val_name = "Val" + str([int(s) for s in max_dur_name if s.isdigit()][0]) filter_col = [''Seq'', max_dur_name, val_name] df_res = df[filter_col].sort_values(max_dur_name, ascending=False).head(1)

Y obtienes:

Seq Dur1 Val1 1 2 7 y

Explicación del código:

Obtengo automáticamente las columnas que comienzan con ''Dur'', y encuentro el nombre de la columna con una duración más larga:

dur_col = [col_name for col_name in df.columns if col_name.startswith(''Dur'')] # [''Dur1'', ''Dur2''] max_dur_name = df.loc[:, dur_col].max().idxmax() val_name = "Val" + str([int(s) for s in max_dur_name if s.isdigit()][0])

Elija las columnas que me interesan:

filter_col = [''Seq'', max_dur_name, val_name]

Filtre las columnas que me interesan, ordeno max_dur_name y obtengo el resultado de búsqueda:

df_res = df[filter_col].sort_values(max_dur_name, ascending=False).head(1) # output: Seq Dur1 Val1 1 2 7 y


Un poco similar a la respuesta de @ Massifox , pero creo que es lo suficientemente diferente como para ser digno de ser agregado.

mvc = df[[name for name in df.columns if ''Duration'' in name]].max().idxmax() mvidx = df[mvc].idxmax() valuecol = ''Value'' + mvc[-1] df.loc[mvidx, [''Sequence'', mvc, valuecol]]

  1. Primero obtengo el nombre de columna mvc donde se encuentra el valor máximo ( mvc es ''Durantion3'' siguiendo su ejemplo).
  2. Luego obtengo el índice de fila mvidx del valor máximo ( mvidx es 7 ).
  3. Luego construyo la columna Value correcta ( valuecol es ''Value3'' ).
  4. Finalmente con loc selecciono la salida deseada, que es:

    Sequence 1008 Duration3 981 Value3 82 Name: 7, dtype: int64


if len(df[df[dur1]>=df[dur2].max()])==0: if len(df[df[dur2]>=df[dur3].max()])==0: print(df[df[dur3].idmax()][[seq,dur3,val3]]) else: print(df[df[dur2].idmax()][[seq,dur2,val2]]) else: if len(df[df[dur1]>=df[dur3].max()])==0: print(df[df[dur3].idmax()][[seq,dur3,val3]]) else: print(df[df[dur1].idmax()][[seq,dur1,val1]])