use*_*490 4 max dataframe pandas argmax
论坛上有很多例子,如何找到具有相应列名的行的最大值。一些例子在这里或这里
我想做的是对上面的例子进行一些具体的修改。我的数据框看起来像这样,其中所有列都是从左到右编号的(这个顺序非常重要):
x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10
0 0 1 2 2 0 0 0 0 0
4 4 0 4 4 1 0 0 0 0
0 0 1 2 3 0 0 0 0 0
Run Code Online (Sandbox Code Playgroud)
现在,我想在每行末尾创建 6 个新列,其中包含列名称和行中的最大值。
x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10 Max1 ValMax1 Max2 ValMax2 Max3 ValMax3
0 0 1 2 2 0 0 0 0 0
4 4 0 4 4 1 0 0 0 0
0 0 1 2 3 0 0 0 0 0
Run Code Online (Sandbox Code Playgroud)
如果某行的 max 个数超过 1(例如第一行中的值 2),我想在 Max1 列中仅保存一个具有最小索引的列名。在这种情况下,第二大值也是2,但相应的列有更大的索引。这意味着,“Max(y)”列中只需要保存一个列名。这是主要条件。在这种情况下,如果某行有超过 3 个最大值,则只需保存索引最小的 3 个列名。所以最终的输出应该是这样的 DF:
x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10 Max1 ValMax1 Max2 ValMax2 Max3 ValMax3
0 0 1 2 2 0 0 0 0 0 x_4 2 x_5 2 x_3 1
4 4 0 4 4 1 0 0 0 0 x_1 4 x_2 4 x_4 4
0 0 1 2 3 0 0 0 0 0 x_5 3 x_4 2 x_3 1
Run Code Online (Sandbox Code Playgroud)
总结一下,我们得到了下一个结果:在第一行中 4 < 5,这意味着 4 首先出现(无论如何,第二个 2 立即出现在下一列中)。在第二行 1 < 2 < 4 < 5 中,我们只有 3 列,因此最终结果中缺少 5。在第三行中,索引不起作用,因为该行中的值完全不同。这也是主要条件。
在 NumPy 中执行此操作似乎更有意义,然后在末尾获取列名称。
我编写了一个函数,可用于获取n数组的顶部索引。它的工作原理是先使用np.nanargmax然后将值屏蔽为 NaN,然后再执行一次。(可能有更好的方法来做到这一点,但这只是我首先想到的。)
def argmax_n(arr: np.array, n: int, axis=None):
arr = arr.astype('float')
argmaxes = []
for _ in range(n):
argmax = np.nanargmax(arr, axis=axis, keepdims=True)
argmaxes.append(argmax)
np.put_along_axis(arr, argmax, np.NAN, axis=axis)
return argmaxes
Run Code Online (Sandbox Code Playgroud)
像这样使用:
a = df.to_numpy()
argmax_3 = argmax_n(a, 3, axis=1)
Run Code Online (Sandbox Code Playgroud)
然后你可以构建你想要的 DataFrame,.join如果需要的话可以使用原始的 DataFrame。
max_data = {}
for i, arg in enumerate(argmax_3, start=1):
max_data[f'Max{i}'] = df.columns[arg.flatten()]
max_data[f'ValMax{i}'] = np.take_along_axis(a, arg, axis=1).flatten()
pd.DataFrame(max_data)
Run Code Online (Sandbox Code Playgroud)
Max1 ValMax1 Max2 ValMax2 Max3 ValMax3
0 x_4 2 x_5 2 x_3 1
1 x_1 4 x_2 4 x_4 4
2 x_5 3 x_4 2 x_3 1
Run Code Online (Sandbox Code Playgroud)
为了获得有效的方法,您需要向量化,为此使用numpy和索引argpartition:
import numpy as np
N = 3
# convert to arrays
# and reverse to preserve order
# of min index in case of a tie
cols = df.columns.to_numpy()[::-1]
a = df.loc[:, ::-1].to_numpy()
# get the top N indices
idx = np.argpartition(a, -N)[:, :-N-1:-1]
# get the top names
names = cols[idx]
# get the top values
values = np.take_along_axis(a, idx, axis=1)
# or
values = a[np.arange(len(a))[:,None], idx]
# assign to new columns
df[[f'{x}{i+1}' for i in range(N) for x in ['Max', 'ValMax']]
] = (np.dstack([names, values])
.reshape(len(df), -1)
)
Run Code Online (Sandbox Code Playgroud)
输出:
x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10 Max1 ValMax1 Max2 ValMax2 Max3 ValMax3
0 0 0 1 2 2 0 0 0 0 0 x_4 2 x_5 2 x_3 1
1 4 4 0 4 4 1 0 0 0 0 x_1 4 x_2 4 x_4 4
2 0 0 1 2 3 0 0 0 0 0 x_5 3 x_4 2 x_3 1
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
159 次 |
| 最近记录: |