【问题标题】:Way of easily finding the average of every nth element over a window of size k in a pandas.Series? (not the rolling mean)在pandas.Series中大小为k的窗口上轻松找到每个n个元素的平均值的方法? (不是滚动平均值)
【发布时间】:2016-05-23 08:29:24
【问题描述】:

这里的动机是采用时间序列并获得整个子时段(天、周)的平均活动。

可以重塑一个数组并在 y 轴上取平均值来实现这一点,类似于这个答案(但使用 axis=2):

Averaging over every n elements of a numpy array

但我正在寻找可以处理长度为 N%k != 0 的数组的东西,并且不能通过用 1 或 0(例如 numpy.resize)重塑和填充来解决问题,即取现有的平均值仅限数据。

例如,从长度为 N=10 且不能被 k=3 整除的序列 [2,2,3,2,2,3,2,2,3,6] 开始。我想要的是对尺寸不匹配的重塑数组的列取平均值:

In: [[2,2,3], [2,2,3], [2,2,3], [6]], k =3

Out: [3,2,3]

代替:

In: [[2,2,3], [2,2,3], [2,2,3], [6,0,0]], k =3

Out: [3,1.5,2.25]

谢谢。

【问题讨论】:

  • 你能否提供一个完整的例子来说明你正在尝试做什么以及你已经做了什么?您当前的示例没有意义。

标签: python arrays numpy pandas


【解决方案1】:

您可以使用掩码数组填充在求均值时忽略的特殊值,而不是求和。

k = 3

# how long the array needs to be to be divisible by 3
padded_len = (len(in_arr) + (k - 1)) // k * k

# create a np.ma.MaskedArray with padded entries masked
padded = np.ma.empty(padded_len)
padded[:len(in_arr)] = in_arr
padded[len(in_arr):] = np.ma.masked

# now we can treat it an array divisible by k:
mean = padded.reshape((-1, k)).mean(axis=0)

# if you need to remove the masked-ness
assert not np.ma.is_masked(mean), "in_arr was too short to calculate all means"
mean = mean.data

【讨论】:

    【解决方案2】:

    您可以轻松地通过填充、重塑和计算每行要划分多少个元素来做到这一点:

    >>> import numpy as np
    >>> a = np.array([2,2,3,2,2,3,2,2,3,6])
    >>> k = 3
    

    填充数据

    >>> b = np.pad(a, (0, k - a.size%k), mode='constant').reshape(-1, k)
    >>> b
    array([[2, 2, 3],
           [2, 2, 3],
           [2, 2, 3],
           [6, 0, 0]]) 
    

    然后创建一个掩码:

    >>> c = a.size // k # 3
    >>> d = (np.arange(k) + c * k) < a.size # [True, False, False]
    

    d 的第一部分将创建一个包含[9, 10, 11] 的数组,并将其与a (10) 的大小进行比较,生成上述布尔掩码。

    然后划分:

    >>> b.sum(0) / (c + 1.0 * d)
    array([ 3.,  2.,  3.])
    

    上面将第一列除以 4 (c + 1 * True),其余除以 3。这是向量化的 numpy,因此,它可以很好地扩展到大型数组。

    一切都可以写得更短,我只是展示所有步骤以使其更清晰。

    【讨论】:

    • 如果len(a)可以被k整除,则用一整行零填充
    • 你为什么使用filled
    • @Eric 只是为了取回原始数组,而不是 masked 数组。是的,它确实添加了一行零,但不影响结果。避免零行将需要更多检查
    • 对,但是如果a = [1, 2], k=3masked数组是正确的结果,因为b[2]没有值
    【解决方案3】:

    通过解包链接将列表In展平。创建一个新列表,按列排列扁平列表lst,然后使用map 函数计算每列的平均值:

    from itertools import chain
    
    In = [[2, 2, 3], [2, 2, 3], [2, 2, 3], [6]]
    
    lst = chain(*In)
    k = 3
    
    In_by_cols = [lst[i::k] for i in range(k)]
    # [[2, 2, 2, 6], [2, 2, 2], [3, 3, 3]]
    
    Out  = map(lambda x: sum(x)/ float(len(x)), In_by_cols)
    # [3.0, 2.0, 3.0]
    

    在每个子列表的长度上使用 float 将在 python 2.x 上提供更准确的结果,因为它不会进行整数截断。

    【讨论】:

    • “在长度上使用 float ... 将提供更准确的结果” - 您的意思是“不会在 python 2 上进行整数截断”。在 python 3 上没有它也可以正常工作,可以说更好的解决方法是使用from __future__ import division
    • 是的,这会起作用,但我认为 python 标记专门指 python 2.x。将添加该行:“不会在 python 2 上进行整数截断”。谢谢
    猜你喜欢
    • 2023-01-19
    • 2020-03-29
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 2019-11-24
    • 2019-02-11
    相关资源
    最近更新 更多