为数字字符串创建一个指标,忽略 python pandas 中的特定数字

Creating an indicator for strings of numbers, ignoring a particular one in python pandas

我不知道如何给这个问题起标题,欢迎编辑。

我有一个pandas系列的数字(可以做成一个列表,类型并不重要)。

数字从 1 到 13。

例如:

13,13,1,1,1,1,13,2,1,1   

我想查找相同数字的字符串,但不计算 13 如果它在中间或开头。

我想要 return 一个新列表,当 nth 元素是 13 或与 (n-1)th 相同时作为指示符。例如,这将是:

 0,0,0,1,1,1,1,0,0,1

直到我观察到一个非 13 值,计数器才开始计数,然后它将 13s 计为之前的非 13 值。

它还需要尽可能快,所以我想尽可能避免使用大量 if 条件的疯狂循环。

开头的 13 很烦人;我想不出一种有效的矢量化方法来摆脱它们。也就是说,

def method1(s):
    out = ((s == s.shift()) | (s == 13)).astype(int)
    for i, x in s.iteritems():
        if x == 13: out[i] = 0
        else: break
    return out

def method2(s):
    s13na = s.replace(13, np.nan).ffill()
    indic = (s13na == s13na.shift()).astype(int)
    return indic

应该可以。第一种方法简单地询问是否等于之前出现的数字或 13,然后修补开始。第二个用 nan 替换所有 13,进行前向填充(以便 13 被最后一个非 13 数字或 nan 替换),然后进行通常的轮班检查。这给出了正确答案:

>>> method1(s)
0    0
1    0
2    0
3    1
4    1
5    1
6    1
7    0
8    0
9    1
dtype: int32
>>> (method1(s) == method2(s)).all()
True

性能将取决于数组的大小和 13 的分数..

>>> %timeit method1(s)
1000 loops, best of 3: 1.13 ms per loop
>>> %timeit method2(s)
1000 loops, best of 3: 704 µs per loop
>>> s2 = pd.concat([s]*100000).reset_index(drop=True)
>>> %timeit method1(s2)
10 loops, best of 3: 75.8 ms per loop
>>> %timeit method2(s2)
1 loops, best of 3: 203 ms per loop