Return 基于 Python 中其他行的最大值的行平均值

Return Row Mean Based on Max of Other Rows in Python

我有这个 DataFrame

         A  B  C  A1  B1 C1 
1/1/2021 1  2  7  9   5  7
1/2/2021 4  3  5  3   4  5
1/3/2021 4  6  4  6   7  2  

我想为每一行添加一个新的 D 列 returns 基于 A1、B1、C1 的最大两个值,A、B、C 两列的平均值。因此,如果 A1 和 B1 大于 C1,则 D 列将等于 A 列和 B 列的平均值。

预期输出:

         A  B  C  A1  B1 C1 D
1/1/2021 1  2  7  9   5  7  4 (mean of A and C, since A1 and C1 are the top two)
1/2/2021 4  3  5  3   4  5  4 (mean of B and C, since B1 and C1 are the top two)
1/3/2021 4  6  4  6   7  2  5 (mean of A and B, since A1 and B1 are the top two)

我想我可以使用像下面这样的函数来实现结果(我只是以第一部分为例),写出所有的组合。但我想要一些可以用于大量会改变的列的东西,理想情况下我可以调整 TopN 数。例如,获取前 3 名或前 4 名的平均值,而不是前 2 名的平均值。列的结构始终一致且顺序正确。例如,5列数据用于平均值,5列相同顺序的数据用于确定最大值。

def maxcol(row):  
    if row[A1] >= row[B1] and row[A1] >= row[C1] and row[B1] >= row[C1]:
         val = row[A] + row[B] / 2
    elif: 
         etc etc.
    return val

有没有一种简单的方法可以在不使用上述暴力方法的情况下完成此操作?

更新:我将答案更新为更通用的代码,适用于多列和多个顶部列。

import heapq

df = pd.DataFrame({'A': [1, 4, 4],'B': [2, 3, 6],'C': [7, 5, 4],'A1': [9, 3, 6],'B1': [5, 4, 7],'C1': [7, 5, 2]})

n = 3
t = 2

def helper(row):
    lst = [col for col in row]
    order = [lst[n:].index(x) for x in lst[n:] if x in heapq.nlargest(t,lst[n:])]
    return mean(lst[o] for o in order)

df['D'] = df.apply(helper, axis = 1)
print(df)

如果您有一组值,并且想要删除最低值(或最低的 n 个值,或最高的 n 个值...),我只需对它们的列表进行排序并删除尽可能多的值你喜欢从哪一端开始。所以如果你有一个任意长度的列表,你想去掉最低值然后得到平均值,你可以很容易地这样做:

>>> somelist = [2, 1, 0, 3]
>>> sorted(somelist)[1:]
[1, 2, 3]
>>> sum(_) / len(_)
2.0

这是一种定义辅助函数以应用于数据框的方法:

def helper(row):
    lst = [col for col in row]
    order = [lst[3:].index(x) for x in lst[3:] if x is not min(lst[3:])]
    return int(lst[order[0]] + lst[order[1]]) / 2


df['D'] = df.apply(helper, axis = 1)
print(df)

#output
   A  B  C  A1  B1  C1    D
0  1  2  7   9   5   7  4.0
1  4  3  5   3   4   5  4.0
2  4  6  4   6   7   2  5.0
#notice that I did not include the date indexes in this sample dataframe.

这里是日期时间索引。相同的代码工作正常:

BEFORE:
            A  B  C  A1  B1  C1
2021-01-01  1  2  7   9   5   7
2021-01-02  4  3  5   3   4   5
2021-01-03  4  6  4   6   7   2 

AFTER:
            A  B  C  A1  B1  C1    D
2021-01-01  1  2  7   9   5   7  4.0
2021-01-02  4  3  5   3   4   5  4.0
2021-01-03  4  6  4   6   7   2  5.0

我的代码不够熟练,但我认为可以这样做:

A  B  C  A1  B1 C1 D

所以你有索引 1,2,3,4,5,6,7 1)# 为测试创建了错误的 df

import pandas as pd
import numpy as np
df = pd.DataFrame([1,  2,  7,  9,   5,  7]).T
df
k=(df.loc[:, '3':'5']).idxmin(axis=1) #the position of minimum in A1 B1 C1
#calculation of "wrong" number in abc
wrong =k-3  #you have 3 positions shift
df = df.replace(df.iloc[:, wrong] , np.NaN)##change this element with Nan

#取平均值

df['D']=df.loc[:, '0':'2'].mean(axis=1)

我相信它可以用更简单的方式编码..但算法是。