1

我意识到我的标题有点混乱,但我想如果我们继续举例,我可以更清楚地说明。我想要做的是一个矢量化测试,以检查给定系列中的任何值是否包含在由具有startstop列的 DataFrame 对象定义的任何间隔中。

考虑系列,valid,它是名为 的 DataFrame 的列trials。这是trials看起来的样子:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 156 entries, 0 to 155
Data columns (total 3 columns):
start    156  non-null values
stop     156  non-null values
valid    156  non-null values
dtypes: bool(1), float64(2)

我有一个名为“blink”的单独数据框。它有三列:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 41 entries, 0 to 40
Data columns (total 3 columns):
tstart    41  non-null values
tstop     41  non-null values
dur       41  non-null values
dtypes: bool(1), float64(2)

tstop最后一列没有直接关系:它是眼球的持续时间,即和之间的差异tstart

如果每行之间的间隔对应于与任何trials['valid']to间隔重叠,我想设置每一行。Falsetrials['start']trials['stop']blink['tstart']blink['tstop']

可以遍历行并np.arangein运算符一起在嵌套循环中执行此操作,但实际上需要数小时(我的实际数据集比这个虚拟示例大得多)。我可以使用矢量化方法吗?如果没有,是否有更快的基于迭代的方法?

如果有任何不清楚的地方,我当然很乐意提供更多细节。

4

2 回答 2

1

你的眨眼数据

In [27]: blink = pd.DataFrame(dict(tstart = [0,10], tstop = [5,15]))

In [28]: blink_s = blink.stack()

In [29]: blink_s.index = [ "%s_%s" % (v,i) for i, v in blink_s.index ]

构建一系列眨眼(有点像旋转),但我们需要新的名字

In [37]: blink_s
Out[37]: 
tstart_0     0
tstop_0      5
tstart_1    10
tstop_1     15

试验数据

In [30]: trial = pd.DataFrame(dict(start = [3,7,12],stop=[4,10,16]))

将 blink_s 平铺在试验的各行中

In [32]: blink_df = pd.DataFrame([ blink_s for i in trial.index ])

加入他们

In [33]: x = trial.join(blink_df)

In [34]: x
Out[34]: 
   start  stop  tstart_0  tstop_0  tstart_1  tstop_1
0      3     4         0        5        10       15
1      7    10         0        5        10       15
2     12    16         0        5        10       15

你的答案就是一个向量化的布尔表达式(这可能是一个很长的表达式,所以你应该以编程方式生成它,但这样做并不复杂)

In [35]: x['valid'] = ((x.start>x.tstart_0) & (x.stop<=x.tstop_0)) | ((x.start>x.tstart_1)&(x.stop<=x.tstop_1))

In [36]: x
Out[36]: 
   start  stop  tstart_0  tstop_0  tstart_1  tstop_1  valid
0      3     4         0        5        10       15   True
1      7    10         0        5        10       15  False
2     12    16         0        5        10       15  False

如果您想将浮点数据作为您的 tstart/tstop 标准,这将起作用。如果您将间隔限制为仅 int 数据,那么解决方案会更简单一些,因为您可以只创建一系列包含的值(如 blink_s),然后执行isin.

从本质上讲,您是将闪烁框架展平为一系列,然后您可以将其应用于每个试验

使用 Isin(和 OP 数据):

转换为 int64 数据

trial = pd.load('trials.pickle').reindex(columns=['start','stop']).astype('int64')
blink = pd.load('blink.pickle').astype('int64')

添加一行,我们知道是 ni 范围

trial = trial.append(pd.Series(dict(start=1000,stop=1200)),ignore_index=True)

构造我们要测试的值的范围

selections = []
for r in blink.iterrows():
    e = r[1]
    selections.extend(list(np.arange(e['tstart'],e['tstop'])))
selections = pd.Series(selections)

如果传递的开始/停止在选择范围内,则返回 true

def f(s):
    return s.isin(selections).all()
trial['valid'] = trial.apply(f,axis=1)

trial[trial.valid]

我插入了我知道会通过的 1 行,没有其他行通过

     start  stop valid
156   1000  1200  True
于 2013-04-07T17:39:23.080 回答
0

假设 is 的大小和istrialsm大小。blinkn

blink首先,在你检查每一行tstart之前排序trials,合并重叠的,它需要O(n log n),看看这个

在检查启动/停止对是否有效时,请遵循以下算法。

  1. 使用二分查找在排序后插入开始tstarts
  2. 使用二分查找在排序后插入停止tstarts
  3. 如果tstartstart 和 stop 之间有任何,则返回 True
  4. 找到开始之前的那个,找到它tstop,如果它们与开始/停止对重叠,则返回 True
  5. 返回假

上述算法可能会帮助您降低时间复杂度,以检查一对是否start/stop与任何对重叠blink或不重叠O(n)O(log n)其中 n 是blink

时间复杂度将从 降低O(mn)O(m log n) + O(n log n)。如果m >> log nn很大,那可能对您有很大帮助。

于 2013-04-07T18:41:49.943 回答