计算给定窗口的滚动平均值和滚动最大值

时间:2015-08-02 15:02:20

标签: python generator

计算给定窗口w1的滚动平均值和滚动最大值。 但使用是: 您应该编写一个接受迭代器的类,并充当生成元组的生成器,如上所示。

例如,给定包含以下值的流。 W = 3。

[1, 2, 3, 4, 5, 6]

预计会出现以下元组,其中“无”表示某个值不可用,并且在某些语言中为“NaN”:

(None, None) -- When we have input 1  --- As we dont have w num, ignore - None
(None, None) -- Now we have input 1,2 
(2, 3)       -- Now we have input 1,2,3
(3, 4)       -- Discard 1. Window [2,3,4]
(4, 5)       -- Discard 3. Window [3,4,5]
(5, 6)       -- Discard 4. Window [4,5,6]

在这个元组中,第一个数字是平均w(= 3)个数。第二 num是w(= 3)个数的最大值。

我仍然在python中学习iterator和generator / yield。

Que:那么生成器接受整个序列(或迭代器/列表)?如果 seq是巨大的?

我编写的简单解决方案可能不是有效的算法,但无论如何 我想首先知道这是否适用于发电机:

 7 from collections import deque
 8 class Solution:
 9     def sliding_window_avg_max(self, nums, w=3):
 10         d = deque(maxlen = w)   
 11         total = 0
 12         for n in nums:
 13             if len(d) >= w:
 14                 total = total - d.pop() + n
 15             else:
 16                 total = total + n
 17             d.append(n)
 18             if len(d) >= w:
 19                 yield (total/float(w), max(d))
 20             else:
 21                 yield(None, None)
 22 
 23 s = Solution()
 24 a = [1, 2, 3, 4, 5, 6]
 25 for t in s.sliding_window_avg_max(a):
 26     print t 

编辑: 这不是作业问题。这是我想要的面试问题 也了解其他人的想法。我真的想知道生成器如何帮助 - 不是它需要列表(nums)在内存中吗? 如果我们应该如何使用迭代器呢?

3 个答案:

答案 0 :(得分:0)

我会把你的方法分成:

  1. 产生W数元组的生成器。它可以保存W + 1值,因此它知道添加新数字时要丢弃的内容。
  2. 计算当前元组的均值和最大值的计算器。
  3. 这有两个原因。首先,在这种情况下,编码时间是有限的,如果您只是检查正确的交付,将更容易调试生成器。其次,它是一种更灵活的方法 - 如果采访者要求添加最小和标准偏差,那么它只是计算模块中的几行。

答案 1 :(得分:0)

您应该能够将其转换为类,或将其作为方法添加到类中。

def sliding_window_avg_max(nums, w=3):
    if w < 1:
        raise ValueError('Window size must be > 0')
    for i in range(1, len(nums)+1):
        if i < w:
            yield None, None
        else:
            yield sum(nums[i-w:i])/float(w), max(nums[i-w:i])


>>> for t in sliding_window_avg_max([1, 2, 3, 4, 5, 6]):
...     print t
(None, None)
(None, None)
(2.0, 3)
(3.0, 4)
(4.0, 5)
(5.0, 6)

答案 2 :(得分:0)

请注意,规范说明(强调我的):

  

你应该写一个接受迭代器的类,作为一个   生成器,它产生如上所示的元组。

我认为你误解了这个问题;我怀疑你被要求实施the iterator protocol。一种可能的解决方案看起来像这样:

from collections import deque


class Solution(object):
    """Apply a moving window to an iterator, calculate max and average.

    Arguments:
      iter_ (iterator): The iterator to process.
      w (int): The length of the moving window to apply.

    Attributes:
      window (deque): The moving window.

    Example:

        >>> list(Solution(range(1, 7), 3))
        [(None, None), (None, None), (2, 3), (3, 4), (4, 5), (5, 6)]

    """

    def __init__(self, iter_, w):
        self.iter = iter(iter_)
        self.w = w
        self.window = deque(maxlen=w)

    def __iter__(self):
        return self

    def next(self):
        """Calculate the next value in the series.

        Notes:
          If the window isn't full, return (None, None). 

        """
        self.window.append(next(self.iter))
        if len(self.window) == self.w:
            return self._avg(), self._max()
        return None, None

    def _max(self):
        """Calculate the maximum of the current window."""
        return max(self.window)

    def _avg(self):
        """Calculate the average of the current window."""
        return int(sum(self.window) / float(len(self.window)))

请注意,您也可以将__iter__作为生成器实施,即删除next并执行:

    def __iter__(self):
        for val in self.iter:
            self.window.append(val)
            if len(self.window) == self.w:
                yield self._avg(), self._max()
            else:
                yield None, None

无论哪种方式,您都要确保从__iter__返回的是迭代器!

你的解决方案的形式应该让你停下来;根据{{​​3}},如果您的班级实施了__init__和另一种方法(在这种情况下甚至不是__init__!),则它不应该是一个班级。