在numpy / pandas中查找特定值之前的最后一个值

时间:2014-11-04 16:25:45

标签: python pandas numpy dataframe

我有一个pandas系列,我想找到一些值在某个其他特定值之前出现的最后一次的索引/位置(或布尔掩码)。

E.g。给出:

df = pd.DataFrame({'x':np.random.randint(10, 1000000)})

我想找到0的所有位置,这是9之前的最后位置。所以如果我的数组是

[9, 0, 3, 0, 1, 9, 4, 9, 0, 0, 9, 4, 0]

我只对第3和第9位的零感兴趣。请注意,在这里,我不担心在第12位的最后一个0会发生什么。我宁愿不在返回集中使用它,但这并不重要。

我目前的方法是:

df['last'] = np.nan
df.loc[df.x == 0, 'last'] = 0.0
df.loc[df.x == 9, 'last'] = 1.0
df.last.fillna(method='bfill', inplace=True)
df.loc[df.x == 0, 'last'] = np.nan
df.last.fillna(method='bfill', inplace=True)
df.last.fillna(value=0.0, inplace=True)
df.loc[df.x != 0, 'last'] = 0.0

有人会有更快或更简洁的方法吗?

3 个答案:

答案 0 :(得分:2)

您可以使用布尔索引和shift。例如:

>>> s = pd.Series([9, 0, 3, 0, 9, 4, 9, 0, 0, 9, 4, 0])
>>> s[(s == 0) & (s.shift(-1) == 9)]
3    0
8    0
dtype: int64

这将查找s中的索引位置,其值为0,紧跟9后。

编辑:略微调整,以便我们允许介于9和前一个零之间的值(另请参阅@ acushner'答案)...

这是一个稍微修改过的系列s;我们仍然希望索引3和8处的零:

>>> s = pd.Series([9, 0, 3, 0, 9, 4, 9, 0, 0, 4, 9, 0])
>>> t = s[(s == 0) | (s == 9)]
>>> t
0     9
1     0
3     0
4     9
6     9
7     0
8     0
10    9
11    0

ts中包含所有九和零的系列。我们可以像以前一样检索相关指数:

>>> t[(t == 0) & (t.shift(-1) == 9)]
3    0
8    0
dtype: int64

答案 1 :(得分:1)

非常简单地适应@ ajcr的答案:

s = pd.Series([9, 0, 3, 0, 1, 9, 4, 9, 0, 0, 9, 4, 0]) #using your example array
s = s[s.isin([0,9])]
s[(s == 0) & (s.shift(-1) == 9)]

答案 2 :(得分:0)

我认为这适用于一般性输入:

def find_last_a_before_b(arr, a, b):
    arr = np.asarray(arr)
    idx_a, = np.where(arr == a)
    idx_b, = np.where(arr == b)
    iss = idx_b.searchsorted(idx_a)
    mask = np.concatenate((iss[1:] != iss[:-1],
                           [True if iss[-1] < len(idx_b) else False]))
    return idx_a[mask]

>>> find_last_a_before_b([9, 0, 3, 0, 1, 9, 4, 9, 0, 0, 9, 4, 0], 0, 9)
array([3, 9])
>>> find_last_a_before_b([9, 0, 3, 0, 1, 9, 4, 9, 0, 0, 9, 4, 0], 9, 0)
array([ 0,  7, 10])

关键在于使用np.searchsorted来找出在给定的0之后出现哪9个,然后去除重复,以及在它之后没有9的最后一个。