Pandas:每行最大值的矢量化操作

时间:2016-03-06 21:27:46

标签: python pandas max dataframe vectorization

我有以下pandas数据帧df

index        A    B    C
    1        1    2    3
    2        9    5    4
    3        7    12   8
    ...      ...  ...  ...

我希望每行的最大值保持不变,所有其他值都变为-1。因此输出如下:

index        A    B    C
    1       -1   -1    3
    2        9   -1   -1
    3       -1    12  -1
    ...      ...  ...  ...

通过使用df.max(axis = 1),我获得了每行最大值的panda Series。但是,我不确定如何最佳地使用这些最大值来创建我需要的结果。我正在寻找一个矢量化,快速的实现。

3 个答案:

答案 0 :(得分:4)

考虑使用where

>>> df.where(df.eq(df.max(1), 0), -1)
       A   B  C
index          
1     -1  -1  3
2      9  -1 -1
3     -1  12 -1

这里df.eq(df.max(1), 0)是一个布尔数据框,用于标记行的最大值;真值(最大值)保持不变,而假值变为-1。如果您愿意,也可以使用Series或其他DataFrame而不是标量。

该操作也可以在现场完成(通过传递inplace=True)。

答案 1 :(得分:2)

您可以按行eqmax进行比较,然后应用反向mask来创建布尔mask

print df
       A   B  C
index          
1      1   2  3
2      9   5  4
3      7  12  8

print df.max(axis=1)
index
1     3
2     9
3    12
dtype: int64

mask = df.eq(df.max(axis=1), axis=0)
print mask
           A      B      C
index                     
1      False  False   True
2       True  False  False
3      False   True  False

df[~mask] = -1
print df
       A   B  C
index          
1     -1  -1  3
2      9  -1 -1
3     -1  12 -1

所有在一起:

df[~df.eq(df.max(axis=1), axis=0)] = -1
print df
       A   B  C
index          
1     -1  -1  3
2      9  -1 -1
3     -1  12 -1

答案 2 :(得分:1)

为每个值创建一个大小为df的新数据帧,其中包含-1。然后使用enumerate来获取给定行中的第一个最大值,使用标量的整数获取/设置(iat)。

df2 = pd.DataFrame(-np.ones(df.shape), columns=df.columns, index=df.index)

for row, col in enumerate(np.argmax(df.values, axis=1)):
    df2.iat[row, col] = df.iat[row, col]

>>> df2
   0   1  2
0 -1  -1  3
1  9  -1 -1
2 -1  12 -1

<强>计时

df = pd.DataFrame(np.random.randn(10000, 10000))

%%timeit
df2 = pd.DataFrame(-np.ones(df.shape))
for row, col in enumerate(np.argmax(df.values, axis=1)):
    df2.iat[row, col] = df.iat[row, col]
1 loops, best of 3: 1.19 s per loop

%timeit df.where(df.eq(df.max(1), 0), -1)
1 loops, best of 3: 6.27 s per loop

# Using inplace=True
%timeit df.where(df.eq(df.max(1), 0), -1, inplace=True)
1 loops, best of 3: 5.58 s per loop

%timeit df[~df.eq(df.max(axis=1), axis=0)] = -1
1 loops, best of 3: 5.65 s per loop