情况
我有一个二维 Numpy 数组,其中包含一些 nan
值。简化示例:
arr = np.array([[3, 5, np.nan, 2, 4],
[9, 1, 3, 5, 1],
[8, np.nan, 3, np.nan, 7]])
在控制台输出中看起来像这样:
array([[ 3., 5., nan, 2., 4.],
[ 9., 1., 3., 5., 1.],
[ 8., nan, 3., nan, 7.]])
问题
我正在寻找一种将现有 nan
值右侧的所有值也设置为 nan
的好方法。换句话说,我需要将示例数组转换为:
array([[ 3., 5., nan, nan, nan],
[ 9., 1., 3., 5., 1.],
[ 8., nan, nan, nan, nan]])
我知道如何使用循环来完成此操作,但我认为仅使用 Numpy 向量化操作的方法会更加高效。有谁能帮我找到这样的方法吗?
最佳答案
一种方法 cumsum
和 boolean-indexing
-
arr[np.isnan(arr).cumsum(1)>0] = np.nan
为了性能,使用 np.maximum.accumulate
可能会更好-
arr[np.maximum.accumulate(np.isnan(arr),axis=1)] = np.nan
另一种有点扭曲使用 broadcasting
的方法-
n = arr.shape[1]
mask = np.isnan(arr)
idx = mask.argmax(1)
idx[~mask.any(1)] = n
arr[idx[:,None] <= np.arange(n)] = np.nan
sample 运行-
In [96]: arr
Out[96]:
array([[ 3., 5., nan, 2., 4.],
[ 9., 1., 3., 5., 1.],
[ 8., nan, 3., nan, 7.]])
In [97]: arr[np.maximum.accumulate(np.isnan(arr),axis=1)] = np.nan
In [98]: arr
Out[98]:
array([[ 3., 5., nan, nan, nan],
[ 9., 1., 3., 5., 1.],
[ 8., nan, nan, nan, nan]])
基准测试
方法-
def func1(arr):
arr[np.isnan(arr).cumsum(1)>0] = np.nan
def func2(arr):
arr[np.maximum.accumulate(np.isnan(arr),axis=1)] = np.nan
def func3(arr): # @ MSeifert's suggestion
mask = np.isnan(arr);
accmask = np.cumsum(mask, out=mask, axis=1);
arr[accmask] = np.nan
def func4(arr):
mask = np.isnan(arr);
np.maximum.accumulate(mask,axis=1, out = mask)
arr[mask] = np.nan
def func5(arr):
n = arr.shape[1]
mask = np.isnan(arr)
idx = mask.argmax(1)
idx[~mask.any(1)] = n
arr[idx[:,None] <= np.arange(n)] = np.nan
时间 -
In [201]: # Setup inputs
...: arr = np.random.rand(5000,5000)
...: arr.ravel()[np.random.choice(range(arr.size), 10000, replace=0)] = np.nan
...: arr1 = arr.copy()
...: arr2 = arr.copy()
...: arr3 = arr.copy()
...: arr4 = arr.copy()
...: arr5 = arr.copy()
...:
In [202]: %timeit func1(arr1)
...: %timeit func2(arr2)
...: %timeit func3(arr3)
...: %timeit func4(arr4)
...: %timeit func5(arr5)
...:
10 loops, best of 3: 149 ms per loop
10 loops, best of 3: 90.5 ms per loop
10 loops, best of 3: 88.8 ms per loop
10 loops, best of 3: 88.5 ms per loop
10 loops, best of 3: 75.3 ms per loop
基于广播的似乎做得很好!
关于python - Numpy 二维数组 : change all values to the right of NaNs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42098237/