我有一个"信号"系列,有1个值(开(、-1个值(关(和零值:
signal = pd.Series([0, 1, 0, 0, -1, 0, 1, 1, 0, -1])
我需要返回连续开和关信号之间的行数,在结果下方:
首次出现=3
第二次出现=2
要考虑存在两个或多个连续的on值时,引用是最后一个。
非常感谢。
问候Tom
您可以利用系列的索引标签:
s = signal[signal!=0]
np.diff(s[s.shift(-1) != s].index)[::2]
输出:
array([3, 2])
解释
首先,去除零:
s = signal[signal!=0]
然后,删除连续重复的(保留最后一个(:
s = s[s.shift(-1) != s]
查看输出以了解发生了什么:
1 1
4 -1
7 1
9 -1
dtype: int64
看到了吗,现在我们有一个,后面是负的,原始索引保留在那里。因此,我们可以计算这些指数的差异(只对正指数进行切片(:
np.diff(s.index)[::2]
基本解决方案
我要做的方法是定义几个状态,比如ON_SIGNAL_SEEN
和RESET
,然后逐步完成该系列,将事物视为状态机。因此,当你浏览每个项目时,你会有不同的行为,这取决于当前状态和系列中当前项目的组合。类似(伪代码(:
let counter = 0;
let result = [];
let state = RESET
for n in series:
if state == RESET:
if n == 1:
state = ON_SEEN
counter = 0
elif state == ON_SEEN
if n == -1
counter++
results += [counter]
state = RESET
elif n == 0
counter++
elif n == 1
counter = 0
return result
如果将每个状态定义为一个类,然后调用state = state.next(item)
,则还有一种更为面向对象的方法,其中state的值可以是状态对象ON_SEEN
或RESET
之一,每个状态对象都有不同的next()
实现。
Regex解决方案
由于正则表达式是状态机,我认为您还可以将数据转换为字符串并查找ab*?c
模式。在这里,我在所有数字上加了2,以避免不得不处理-1
与1
(再次伪代码(:
result = []
//Change the nums from {0,1,-1} to {0,1,2} for easier matching
series = series.add_element_wise(2)
// Change to a string so we can use regex
series_string = (string) series
//Find matches of 2, then 1's, then 0 (with non-greedy matching)
for m in /21*?0/.match(series_string)
// Save the length of the match
result += [m.length]