在 pandas 中将行中的最大值设置为 1,其余设置为 0
Posted
技术标签:
【中文标题】在 pandas 中将行中的最大值设置为 1,其余设置为 0【英文标题】:Setting highest value in row to 1 and rest to 0 in pandas 【发布时间】:2018-11-05 07:11:34 【问题描述】:我的原始数据框如下所示:
A B C
0.10 0.83 0.07
0.40 0.30 0.30
0.70 0.17 0.13
0.72 0.04 0.24
0.15 0.07 0.78
我希望每一行都被二值化:1 将分配给具有最高值的列,其余的将设置为 0,因此前一个数据帧将变为:
A B C
0 1 0
1 0 0
1 0 0
1 0 0
0 0 1
如何做到这一点? 谢谢。
编辑:我知道一个特定的案例使我的问题模棱两可。我应该说,如果给定行的 3 列相等,我仍然希望获得一个 [1 0 0] 向量,而不是该行的 [1 1 1]。
【问题讨论】:
你如何对待像0.333, 0.333, 0.333
这样的列?
鉴于我在数据框中的浮点精度,我认为不会出现这样的问题。但如果发生这种情况,我不介意将“1”随机分配给三列之一,其余为 0。
如果你没有任何重复,你可以做== max()
(然后输入它/乘以1/随便)。如果确实有重复项,并且想随机选择一个而不是将它们都设置为 1,那就有点复杂了。
请注意,人们给您的几乎所有答案都是== max()
的变体。因为您暗示的唯一可能不是您想要的地方是在评论中。您确实需要将问题编辑为明确的。
@abarnert:我不确定你的意思?给出的解决方案真的很令人满意,解决了我的问题。您是在谈论编辑以添加如果一行的三列重复,我只希望一个等于 1 吗?
【参考方案1】:
使用 numpy
和 argmax
m = np.zeros_like(df.values)
m[np.arange(len(df)), df.values.argmax(1)] = 1
df1 = pd.DataFrame(m, columns = df.columns).astype(int)
# Result
A B C
0 0 1 0
1 1 0 0
2 1 0 0
3 1 0 0
4 0 0 1
时间
df_test = df.concat([df] * 1000)
def chris_z(df):
m = np.zeros_like(df.values)
m[np.arange(len(df)), df.values.argmax(1)] = 1
return pd.DataFrame(m, columns = df.columns).astype(int)
def haleemur(df):
return df.apply(lambda x: x == x.max(), axis=1).astype(int)
def haleemur_2(df):
return pd.DataFrame((df.T == df.T.max()).T.astype(int), columns=df.columns)
def sacul(df):
return pd.DataFrame(np.where(df.T == df.T.max(), 1, 0),index=df.columns).T
结果
In [320]: %timeit chris_z(df_test)
358 µs ± 1.08 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [321]: %timeit haleemur(df_test)
1.14 s ± 45.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [329]: %timeit haleemur_2(df_test)
972 µs ± 11.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [333]: %timeit sacul(df_test)
1.01 ms ± 3.29 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
【讨论】:
您可能希望m
为布尔型,不是吗?
argmax
解决方案是唯一(至少可以说)对重复项正确且最快的解决方案。【参考方案2】:
另一个numpy
方法,使用np.where
:
import numpy as np
new_df = pd.DataFrame(np.where(df.T == df.T.max(), 1, 0),index=df.columns).T
A B C
0 0 1 0
1 1 0 0
2 1 0 0
3 1 0 0
4 0 0 1
【讨论】:
如果有重复,这会给出错误的结果。虽然这个问题对于在这种情况下应该发生的事情模棱两可,但从 OP 的 cmets 看来,1 1 1
行是不可接受的。
另外,np.where
只是增加了开销,将时间与@haleemur 的相同答案进行比较,没有np.where
实际上更快。
我不会删除,它仍然是一个有效的答案。这个问题很模棱两可
谢谢大家的cmets,确实是我的错。让我先编辑我的问题。对不起:)
在我的时间里查看haleemur_2
与您的解决方案,这就是我所说的开销。它对性能几乎没有影响【参考方案3】:
df.apply(lambda x: x == x.max(), axis=1).astype(int)
应该这样做。这通过检查该值是否是该列的最大值,然后转换为整数 (True -> 1, False -> 0)
除了apply
-ing a lambda row-wise,还可以转置数据帧并与max
比较,然后转回
(df.T == df.T.max()).T.astype(int)
最后,一个非常快速的基于 numpy 的解决方案:
pd.DataFrame((df.T.values == np.amax(df.values, 1)).T*1, columns = df.columns)
所有情况下的输出:
A B C
0 0 1 0
1 1 0 0
2 1 0 0
3 1 0 0
4 0 0 1
【讨论】:
这没有给我正确的输出,它使第 1 行和第 2 行全为零 哦,我看错了问题,您需要按行进行最大比较。相应地更新。 @chrisz,已修复。 您的第二种方法要快得多 它会和我的方法一样快,如果不是稍微快一点的话,但同样,如果两列共享相同的值,它将返回重复的1s
。以上是关于在 pandas 中将行中的最大值设置为 1,其余设置为 0的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Python/Pandas 中将变量设置为“今天”日期
pandas使用drop_duplicates函数基于subset参数指定的数据列子集删除重复行并设置keep参数保留重复行中的最后一个数据行