J'ai un Dataframe comme:
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
Je veux trouver la valeur maximale de Durée dans (Durée1, Durée2, Durée3) et renvoyer la valeur et la séquence correspondantes.
Ma sortie souhaitée:
Sequence,Duration3,Value3
1008, 981, 82
Essayez le code suivant, assez court, basé principalement sur 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]]
Le résultat est un série:
Sequence 1008
Duration3 981
Value3 82
Name: 7, dtype: int64
Si vous voulez le "remodeler" (d'abord les valeurs d'index, puis les valeurs réelles), vous pouvez obtenir quelque chose comme ceci en exécutant:
pd.DataFrame([result.values], columns=result.index)
Avec des données étendues, il peut être plus facile de refaçonner d'abord avec wide_to_long
. Cela crée 2 colonnes ['Duration', 'Value']
, et le MultiIndex nous indique de quel numéro il s'agit. Il n'y a aucun recours à un ordre de colonne spécifique.
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
Si je comprends bien la question, compte tenu du cadre de données suivant:
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
Ces 5 lignes de code résolvent votre problème:
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)
Et vous obtenez:
Seq Dur1 Val1
1 2 7 y
J'obtiens automatiquement les colonnes qui commencent par "Dur", et je trouve le nom de la colonne avec une durée plus longue:
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])
Choisissez les colonnes qui m'intéressent:
filter_col = ['Seq', max_dur_name, val_name]
Filtrer les colonnes qui m'intéressent, je commande pour max_dur_name
et j'obtiens le résultat de la recherche:
df_res = df[filter_col].sort_values(max_dur_name, ascending=False).head(1)
# output:
Seq Dur1 Val1
1 2 7 y
Un peu similaire à @ réponse de Massifox , mais je pense que c'est assez différent pour être digne d'être ajouté.
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]]
mvc
où se trouve la valeur maximale (mvc
est 'Durantion3'
suivant votre exemple).mvidx
de la valeur maximale (mvidx
est 7
).valuecol
est 'Value3'
).Enfin avec loc
je sélectionne la sortie souhaitée, qui est:
Sequence 1008
Duration3 981
Value3 82
Name: 7, dtype: int64
Voici une autre façon,
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
numpy
sorcellerie: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]]
Sequence 1008
Duration3 981
Value3 82
Name: 7, dtype: int64
max_value = max(df.filter(like='Dur', axis=1).max().tolist())
, pour renvoyer la valeur maximale dans les colonnes Duration
max_col_name = df.filter(like='Dur', axis=1).max().idxmax()
, pour renvoyer le nom de la colonne où se trouve la valeur maximaletest = ['Duration5', 'Duration2', 'Duration3']
print(max(test))
>>> 'Duration5'
idmax
# 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 ]]
Sequence 1008
Duration3 981
Value3 82
Name: 7, dtype: int64
Vous pouvez obtenir l'index de la valeur maximale d'une colonne en utilisant:
>>> idx = df['Duration3'].idxmax()
>>> idx
7
Et les colonnes pertinentes utilisant uniquement:
>>> df_cols = df[['Sequence', 'Duration3', 'Value3']]
>>> df_cols.loc[idx]
Sequence 1008
Duration3 981
Value3 82
Name: 7, dtype: int64
Donc, tout simplement envelopper tout cela dans une seule fonction Nice:
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]
Et boucle sur 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 vous souhaitez réduire ces 3 à une seule ligne maximale, vous pouvez effectuer les opérations suivantes:
>>> 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
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]])