我意识到我的头衔有点令人困惑,但我想如果我们以身作则,我会更清楚。我想要做的是一个矢量化测试,以检查给定系列中的任何值是否包含在由start
和stop
列的DataFrame对象定义的任何间隔中。
考虑系列valid
,它是名为trials
的DataFrame的列。以下是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`的单独DataFrame。它有三列:
<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']
的每一行设置为False
,如果其对应的trials['start']
到trials['stop']
之间的间隔与任何重叠blink['tstart']
到blink['tstop']
间隔。{/ p>
我可以遍历行并使用np.arange
和in
运算符在嵌套循环中执行此操作,但实际上需要数小时(我的实际数据集)比这个虚拟例子大得多)。我可以使用矢量化方法吗?如果没有,是否有更快的基于迭代的方法?
如果有任何不清楚的地方,我当然乐意提供更多细节。
答案 0 :(得分: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),而只需执行{{1} }。
从本质上讲,您将闪烁框架展平为一系列,然后您可以将其应用于每个试用
使用Isin(和OP数据):
转换为int64数据
isin
添加一行我们知道的是范围
trial = pd.load('trials.pickle').reindex(columns=['start','stop']).astype('int64')
blink = pd.load('blink.pickle').astype('int64')
构造我们想要测试的值范围
trial = trial.append(pd.Series(dict(start=1000,stop=1200)),ignore_index=True)
如果传递的开始/结束位于选择范围
,则返回trueselections = []
for r in blink.iterrows():
e = r[1]
selections.extend(list(np.arange(e['tstart'],e['tstop'])))
selections = pd.Series(selections)
我插入了一行我知道会传递的行,没有其他行传递
def f(s):
return s.isin(selections).all()
trial['valid'] = trial.apply(f,axis=1)
trial[trial.valid]
答案 1 :(得分:0)
假设trials
的大小为m
且blink
的大小为n
。
首先,在检查blink
中的每一行之前,按tstart
对trials
进行排序,合并重叠的一行,需要O(n log n)
,看看{{3} }}
在检查启动/停止对是否有效时,请遵循以下算法。
tstarts
tstarts
tstart
,则返回True tstop
,
如果它们与开始/停止对重叠,则返回True 上述算法可能会帮助您降低时间复杂度,以检查start/stop
对是否与blink
中的任何对重叠,而不是O(n)
与O(log n)
重叠,其中n是长度blink
时间复杂度将从O(mn)
降低到O(m log n) + O(n log n)
。如果m >> log n
和n
很大,那可能对您有很大帮助。