python pandas从一系列布尔值中获取索引边界

问题描述:

我试图根据一些特性来剪切视频。 我目前的策略是针对每个帧的pandas系列布尔值,这些布尔值由时间戳索引。 True保留它,False转储它。python pandas从一系列布尔值中获取索引边界

由于我计划剪切视频,我需要从这个列表中提取边界,以便我可以告诉fmpeg开始和结束我想从主视频中提取的部分。

涂总结:

我有一个pandas系列,看起来像这样:

acquisitionTs 
0.577331  False 
0.611298  False 
0.645255  False 
0.679218  False 
0.716538  False 
0.784453  True 
0.784453  True 
0.818417  True 
0.852379  True 
0.886336  True 
0.920301  True 
0.954259  False 
      ... 
83.393376 False 
83.427345 False 
dtype: bool 

(截断提出的理由,但时间戳通常在0开始)

,我需要得到True序列的边界,所以在这个例子中我应该得到[[t_0,t_1],[t_2,t_3]n, ... [t_2n-1,t_2n]]t_0 = 0.784453t_1 = 0.920301如果我有n不同的序列True在我的熊猫系列。

现在probleme看起来很简单,其实你可以只通过一个移动的序列和做出XOR之间得到布尔的列表,True是对边界

e = df.shift(periods=1, freq=None, axis=0)^df 
print(e[e].index) 

(与df是一个熊猫系列) 还有一些工作要做,比如确定第一个元素是上升沿还是下降沿,但是这个黑客行得通。

然而,这似乎并不pythonic。事实上,这个问题非常简单,我相信在pandas,numpy或者甚至python之间必须有一个预构建的函数,它可以很好地适用于单个函数调用,而不是像上面那样的破解。 groupby功能似乎很有前途,但我从未使用过。

这样做的最好方法是?

我会使用一个Dataframe而不是一个Series(它实际上也适用于一个Series)。

df 
    acquisitionTs Value 
0  0.577331 False 
1  0.611298 False 
2  0.645255 False 
3  0.679218 False 
4  0.716538 False 
5  0.784453 True 
6  0.784453 True 
7  0.818417 False 
8  0.852379 True 
9  0.886336 True 
10  0.920301 True 
11  0.954259 False 

,我会做:

df[df.Value.diff().fillna(False)] 
    acquisitionTs Value 
5  0.784453 True 
7  0.818417 False 
8  0.852379 True 
11  0.954259 False 

所以,当你知道第值为false在这里,你知道0-4是假,然后将其各项指标在开关(5,7,8- ,11)

groupby函数不会帮助你我认为,因为它会失去你的True/False值的顺序(在我的例子中你将有2个组,而不是5个)。

+0

使用资源,而不是引入无关的依赖性的好处。 –

+0

感谢您的回答!然而,你的代码似乎并不知道第一个元素,它可以是True或False,所以你会以与你第一次想要的相反的方式结束。 一个简单的修复方法是将第一行插入到结果中(如果它为True)(最后一行也是如此) 感谢您的帮助! 编辑:其实我们可以只看结果的第一个(也是最后一个)元素的值,它告诉边缘是上升还是下降,所以起初没有问题。 –

你可以使用scipy.ndimage.label识别的True S上的集群:

In [102]: ts 
Out[102]: 
0.069347 False 
0.131956 False 
0.143948 False 
0.224864 False 
0.242640  True 
0.372599 False 
0.451989 False 
0.462090 False 
0.579956  True 
0.588791  True 
0.603638 False 
0.625107 False 
0.642565 False 
0.708547 False 
0.730239 False 
0.741652 False 
0.747126  True 
0.783276  True 
0.896705  True 
0.942829  True 
Name: keep, dtype: bool 

In [103]: groups, nobs = ndimage.label(ts); groups 
Out[103]: array([0, 0, 0, 0, 1, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3], dtype=int32) 

一旦你拥有了groups阵列,您可以使用groupby/agg找到相关时间:

result = (df.loc[df['group'] != 0] 
       .groupby('group')['times'] 
       .agg({'start':'first','end':'last'})) 

例如,

import numpy as np 
import pandas as pd 
import scipy.ndimage as ndimage 
np.random.seed(2016) 

def make_ts(N, ngroups): 
    times = np.random.random(N) 
    times = np.sort(times) 
    idx = np.sort(np.random.randint(N, size=(ngroups,))) 
    arr = np.zeros(N) 
    arr[idx] = 1 
    arr = arr.cumsum() 
    arr = (arr % 2).astype(bool) 
    ts = pd.Series(arr, index=times, name='keep') 
    return ts 

def find_groups(ts): 
    groups, nobs = ndimage.label(ts) 
    df = pd.DataFrame({'times': ts.index, 'group': groups}) 
    result = (df.loc[df['group'] != 0] 
       .groupby('group')['times'] 
       .agg({'start':'first','end':'last'})) 
    return result 

ts = make_ts(20, 5) 
result = find_groups(ts) 

产生

  start  end 
group      
1  0.242640 0.242640 
2  0.579956 0.588791 
3  0.747126 0.942829 

要获取的开始和结束时间为一个列表的列表,你可以使用:

In [125]: result.values.tolist() 
Out[125]: 
[[0.24264034406127022, 0.24264034406127022], 
[0.5799564094638113, 0.5887908182432907], 
[0.747126, 0.9428288694956402]] 

使用ndimage.label很方便,但要注意的是,还可以计算此无scipy

def find_groups_without_scipy(ts): 
    df = pd.DataFrame({'times': ts.index, 'group': (ts.diff() == True).cumsum()}) 
    result = (df.loc[df['group'] % 2 == 1] 
       .groupby('group')['times'] 
       .agg({'start':'first','end':'last'})) 
    return result 

这里的主要想法是找到使用(ts.diff() == True).cumsum()True的群集的标签。 ts.diff() == Truets.shift()^ts的结果相同,但速度稍快。以累积和(即主叫cumsum)对待True为等于1且如False等于0,因此每次True遇到由1的累积和增加。因此每个群集被标记有不同数目:

In [111]: (ts.diff() == True).cumsum() 
Out[111]: 
0.069347 0 
0.131956 0 
0.143948 0 
0.224864 0 
0.242640 1 
0.372599 2 
0.451989 2 
0.462090 2 
0.579956 3 
0.588791 3 
0.603638 4 
0.625107 4 
0.642565 4 
0.708547 4 
0.730239 4 
0.741652 4 
0.747126 5 
0.783276 5 
0.896705 5 
0.942829 5 
Name: keep, dtype: int64