Anna Sviridova
Anna Sviridova

Reputation: 23

Weighted smoothing of a 1D array - Python

I am quite new to Python and I have an array of some parameter detections, some of the values were detected incorrectly and (like 4555555):

array = [1, 20, 55, 33, 4555555, 1]

And I want to somehow smooth it. Right now I'm doing that with a weighted mean:

def smoothify(array):
    for i in range(1, len(array) - 2):
        array[i] = 0.7 * array[i] + 0.15 * (array[i - 1] + array[i + 1])
    return array

But it works pretty bad, of course, we can take a weighted mean of more than 3 elements, but it results in copypasting... I tried to find some native functions for that, but I failed.

Could you please help me with that?

P.S. Sorry if it's a noob question :(

Thanks for your time, Best regards, Anna

Upvotes: 2

Views: 6826

Answers (4)

Divakar
Divakar

Reputation: 221574

For weighted smoothing purposes, you are basically looking to perform convolution. For our case, since we are dealing with 1D arrays, we can simply use NumPy's 1D convolution function : np.convolve for a vectorized solution. The only important thing to remember here is that the weights are to be reversed given the nature of convolution that uses a reversed version of the kernel that slides across the main input array. Thus, the solution would be -

weights = [0.7,0.15,0.15]
out = np.convolve(array,np.array(weights)[::-1],'same')

If you were looking to get weighted mean, you could get those with out/sum(weights). In our case, since the sum of the given weights is already 1, so the output would stay the same as out.

Let's plot the output alongwith the input for a graphical debugging -

# Input array and weights
array = [1, 20, 55, 33, 455, 200, 100, 20 ]
weights = [0.7,0.15,0.15]

out = np.convolve(array,np.array(weights)[::-1],'same')

x = np.arange(len(array))
f, axarr = plt.subplots(2, sharex=True, sharey=True)
axarr[0].plot(x,array)
axarr[0].set_title('Original and smoothened arrays')
axarr[1].plot(x,out)

Output -

enter image description here

Upvotes: 5

nlloyd
nlloyd

Reputation: 2016

Would suggest numpy.average to help you with this. the trick is getting the weights calculated - below I zip up the three lists - one the same as the original array, the next one step ahead, the next one step behind. Once we have the weights, we feed them into the np.average function

import numpy as np
array = [1, 20, 55, 33, 4555555, 1]
arrayCompare = zip(array, array[1:] + [0], [0] + array)

weights = [.7 * x + .15 * (y + z) for x, y, z in arrayCompare]

avg = np.average(array, weights=weights)

Upvotes: 1

22degrees
22degrees

Reputation: 645

Since you tagged this with numpy I wrote how I would do this with numpy:

import numpy as np

def smoothify(thisarray):
    """
    returns moving average of input using:
    out(n) = .7*in(n) + 0.15*( in(n-1) + in(n+1) )
    """

    # make sure we got a numpy array, else make it one
    if type(thisarray) == type([]): thisarray = np.array(thisarray)

    # do the moving average by adding three slices of the original array
    # returns a numpy array,
    # could be modified to return whatever type we put in...
    return 0.7 * thisarray[1:-1] + 0.15 * ( thisarray[2:] + thisarray[:-2] )

myarray = [1, 20, 55, 33, 4555555, 1]
smootharray = smoothify(myarray)

Instead of looping through the original array, with numpy you can get "slices" by indexing. The output array will be two items shorter than the input array. The central points (n) are thisarray[1:-1] : "From item index 1 until the last item (not inclusive)". The other slices are "From index 2 until the end" and "Everything except the last two"

Upvotes: 0

Jesper Freesbug
Jesper Freesbug

Reputation: 415

Maybe you want to have a look at numpy and in particular at numpy.average. Also, did you see this question Weighted moving average in python? Might be helpful, too.

Upvotes: 0

Related Questions