python - Numpy 二维数组 : change all values to the right of NaNs

标签 python arrays performance numpy vectorization

情况

我有一个二维 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 向量化操作的方法会更加高效。有谁能帮我找到这样的方法吗?

最佳答案

一种方法 cumsumboolean-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/

相关文章:

python - 如何在 pandas DataFrame 中将值从 6200000 转换为 6.2M 或 1900 到 1.90K 的列?

c - C中的数组,char类型

python - 功能和标签尺寸崩溃 (tflearn)

python - 如何将 python 包上传到 Nexus sonatype 私有(private)仓库

php - 多表查询

jquery - 缓存 $(this) 是否会带来性能提升?

tomcat - 什么性能更好 : Jetty or Tomcat for production needs?

performance - Azure SQL 性能缓慢

python - 数据类与 typing.NamedTuple 主要用例

javascript - 遇到一些 javascript 问题,for 循环。将数字转换为字符串值