python - احصل على القيمة القصوى لمقارنة أعمدة متعددة وإرجاع قيم محددة




python-3.x pandas (6)

بدون استخدام معالج 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

تحديث

  • الليلة الماضية ، في الواقع في الرابعة صباحًا ، رفضت حلاً أفضل ، لأنني كنت متعبًا جدًا.
    • لقد استخدمت 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

الأساليب المستخدمة:

لدي 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

أريد العثور على الحد الأقصى لقيمة المدة في (المدة 1 ، المدة 2 ، المدة 3) وإرجاع القيمة التسلسلية المقابلة.

مخرجاتي المطلوبة:

Sequence,Duration3,Value3
1008,    981,      82

إذا فهمت السؤال بشكل صحيح ، بالنظر إلى قاعدة البيانات التالية:

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

هذه الأسطر الخمسة للشفرة تحل مشكلتك:

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

جرب ما يلي ، رمز قصير للغاية ، يعتمد بشكل أساسي على 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)

من خلال البيانات الواسعة ، قد يكون من الأسهل أولاً إعادة wide_to_long باستخدام wide_to_long . يؤدي هذا إلى إنشاء عمودين ['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

يمكنك الحصول على فهرس الحد الأقصى لقيمة العمود باستخدام:

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

إذا كنت ترغب في تقليل هذه العناصر الثلاثة إلى صف واحد كحد أقصى ، يمكنك القيام بما يلي:

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




dataframe