Vectorize numpy array expansion

后端 未结 4 1973
被撕碎了的回忆
被撕碎了的回忆 2021-01-15 02:38

I\'m trying to find a way to vectorize an operation where I take 1 numpy array and expand each element into 4 new points. I\'m currently doing it with Python loop. First l

相关标签:
4条回答
  • 2021-01-15 02:50

    For the first example, you can use np.kron

    >>> a = np.array([0, 1, 1, 0])
    >>> np.kron(input_array, a)
    array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])
    

    For the second example, you can use np.repeat and np.tile

    >>> b = np.array([-0.2, -0.2, 0.2, 0.2])
    >>> np.repeat(input_array, b.size) + np.tile(b, input_array.size)
    array([ 0.8,  0.8,  1.2,  1.2,  1.8,  1.8,  2.2,  2.2,  2.8,  2.8,  3.2,
            3.2,  3.8,  3.8,  4.2,  4.2])
    
    0 讨论(0)
  • 2021-01-15 02:51

    It seems you want to want to do elementwise operations between input_array and the array that contains the extending elements. For these, you can use broadcasting.

    For the first example, it seems you are performing elementwise multiplication -

    In [424]: input_array = np.array([1, 2, 3, 4])
         ...: extend_array = np.array([0, 1, 1, 0])
         ...: 
    
    In [425]: (input_array[:,None] * extend_array).ravel()
    Out[425]: array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])
    

    For the second example, it seems you are performing elementwise addition -

    In [422]: input_array = np.array([1, 2, 3, 4])
         ...: extend_array = np.array([-0.2, -0.2, 0.2, 0.2])
         ...: 
    
    In [423]: (input_array[:,None] + extend_array).ravel()
    Out[423]: 
    array([ 0.8,  0.8,  1.2,  1.2,  1.8,  1.8,  2.2,  2.2,  2.8,  2.8,  3.2,
            3.2,  3.8,  3.8,  4.2,  4.2])
    
    0 讨论(0)
  • 2021-01-15 02:56

    For the first example, you can do an outer product of the input and the template and reshape the result:

    input_array = np.array([1, 2, 3, 4])
    template = np.array([0, 1, 1, 0])
    
    np.multiply.outer(input_array, template)
    # array([[0, 1, 1, 0],
    #        [0, 2, 2, 0],
    #        [0, 3, 3, 0],
    #        [0, 4, 4, 0]])
    
    result = np.multiply.outer(input_array, template).ravel()
    # array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])
    

    Similarly for your second example you can use np.add.outer

    np.add.outer(input_array, [-0.2, -0.2, 0.2, 0.2]).ravel()
    # array([ 0.8,  0.8,  1.2,  1.2,  1.8,  1.8,  2.2,  2.2,  2.8,  2.8,  3.2,
            3.2,  3.8,  3.8,  4.2,  4.2])
    

    See:

    • http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.outer.html
    0 讨论(0)
  • 2021-01-15 03:04

    I'm not certain of the logic of your algorithm, but I think if you want each point to extend around it, and then queue them all together, your best approach would be to increase the dimension, and then take the flattened version; for your first example:

    >>> x = np.array([1,2,3,4])
    >>> x
    array([1, 2, 3, 4])
    >>> y = np.empty((len(x), 4))
    >>> y[:, [0, 3]] = 0
    >>> y[:, 1:3] = x[:, None]
    >>> y
    array([[ 0.,  1.,  1.,  0.],
           [ 0.,  2.,  2.,  0.],
           [ 0.,  3.,  3.,  0.],
           [ 0.,  4.,  4.,  0.]])
    >>> y.reshape((4*len(x),))  # Flatten it back
    array([ 0.,  1.,  1.,  0.,  0.,  2.,  2.,  0.,  0.,  3.,  3.,  0.,  0.,
        4.,  4.,  0.])
    

    How you then go about making that generic depends on your algorithm, which I'm not entirely sure to follow... But this should give you some pointers to get started.

    Edit: As others have stated, you can actually do all that with outer products in a much more concise way, which will probably match your algorithm more closely, e.g., shamelessely making YXD answer a one-liner:

    >>> (x[:, None] * np.array([0,1,1,0])[None, :]).flatten()
    array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])
    

    However, the principle is still to go in a higher dimension (2) before expanding it in you original dimension (1)

    0 讨论(0)
提交回复
热议问题