Any better way to slicing numpy array in parametric way in numpy?

Viewed 210

I'd like to do slice operation on numpy array in parametric way in function so I could get expected array element for my computation. I know how to slide the array by index, but I am more interested in slicing array element in parametric way, so no need to indicate the index. In my case, I have coefficient array c and power array p, I have also parameter num_order. Basically, num_order decide the index of slicing array. To do so, I have following attempt:

my attempt:

import numpy as np

c=[1,1/2, -1/6, 1/12]
p= [1,2,3,4]
x = np.array([1, 1, 2, 3, 5, 8, 13, 21])


def arr_pow(x, num_order):
    output= []
    for i in range(num_order):
        mul = c[i] * np.power(x, p[i])
        output.append(mul)
    return output

so, if num_order=2, then I also slice first two term of c and p doing c_new = c[:-2], p_new=p[:-2], c_new=[1,1/2], p_new=[1,2] and so on. I am curious is there any better way to do slicing element in two or more array based on param num_order. Can anyone point me out any elegant way to make this happen in parameterized function? Any thoughts?

update:

instead of doing c_new=c[:-1], p_new=[:-1] if num_order=3, and c_new=c[:-2], p_new=p[:-2] if num_order=2, and so on, is there more elegant way (parametric fashion) to do this? Any way of doing this efficiently in python function? Thanks!

2 Answers

I'm not sure if this is the output you want (if you could please update your question to include the expected output that would be helpful):

import numpy as np

c = np.array([1, 1 / 2, -1 / 6, 1 / 12])
p = np.array([1, 2, 3, 4])
x = np.array([1, 1, 2, 3, 5, 8, 13, 21])


def arr_pow_numpy(x, num_order):
    return c[:num_order, None] * np.power(x[None], p[:num_order, None])


def arr_pow(x, num_order):
    output = []
    for i in range(num_order):
        mul = c[i] * np.power(x, p[i])
        output.append(mul)
    return np.asarray(output)


for num_order in range(1, len(p)):
    assert np.array_equal(arr_pow(x, num_order), arr_pow_numpy(x, num_order)), f"{num_order}"

The idea here is to use NumPy broadcasting plus NumPy slicing to achieve the result you want without for loops and in a parametric way.

Use the following:

num_order = 2
np.array([c[i] * np.power(x, p[i]) for i in range(num_order)])

# Out:
# array([[  1. ,   1. ,   2. ,   3. ,   5. ,   8. ,  13. ,  21. ],
#        [  0.5,   0.5,   2. ,   4.5,  12.5,  32. ,  84.5, 220.5]])
Related