查找 pandas.Series 的值何时变化至少 x

Posted

技术标签:

【中文标题】查找 pandas.Series 的值何时变化至少 x【英文标题】:Find when the values of a pandas.Series change by at least x 【发布时间】:2019-04-18 02:04:19 【问题描述】:

我有一个存储为 pandas.Series 的时间序列,我需要找出时间序列跟踪的值何时变化至少 x。

在伪代码中:

print s(0)
s*=s(0)
for all t in ]t, t_max]:
    if |s(t)-s*| > x:
        s* = s(t)
        print s*

天真地,这可以用 Python 编码如下:

import pandas as pd

def find_changes(s, x):

    changes = []
    s_last = None

    for index, value in s.iteritems():

        if s_last is None:
            s_last = value 

        if value-s_last > x or s_last-value > x:
            changes += [index, value]
            s_last = value
    return changes

我的数据集很大,不能只用上面的方法。此外,由于我将运行它的框架的限制,我不能使用 Cython 或 Numba。我可以(并且计划)使用 pandas 和 NumPy。

我正在寻找有关使用哪些 NumPy 向量化/优化方法以及如何使用的指导。

谢谢!

编辑:更改代码以匹配伪代码。

【问题讨论】:

这个问题在内部具有很强的线性关系,因为在你看到它之前没有迹象表明下一个阈值在哪里。所以看到一个并行/矢量化的解决方案会很有趣。 另外,有几件事我不太确定: 1. 您的伪代码似乎与您的 Python 代码不同。 2. 你的数据有多大,因为即使是 Python 代码也最多可以在几分钟内处理数十亿行。 @QuangHoang 我修复了代码以匹配伪代码,在我编写 OP 时一定是复制粘贴错误。数据集有 ~ 100 GB。 内存大小无关紧要,除非您需要对每一列都这样做。否则,重要的是行数。 @dd_rlwll 单个文件 100GB?你如何存储原始数据? 【参考方案1】:

我不知道我是否理解正确,但我是这样解释问题的:

import pandas as pd
import numpy as np

# Our series of data.

data = pd.DataFrame(np.random.rand(10), columns = ['value'])

# The threshold.

threshold = .33

# For each point t, grab t - 1. 

data['value_shifted'] = data['value'].shift(1)

# Absolute difference of t and t - 1.

data['abs_change'] = abs(data['value'] - data['value_shifted'])

# Test against the threshold.

data['change_exceeds_threshold'] = np.where(data['abs_change'] > threshold, 1, 0)

print(data)

给予:

      value  value_shifted  abs_change  change_exceeds_threshold
0  0.005382            NaN         NaN                         0
1  0.060954       0.005382    0.055573                         0
2  0.090456       0.060954    0.029502                         0
3  0.603118       0.090456    0.512661                         1
4  0.178681       0.603118    0.424436                         1
5  0.597814       0.178681    0.419133                         1
6  0.976092       0.597814    0.378278                         1
7  0.660010       0.976092    0.316082                         0
8  0.805768       0.660010    0.145758                         0
9  0.698369       0.805768    0.107400                         0

【讨论】:

解决方案很简洁,但我认为它与伪代码不同。 他不只是想与前一点进行比较,而是要与上次违规后的所有点进行比较。想象一下,如果系列正在增加,那么我们将通过重置查看diff() 中的cumsum() 这似乎与应用 diff() 并将新列与阈值进行比较相同。这不是我要照顾的。 @QuangHoang 你说得对。不幸的是,这个系列并不单调。【参考方案2】:

我不认为伪代码可以向量化,因为s* 的下一个状态取决于最后一个状态。有一个纯python解决方案(1次迭代):

import random
import pandas as pd

s = [random.randint(0,100) for _ in range(100)]
res = [] # record changes
thres = 20

ss = s[0]
for i in range(len(s)):
    if abs(s[i] - ss) > thres:
        ss = s[i]
        res.append([i, s[i]])

df = pd.DataFrame(res, columns=['value'])

我认为在这种情况下没有办法比 O(N) 跑得更快。

【讨论】:

我在这个问题上花了几个小时,我自己无法击败 O(N)。但是,我希望可以通过 NumPy 函数的重要组合来优化循环。如果没有任何结果,我可能别无选择,只能安装 Cython。 @dd_rlwll 没有比 O(N) 更好的解决方案,即使 numpy 提供的函数也救不了你。如果您计算创建开销的对象,它们可能会更糟。 尤其是这种情况下有 100GB 的数据,你不能创建这么大的数据框。您应该使用较小的块并在每个特定循环中将结果刷新到磁盘。 我不想详细介绍数据的结构(或存储),但它已经被分块读取,并且定期刷新结果。以防我上面的信息不清楚,我知道该解决方案不会比 O(N) 更好地扩展。这并不意味着每个循环操作都不能被优化为比我在 OP 中的幼稚代码版本运行得更快。 块与否,似乎天真的方法有效。而且这不是那么耗时。我敢打赌,您在 *** 上花在这个问题上的时间足以运行该算法多次。

以上是关于查找 pandas.Series 的值何时变化至少 x的主要内容,如果未能解决你的问题,请参考以下文章

pandas Series

pandas数组(pandas Series)-向量化运算

pandas数组(pandas Series)-apply方法自定义函数

Pandas Series.apply() 和 Series.map() 有啥区别? [复制]

Pandas Series .loc() 附加后访问错误

pandas Series' 对象没有属性 'find'