Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Numpy 2D数组:将所有值更改为NaN的右侧 处境_Python_Arrays_Performance_Numpy_Vectorization_Numba - Fatal编程技术网

Python Numpy 2D数组:将所有值更改为NaN的右侧 处境

Python Numpy 2D数组:将所有值更改为NaN的右侧 处境,python,arrays,performance,numpy,vectorization,numba,Python,Arrays,Performance,Numpy,Vectorization,Numba,我有一个2D 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.], [

我有一个2D 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矢量化操作的方法将更加高效。有人能帮我找到这样的方法吗?

一种方法,带和-

为了提高性能,最好使用-

另一种方法是使用有点扭曲的-

基准测试

接近-

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

基于广播的一个似乎做得很好

使用布尔索引和某种累加器(我在这里使用了
np.cumsum
):


正如在注释中已经指出的,使用
out
-参数可能会加快速度并避免创建另一个临时数组:

def put_nans_right_of_nans(arr):
    mask = np.isnan(arr)
    mask = np.cumsum(mask, out=mask, axis=1)
    arr[mask] = np.nan

鉴于我是一个相当狂热的人,我想展示一个易于实现的解决方案,它在性能和内存使用方面优于所有其他方法:

import numba as nb
import math

@nb.njit
def nan_items_rightofnans(arr):
    x, y = arr.shape[0], arr.shape[1]

    for row_no in range(x):
        nanfound = False
        for col_no in range(y):
            if nanfound:
                arr[row_no, col_no] = np.nan
            elif math.isnan(arr[row_no, col_no]):
                nanfound = True

    return arr

如果性能是一个问题,
mask=np.isnan(arr);accmask=np.cumsum(mask,out=mask,axis=1);arr[accmask]=np.nan
会更快(而且可能更节省内存):-@mseivert与Accumculate相当,建议不错!考虑添加到你的帖子!虽然里面有太多的代码;)@MSeifert与其他计算机一起添加了计时。在我的计算机上,您的
func5
func2
func3
func4
慢。但是考虑到这是一个非常接近的运行,我添加了一个比所有解决方案都快1.5倍的numba解决方案:)@MSeifert当然,基于JIT的解决方案在这里会很好。
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
>>> mask = np.cumsum(np.isnan(arr), axis=1).astype(bool)

>>> arr[mask] = np.nan

>>> arr
array([[  3.,   5.,  nan,  nan,  nan],
       [  9.,   1.,   3.,   5.,   1.],
       [  8.,  nan,  nan,  nan,  nan]])
def put_nans_right_of_nans(arr):
    mask = np.isnan(arr)
    mask = np.cumsum(mask, out=mask, axis=1)
    arr[mask] = np.nan
import numba as nb
import math

@nb.njit
def nan_items_rightofnans(arr):
    x, y = arr.shape[0], arr.shape[1]

    for row_no in range(x):
        nanfound = False
        for col_no in range(y):
            if nanfound:
                arr[row_no, col_no] = np.nan
            elif math.isnan(arr[row_no, col_no]):
                nanfound = True

    return arr