从1d数组构建有效的2d numpy数组,并带有条件函数

时间:2019-10-17 19:14:40

标签: python arrays numpy

我正在从应用于1d numpy数组(包含条件)的函数创建2d numpy数组,并且想知道一种更有效的方法。目前,这是我代码中最慢的部分。 x是1d numpy数组,输出是2d numpy数组。有一个开关可以根据x小于还是大于0构造一个不同的数组元素。将来,开关的数量可以是任意的。

def basis2(x) :

  final = []
  for i in x :
    if i > 0 :
        xr = 2.0*(i-0.5)
        final.append(np.array([0.0, 0.0, 0.0, 0.5*xr*(xr-1.0),-1.0*(xr+1)*(xr-1), 0.5*xr*(xr+1.0)]))
    else :
        xl = 2.0*(i+0.5)
        final.append(np.array([0.5*xl*(xl-1.0),-1.0*(xl+1)*(xl-1),0.5*xl*(xl+1.0),0.0,0.0,0.0]))


return np.array(final)

理想情况下,我可以消除for循环-但是到目前为止,我还没有设法正确地做到这一点,例如使用“ where”。谢谢您的帮助。

2 个答案:

答案 0 :(得分:1)

具有您的功能

In [247]: basis2(np.array([1,.5,0,-.5,-1]))                                     
Out[247]: 
[array([ 0.,  0.,  0.,  0., -0.,  1.]),
 array([ 0.,  0.,  0., -0.,  1.,  0.]),
 array([ 0., -0.,  1.,  0.,  0.,  0.]),
 array([-0.,  1.,  0.,  0.,  0.,  0.]),
 array([ 1.,  0., -0.,  0.,  0.,  0.])]
In [248]: %hist 245                                                             
basis2_1(np.array([1,.5,0,-.5,-1]))

有一些肤浅的变化:

def basis2_1(x) :
    xr = 2.0*(x[x>0]-0.5)
    res1 = np.array([0.0*xr, 0.0*xr, 0.0*xr, 0.5*xr*(xr-1.0),-1.0*(xr+1)*(xr-1), 0.5*xr*(xr+1.0)])
    xl = 2.0*(x[x<=0]+0.5)
    res2 = np.array([0.5*xl*(xl-1.0),-1.0*(xl+1)*(xl-1),0.5*xl*(xl+1.0),0.0*xl,0.0*xl,0.0*xl])
    return res1, res2

In [250]: basis2_1(np.array([1,.5,0,-.5,-1]))                                   
Out[250]: 
(array([[ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.],
        [ 0., -0.],
        [-0.,  1.],
        [ 1.,  0.]]), 
 array([[ 0., -0.,  1.],
        [-0.,  1.,  0.],
        [ 1.,  0., -0.],
        [ 0.,  0., -0.],
        [ 0.,  0., -0.],
        [ 0.,  0., -0.]]))

加入两个子数组:

In [251]: np.hstack(_)                                                          
Out[251]: 
array([[ 0.,  0.,  0., -0.,  1.],
       [ 0.,  0., -0.,  1.,  0.],
       [ 0.,  0.,  1.,  0., -0.],
       [ 0., -0.,  0.,  0., -0.],
       [-0.,  1.,  0.,  0., -0.],
       [ 1.,  0.,  0.,  0., -0.]])

显然,这需要改进,但这足以让您入门。

例如,您可以制作一个result = np.zeros((5,x.shape[0]))数组,只需插入相应的非零元素(保存所有这些0.0*xr项)。

查看Out[251]中的那些块:

In [257]: x = np.array([1,.5,0,-.5,-1])                                         
In [258]: Out[251][3:,np.nonzero(x>0)[0]]                                       
Out[258]: 
array([[ 0., -0.],
       [-0.,  1.],
       [ 1.,  0.]])
In [259]: Out[251][:3,np.nonzero(x<=0)[0]]                                      
Out[259]: 
array([[ 0., -0.,  1.],
       [-0.,  1.,  0.],
       [ 1.,  0., -0.]])

答案 1 :(得分:1)

这是利用对称性的矢量化方法:

col = np.s_[...,None]

def basis2_v(x):
    h,w = np.arange(x.size)[col],np.arange(3,dtype=np.int8)
    # if the terms for xr are the same as the formulas for xl applied to -xr
    # we can therefore unify the code and apply it to |x|:
    # there are three factors in total each term consists of two of them
    aux = (np.abs(x[col])-w/2)*(2/(1^-(w&1)))
    # the easiest is multiplying all three and then dividing one out again
    aux = -aux.prod(-1)[col]/aux
    # fix degenerate cases
    aux[np.isnan(aux)] = 1
    # finally, we need to embed the terms in a zero matrix
    out = np.zeros((x.size,6),x.dtype)
    # the xor trick maps 2,1,0 to -3,-2,-1 if x>0
    out[h,(-(x[col]>0).view(np.int8))^w[::-1]] = aux
    return out

# make small test
x = np.random.randn(10)
# this should pass
assert np.allclose(basis2(x),basis2_v(x))