Получить максимальное значение, сравнивая несколько столбцов и вернуть конкретные значения - PullRequest
14 голосов
/ 21 сентября 2019

У меня есть Dataframe вроде:

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

Я хочу найти максимальное значение Duration в (Duration1, Duration2, Duration3) и вернуть соответствующее значение и последовательность.

MyЖелаемый вывод:

Sequence,Duration3,Value3
1008,    981,      82

Ответы [ 8 ]

11 голосов
/ 21 сентября 2019

Попробуйте следующий, довольно короткий код, основанный в основном на 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]]

В результате получается серия :

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

Если вы хотите «преобразовать» его (сначала индексные значения, затем фактические значения), вы можете получить что-то вроде этого, выполнив:

pd.DataFrame([result.values], columns=result.index)
5 голосов
/ 21 сентября 2019

С широкими данными может быть легче сначала изменить форму с wide_to_long.Это создает 2 столбца ['Duration', 'Value'], и MultiIndex сообщает нам, какой это был номер.Там нет опоры на какой-либо конкретный порядок столбцов.

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
4 голосов
/ 21 сентября 2019

Немного похоже на @ ответ 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. Затем я получаю индекс строки mvidx максимального значения (mvidx равно 7).
  3. Затем я строю правильный столбец значения (valuecol равен 'Value3').
  4. Наконец, с помощью loc я выбираю желаемый вывод, который равен:

    Sequence     1008
    Duration3     981
    Value3         82
    Name: 7, dtype: int64
    
4 голосов
/ 21 сентября 2019

Без использования numpy wizardry:

  • Во-первых, есть некоторые действительно отличные решения этой проблемы, другие.
  • Данные будут предоставлены в вопросе, так как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

Используемые методы:

4 голосов
/ 21 сентября 2019

Вот еще один способ,

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
4 голосов
/ 21 сентября 2019

Если я правильно понимаю вопрос, учитывая следующий фрейм данных:

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

Выберите столбцы Iменя интересует:

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   
4 голосов
/ 21 сентября 2019

Вы можете получить индекс максимального значения столбца, используя:

>>> 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
0 голосов
/ 21 сентября 2019
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]])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...