在Pandas数据集中,我只希望保持每行的最低值。应删除所有其他值。 我需要完整的原始数据集。只需删除不是最小值的所有值(替换为NaN)。
最好的方法是什么 - 速度/性能明智。
如果每列操作更容易,我也可以转置数据集。
由于 罗伯特
答案 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_min
与using_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_where
和nan_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的优秀答案,以下小改动应该适应您修改后的问题。
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