python - 獲取比較多個列的最大值並返回特定值




python-3.x pandas (6)

我有一個像這樣的數據框:

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

我想在(Duration1,Duration2,Duration3)中找到Duration的最大值,然後返回相應的Value&Sequence。

我想要的輸出:

Sequence,Duration3,Value3
1008,    981,      82

不使用 numpy 嚮導:

  • 首先,其他人確實有一些非常好的解決方案。
  • 數據將是問題中提供的數據,例如 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

更新

  • 昨晚,實際上是凌晨4點,我放棄了更好的解決方案,因為我太累了。
    • 我使用 max_value = max(df.filter(like='Dur', axis=1).max().tolist()) 來返回 Duration 列中的最大值
    • 代替 max_col_name = df.filter(like='Dur', axis=1).max().idxmax() ,返回出現最大值的列名
    • 我之所以這樣做,是因為我的大腦不停地告訴我,我返回的是列名的最大值,而不是列中的最大值。 例如:
test = ['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

使用的方法:


如果我正確理解了這個問題,請考慮以下數據框:

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

這5行代碼解決了您的問題:

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)

你會得到:

   Seq  Dur1 Val1 
1    2     7    y  

代碼說明:

我自動獲得以'Dur'開頭的列,並且發現持續時間更長的列名稱:

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]

過濾我感興趣的列,我為 max_dur_name 訂購,然後得到搜索結果:

df_res = df[filter_col].sort_values(max_dur_name, ascending=False).head(1)

# output:
   Seq  Dur1 Val1 
1    2     7    y   

您可以使用以下方法獲取列最大值的索引:

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

和相關的列僅使用:

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

因此,只需將所有內容包裝到一個不錯的函數中:

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]

並循環 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

如果要將這3個減少到單個最大行,可以執行以下操作:

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

有點類似於 @Massifox的答案 ,但我認為有很大的不同,值得添加。

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. 首先,我得到最大值位於的列名稱 mvc 在您的示例中, mvc'Durantion3' )。
  2. 然後我得到最大值的行索引 mvidxmvidx7 )。
  3. 然後,我構建正確的Value列( valuecol'Value3' )。
  4. 最後,使用 loc 選擇所需的輸出,即:

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

這是另一種方式,

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

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




dataframe