How to create a list comprehension for this cycle

I am trying to use list comprehension to replace this loop. My list

test_list = [3, 4, 6, 3, 8, 4, 7, 8, 12, 14, 1, 6, 7, 3, 7, 8, 3, 3, 7]

Function

import numpy as np
def ema(x, n):
    x = np.array(x)
    emaint = np.zeros(len(x))
    k = 2 / float(n + 1)

    emaint[0:n] = np.average(x[:n])

    for i in range(n, len(x)):
        emaint[i] = (x[i] * k) + (emaint[i - 1] * (1 - k))

    return emaint

The result for if I call ema (test_list, 5) will be

[4.8 4.8 4.8 4.8 4.8 4.53333333 5.35555556 6.23703704 8.15802469 10.10534979 7.0702332 6.7134888 6.80899253 5.53932835 6.0262189 6.68414594 5.45609729 4.63739819 5.42493213]

I tried this

import numpy as np
def ema_compr(x, n):
    x = np.array(x)
    emaint = np.zeros(len(x))
    k = 2 / float(n + 1)

    emaint[0:n] = np.average(x[:n])

    emaint[n:] = [(x[i] * k) + (emaint[i - 1] * (1 - k)) for i in range(n, len(x))]

    return emaint

however, the result is different if I call ema_compr (test_list, 5):

[4.8 4.8 4.8 4.8 4.8 4.53333333 2.33333333 2.66666667 4. 4.66666667 0.33333333 2. 2.33333333 1. 2.33333333 2.66666667 1. 1. 2.33333333]
  • I would like if you can get an understanding of the list.
  • Is the result of comprehending the list different because I am bound to access an un-created item?
+4
source share
4 answers

Since your loop needs to maintain its current state, it cannot be purely converted to list comprehension, although hacks exist.

So, if you want a โ€œsomething likeโ€ list comprehension, I recommend the following best: battery.

from itertools import accumulate

def ema(x, n):
    xx = n*[sum(x[:n])/n] + x[n:]
    p, q = 2 / (n+1), (n-1) / (n+1)
    return list(accumulate(xx, lambda a, b: q*a + p*b))

gives:

ema(test_list, 5)
# [4.8, 4.8, 4.8, 4.8, 4.8, 4.533333333333333, 5.355555555555555, 6.2370370370370365, 8.158024691358024, 10.105349794238682, 7.070233196159121, 6.713488797439414, 6.808992531626275, 5.539328354417517, 6.026218902945011, 6.684145935296673, 5.456097290197782, 4.637398193465188, 5.424932128976792]
+1

ewma Pandas:

import pandas as pd
def ema(x, n):
    pd_x = pd.Series(x)
    pd_x[:n] = pd_x[:n].mean()
    return pd.ewma(pd_x, span=n, adjust=False).as_matrix()
+1

:

import numpy as np
test_list = [3, 4, 6, 3, 8, 4, 7, 8, 12, 14, 1, 6, 7, 3, 7, 8, 3, 3, 7]

def ema(x, n):
    x = np.array(x)
    emaint = np.zeros(len(x))
    k = 2 / float(n + 1)

    emaint[0:n] = np.average(x[:n])

    for i in range(n, len(x)):
        [emaint.__setitem__(i, ((x[i] * k) + (emaint[i - 1] * (1 - k)))) for i in range(n, len(x))]

    return emaint


print(ema(test_list, 5))

:

[  4.8          4.8          4.8          4.8          4.8          4.53333333
   5.35555556   6.23703704   8.15802469  10.10534979   7.0702332
   6.7134888    6.80899253   5.53932835   6.0262189    6.68414594
   5.45609729   4.63739819   5.42493213]
0

In your understanding of the list, you are trying to use the index emaint[i-1]without saving the array. In the understanding of the list, it will be saved after iterating through the entire array

You can write for a loop like this to set the element and go to the next iteration (this is almost like the first solution)

for i in range(0,len(x)):
    if i<=n:
        emaint[i]=np.average(x[:n])
    else:
        emaint[i]=((x[i] * k) + (emaint[i - 1] * (1 - k)))

Or, as Sebastian suggested, you can use Pandas

0
source

Source: https://habr.com/ru/post/1691212/


All Articles