web-dev-qa-db-ja.com

複数の列を比較して最大値を取得し、特定の値を返す

私は次のようなデータフレームを持っています:

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)で期間の最大値を検索し、対応する値とシーケンスを返します。

私の望ましい出力:

Sequence,Duration3,Value3
1008,    981,      82
18
Rohit Lamba K

主に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]]

結果はSeriesです。

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

それを "再現"したい場合(最初のインデックス値、次に実際の値)、次のようなものを実行できます。

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

幅の広いデータを使用すると、最初に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
5
ALollz

私が質問を正しく理解した場合、次のデータフレームが与えられます:

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

@ 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を取得します(mvidx7)。
  3. 次に、正しいValue列を作成します(valuecol is 'Value3')。
  4. 最後にlocを使用して、目的の出力を選択します。

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

ここに別の方法があります、

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
anky_91

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
_

使用される方法:

4

以下を使用して、列の最大値のインデックスを取得できます。

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

したがって、これらすべてを1つの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]

そして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
4
Mateen Ulhaq
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]])
0
vBrail