-1

我需要找到一维列表中项目的平均值:例如:L = [123,678,234,256,789,-----] 首先我需要从列表中的最后一项开始获取运行平均值。从而提供结果列表如下: reslist= [416,489.25,426.33,522.5,789---]。任何人都可以在 python 中建议一个简单的代码来执行此操作,这将很有帮助..

4

2 回答 2

2

So for each index i, you want the average of the values L[i] through L[-1], right?

First, let's write a simple average function:

def average(values):
    return sum(values) / len(values)

Now, we can translate the description into code:

running_averages = [average(L[i:]) for i in range(len(L))]

You also seem to want to round things in some unspecified way (489.25 is rounded to 489, but 522.5 is left as 522.5); if you can describe the rule, I can show how to implement it, but I can't guess the rule from your examples.


Of course this isn't very efficient if L is long, because it will do len(L)**2 / 2 additions. Is there a way we could do it in just len(L)? Sure, it's just a bit more complicated. For example:

partial_sums = itertools.accumulate(reversed(L))
averages = [value/(i+1) for i, value in enumerate(partial_sums)]
averages.reverse()

The first and last steps are easy: just reverse the list at the start and then at the end. But what about the rest?

First, accumulate just takes any iterable, and returns an iterator with the accumulated sums. So it gives you i[0], then i[0] + i[1], then i[0] + i[1] + i[2], etc. But, because it remembers the last partial sum, each step only takes one addition. In other words, it's giving you 0 + i[0], then result[0] + i[1], then result[1] + i[2]. If you want to see how it works (or if you're using an older version of Python that doesn't have accumulate), the linked documentation shows how you can build it yourself.

And then, we just divide each partial sum by the index (+ 1, because Python indices are 0-based) to get the running average. The list comprehension should be obvious; if you don't know the enumerate function, that's the only clever bit.


That's not the only way to do it. You could also use functools.reduce, or an explicit loop, or build a tail-recursive function by accumulator passing, or a naive recursive function, or… It might be a good exercise to try to write as many of them as you can. There may be only one obvious way to do it, but sometimes it's not obvious which one is the obvious way until you try a few. :)


Another way to do this is with numpy. rogaos deleted his too-simple answer, but it's a start.

First, the easy part: reverse the list, and cram it into a numpy array:

a = np.array(reversed(L))

Now, the trick is to write a vectorized running sum. Well, numpy comes with convolve, and convolving with a run of N ones gives you an N+M-1-windowed sum. So, what happens if the window is as wide as the whole array? We get a windowed sum that's almost twice as long as we need, where the first len(L) values are the running sums. So:

running_sums = np.convolve(a, np.ones(len(L)))[:len(L)]

Then we just divide by the indices, just as in the itertools version:

running_means = running_sums / np.arange(1, len(L)+1)

And now we just reverse it and turn it back into a list:

reslist = list(reversed(running_means))

Of course in real life, you'd probably want L and reslist to be numpy arrays too, which makes it even simpler.

Anyway, the upside of using numpy is that some of the operations are simpler (notice how I just divided one array by another, instead of writing a list comprehension), and usually about 10x faster (all of the looping and arithmetic takes place in C, or occasionally C++ or Fortran, instead of in Python). The downside is that you have to figure out how to turn each loop into a sensible mathematical operation. (If you don't know what convolve does, you never would have thought to use it here.)

于 2013-08-13T04:11:15.197 回答
0

这是一个使用递归的解决方案:

def runningMean(seq, n=0, total=0):
    if not seq:
        return []
    total = total+seq[-1]
    return runningMean(seq[:-1], n=n+1, total=total) + [total/float(n+1)]

演示

print(runningMean([123,678,234,256,789]))

输出:

[416.0, 489.25, 426.3333333333333, 522.5, 789.0]
于 2013-08-13T04:18:13.873 回答