【问题标题】:rolling statistics in numpy or pytrochnumpy 或 pytorch 中的滚动统计信息
【发布时间】:2020-08-11 15:42:49
【问题描述】:

我有一个传感器的张量数据,每个张量的形状都是 (4,1500) 这是 1500 个时间点,每个时间点我有 4 个特征。 我想用滚动平均值或其他滚动统计数据“平滑”序列。最终目标是尝试使用滚动统计而不是长原始序列来改进 lstm 自动编码器。 我熟悉熊猫的滚动窗口,目前我正在这样做:

#tensor shape:
 data.shape
 (4,1500)

 #convert data to numpy array and then to dataframe and perform rolling mean
 rolled_data=pd.DataFrame(data.numpy().swapaxes(1,0)).rolling(10).mean()[::10]
 rolled_data.shape
 (150, 4)

 # convert back the dataframe to tensor
 tensor_rolled_data=torch.Tensor(rolled_data.to_numpy().swapaxes(1,0))
 tensor_rolled_data.shape
 torch.Size([4, 150])

我的问题是——有更好的方法吗? numpy/torch 中的函数可以以更清洁或更有效的方式进行滚动统计?

【问题讨论】:

    标签: python pandas numpy pytorch


    【解决方案1】:

    由于您按窗口大小跨步输出,这实际上更类似于通过平均进行下采样,而不是计算滚动统计信息。我们可以通过简单地重塑初始张量来利用没有重叠的事实。


    使用Tensor.reshape

    假设您的 data 张量具有可被 10 整除的形状,那么您只需将张量重塑为形状 (4, 150, 10) 并沿最后一个维度计算统计量。例如

    win_size = 10
    tensor_rolled_data = data.reshape(data.shape[0], -1, win_size).mean(dim=2)
    

    此解决方案与您的tensor_rolled_data 给出的结果并不完全相同,因为在此解决方案中,第一个条目将包含前 10 个样本的平均值,第二个条目将包含后 10 个样本的平均值,依此类推。 .. pandas 解决方案是一个“因果过滤器”,因此第一个条目将包含直到样本 0(包括样本 0)的 10 个最近样本的平均值,第二个条目将包含直到样本 10(包括样本 10)的 10 个最近样本,等等。 ..(请注意,pandas 解决方案中的第一个条目是 nan,因为之前的样本少于 10)。

    如果这种差异不可接受,您可以通过首先填充 9 个 nan 值并剪掉最后 9 个样本来重新创建 pandas 结果。

    import torch.nn.functional as F
    win_size = 10
    # pad with `nan` to match behavior of pandas
    data_padded = F.pad(data[None, :, :-(win_size - 1)], (win_size - 1, 0), 'constant', float('nan')).squeeze(0)
    # find mean of groups of N samples
    tensor_rolled_data = data_padded.reshape(data.shape[0], -1, win_size).mean(dim=2)
    

    使用Tensor.unfold

    解决有关重叠时该怎么做的评论。如果您只对平均统计量感兴趣,那么有多种计算方法(例如卷积、平均池化、张量展开)。也就是说,Tensor.unfold 提供了最通用的解决方案,因为它可以用于计算窗口上的任何统计数据。例如

    # same as first example above
    win_size = 10
    tensor_rolled_data = data.unfold(dimension=1, size=win_size, step=win_size).mean(dim=2)
    

    # same as second example above
    import torch.nn.functional as F
    win_size = 10
    data_padded = F.pad(data.unsqueeze(0), (win_size - 1, 0), 'constant', float('nan')).squeeze(0)
    tensor_rolled_data = data_padded.unfold(dimension=1, size=win_size, step=win_size).mean(dim=2)
    

    在上述情况下,展开产生与重塑相同的结果,因为大小和步长相等。但是,与 reshape 不同,展开还支持 size != step。

    win_size = 10
    stride = 2
    tensor_rolled_data = data.unfold(1, win_size, stride).mean(dim=2).mean(dim=2)
    # produces shape [4, 746]
    

    或者您可以使用win_size - 1 值填充特征的前面以获得与熊猫相同的结果。

    import torch.nn.functional as F
    win_size = 10
    stride = 2
    data_padded = F.pad(data.unsqueeze(0), (win_size - 1, 0), 'constant', float('nan')).squeeze(0)
    tensor_rolled_data = data_padded.unfold(1, win_size, stride).mean(dim=2)
    # produces shape [4, 750]
    

    注意 在实践中,您可能不希望 pad 使用 NaN,因为这可能会变得非常令人头疼。相反,您可以使用零填充、'replicate' 填充或'mirror' 填充。

    【讨论】:

    • 感谢您的精彩解释!当不需要重叠时,在 dim2 上进行整形和平均是非常棒的。顺便说一句,您将如何处理重叠?
    • @RachelShalom 我添加了关于窗口形状!= 步长的一般情况的详细信息。
    猜你喜欢
    • 2019-02-27
    • 1970-01-01
    • 2012-08-29
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2021-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多