在Python Pandas数据集中每行仅保留最低值

时间:2014-11-11 14:31:16

标签: python pandas

在Pandas数据集中,我只希望保持每行的最低值。应删除所有其他值。 我需要完整的原始数据集。只需删除不是最小值的所有值(替换为NaN)。

最好的方法是什么 - 速度/性能明智。

如果每列操作更容易,我也可以转置数据集。

由于 罗伯特

4 个答案:

答案 0 :(得分:4)

由于您正在考虑的操作不依赖于列或索引,因此使用NumPy而不是Pandas执行此操作可能更容易(也更快)。

您可以使用

找到每行最小值的位置(即列索引)
idx = np.argmin(arr, axis=1)

然后,您可以创建一个填充NaN的新数组并复制最小值 到新阵列。


import numpy as np
import pandas as pd

def nan_all_but_min(df):
    arr = df.values
    idx = np.argmin(arr, axis=1)
    newarr = np.full_like(arr, np.nan, dtype='float')
    newarr[np.arange(arr.shape[0]), idx] = arr[np.arange(arr.shape[0]), idx]
    df = pd.DataFrame(newarr, columns=df.columns, index=df.index)
    return df

df = pd.DataFrame(np.random.random((4,3)))
print(df)
#           0         1         2
# 0  0.542924  0.499702  0.058555
# 1  0.682663  0.162582  0.885756
# 2  0.389789  0.648591  0.513351
# 3  0.629413  0.843302  0.862828

df = nan_all_but_min(df)
print(df)

产量

          0         1         2
0       NaN       NaN  0.058555
1       NaN  0.162582       NaN
2  0.389789       NaN       NaN
3  0.629413       NaN       NaN

以下是比较nan_all_but_minusing_where

的基准
def using_where(df):
    return df.where(df.values == df.min(axis=1)[:,None])

In [73]: df = pd.DataFrame(np.random.random(100*100).reshape(100,100))

In [74]: %timeit using_where(df)
1000 loops, best of 3: 701 µs per loop

In [75]: %timeit nan_all_but_min(df)
10000 loops, best of 3: 105 µs per loop

请注意,如果一行包含多次相同的最小值,则using_wherenan_all_but_min的行为会有所不同。 using_where将保留所有分钟,nan_all_but_min将只保留一分钟。例如:

In [76]: using_where(pd.DataFrame([(0,0,1), (1,2,1)]))
Out[76]: 
   0   1   2
0  0   0 NaN
1  1 NaN   1

In [77]: nan_all_but_min(pd.DataFrame([(0,0,1), (1,2,1)]))
Out[77]: 
   0   1   2
0  0 NaN NaN
1  1 NaN NaN

答案 1 :(得分:1)

关闭@ unutbu的优秀答案,以下小改动应该适应您修改后的问题。

The where method

In [26]: df2 = df.copy()

In [27]: df2
Out[27]: 
   0   1   2
0  0   1   2
1  3   4   5
2  6   7   8
3  9  10  11

In [28]: df2.where(df2.values == df2.min(axis=1)[:,None])
Out[28]: 
   0   1   2
0  0 NaN NaN
1  3 NaN NaN
2  6 NaN NaN
3  9 NaN NaN

强制性速度测试。

In [29]: df3 = pd.DataFrame(np.random.random(100*100).reshape(100,100))

In [30]: %timeit df3.where(df3.values == df3.min(axis=1)[:,None])
1000 loops, best of 3: 723 µs per loop

答案 2 :(得分:0)

如果数据框已经包含NaN值,则必须使用numpy的nanmin,如下所示:

df2.where(df2.values==np.nanmin(df2,axis=0))

答案 3 :(得分:0)

我刚刚找到并尝试了unutbu的答案。 我尝试了.where方法,但很快就会弃用。

FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.

但是,我却改用了这种吸盘。但是,它是一个lambda函数,并且很可能会更慢...

df = pd.DataFrame(np.random.random((4,3)))
print(df)
#           0         1         2
# 0  0.542924  0.499702  0.058555
# 1  0.682663  0.162582  0.885756
# 2  0.389789  0.648591  0.513351
# 3  0.629413  0.843302  0.862828

    mask = df.apply(lambda d:(d == df.min(axis=1)))
    print (df[mask])

应该产生:

        0         1         2
0       NaN       NaN  0.058555
1       NaN  0.162582       NaN
2  0.389789       NaN       NaN
3  0.629413       NaN       NaN