查找 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数组(pandas Series)-apply方法自定义函数