优雅的numpy数组移动和南填充?

2024-06-18 22:16:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个具体的性能问题。我正在处理气象预报时间序列,我把它编译成一个numpy 2d数组,这样

  • dim0=预测系列开始的时间
  • dim1=预测范围,例如0到120小时

现在,我希望dim0有每小时一次的间隔,但是有些来源只能每N小时生成一次预测。例如,假设N=3,dim1中的时间步长为M=1小时。然后我得到了

12:00  11.2  12.2  14.0  15.0  11.3  12.0
13:00  nan   nan   nan   nan   nan   nan
14:00  nan   nan   nan   nan   nan   nan
15:00  14.7  11.5  12.2  13.0  14.3  15.1

当然,在13:00和14:00也有信息,因为它可以从12:00预测运行中填写。所以我想以这样的方式结束:

^{pr2}$

假设dim0的顺序是1e4,而dim1的顺序是1e2,那么最快的方法是什么?现在我正在一行一行地做,但速度很慢:

nRows, nCols = dat.shape
if N >= M:
    assert(N % M == 0)  # must have whole numbers
    for i in range(1, nRows):
        k = np.array(np.where(np.isnan(self.dat[i, :])))
        k = k[k < nCols - N]  # do not overstep
        self.dat[i, k] = self.dat[i-1, k+N]

我肯定有更优雅的方法来做这个?如有任何提示,将不胜感激。在


Tags: 方法self顺序np时间序列nan性能
3条回答

这似乎起到了作用:

import numpy as np

def shift_time(dat):
    NX, NY = dat.shape
    for i in range(NY):
        x, y = np.where(np.isnan(dat))
        xr = x - 1
        yr = y + 1
        idx = (xr >= 0) & (yr < NY)
        dat[x[idx], y[idx]] = dat[xr[idx], yr[idx]]
    return

现在有一些测试数据:

^{pr2}$

以及使用(1e4,1e2)阵列进行测试:

In [1]: tmp = np.random.uniform(-10, 20, (1e4, 1e2))
In [2]: nan_idx = np.random.randint(30, 1e4 - 1,1e4)
In [3]: tmp[nan_idx] = nan
In [4]: time test3(tmp)
CPU times: user 1.53 s, sys: 0.06 s, total: 1.59 s
Wall time: 1.59 s

使用a=yourdata[:,1:]切片数据。在

def shift_time(dat):

    #Find number of required iterations
    check=np.where(np.isnan(dat[:,0])==False)[0]
    maxiters=np.max(np.diff(check))-1

    #No sense in iterations where it just updates nans
    cols=dat.shape[1]
    if cols<maxiters: maxiters=cols-1

    for iters in range(maxiters):
        #Find nans
        col_loc,row_loc=np.where(np.isnan(dat[:,:-1]))

        dat[(col_loc,row_loc)]=dat[(col_loc-1,row_loc+1)]


a=np.array([[11.2,12.2,14.0,15.0,11.3,12.0],
[np.nan,np.nan,np.nan,np.nan,np.nan,np.nan],
[np.nan,np.nan,np.nan,np.nan,np.nan,np.nan],
[14.7,11.5,12.2,13.0,14.3,15.]])

shift_time(a)
print a

[[ 11.2  12.2  14.   15.   11.3  12. ]
 [ 12.2  14.   15.   11.3  12.    nan]
 [ 14.   15.   11.3  12.    nan   nan]
 [ 14.7  11.5  12.2  13.   14.3  15. ]]

按原样使用您的数据,或者可以稍微更改一下以直接获取数据,但这似乎是一种明确的方式来显示这一点:

^{pr2}$

使用蒂亚戈的测试:

tmp = np.random.uniform(-10, 20, (1e4, 1e2))
nan_idx = np.random.randint(30, 1e4 - 1,1e4)
tmp[nan_idx] = np.nan

t=time.time()
shift_time(tmp,maxiter=1E5)
print time.time()-t

0.364198923111 (seconds)

如果你真的很聪明的话,你应该可以用一个np.where逃脱惩罚。在

看,布尔索引的力量!!!在

def shift_nans(arr) :
    while True:
        nan_mask = np.isnan(arr)
        write_mask = nan_mask[1:, :-1]
        read_mask = nan_mask[:-1, 1:]
        write_mask &= ~read_mask
        if not np.any(write_mask):
            return arr
        arr[1:, :-1][write_mask] = arr[:-1, 1:][write_mask]

我认为这个名字是不言而喻的。正确的切片是一件痛苦的事,但它似乎奏效了:

^{pr2}$

时间安排:

tmp1 = np.random.uniform(-10, 20, (1e4, 1e2))
nan_idx = np.random.randint(30, 1e4 - 1,1e4)
tmp1[nan_idx] = np.nan
tmp1 = tmp.copy()

import timeit

t1 = timeit.timeit(stmt='shift_nans(tmp)',
                   setup='from __main__ import tmp, shift_nans',
                   number=1)
t2 = timeit.timeit(stmt='shift_time(tmp1)', # Ophion's code
                   setup='from __main__ import tmp1, shift_time',
                   number=1)

In [242]: t1, t2
Out[242]: (0.12696346416487359, 0.3427293070417363)

相关问题 更多 >