多个条件的过滤列表
Posted
技术标签:
【中文标题】多个条件的过滤列表【英文标题】:Filtering list on multiple conditions 【发布时间】:2020-12-07 23:37:13 【问题描述】:通过多个条件过滤多个列表的最有效方法是什么?例如。
time = [1, 2, 3, 4, 5]
x = [3, 3, 3, 3, 3]
y = [5, 5, 8, 8, 8]
我想在所有 3 个列表中找到条件索引,这样
time < 4
x > 2
y > 7
这应该会给我结果
[2]
如果上述数据在数据框中,则 pandas 方法将是
(df['time'] < 4) & (df['x'] > 2) & (df['y'] > 7)
蛮力方法类似于
idx = []
for i in range(len(time)):
if time[i] < 4 and x[i] > 2 and y[i] > 7:
idx.append(i)
但是,这些变量可能会变得非常大(500,000+),因此 for 循环的效率会非常低。
【问题讨论】:
循环是 O(n) - 线性运行时间。怎么这么低效? [3] 的正确答案如何?满足所有要求的唯一索引是 2。 @Prune 抱歉,我在 Matlab 中研究了 1 个索引,而不是基于 0 的东西。固定 那么为什么不把这些值放在一个数据框中呢? @Nick 代码正在部署到 pandas 不可用的平台 【参考方案1】:你想要像下面这样的东西
[k for k,g in enumerate(zip(time,x,y)) if g[0]<4 and g[1]>2 and g[2]>7]
或更快(感谢@Steven Rumbalski)
[k for k, (_t, _x, _y) in enumerate(zip(time, x, y)) if _t < 4 and _x > 2 and _y > 7]
给了
[2]
【讨论】:
谢谢!只是一个一般性问题,列表理解实际上比 for 循环更快吗? @so_many_questions 抱歉,我不知道它是否会比for
循环更快
这比 O(n) 好多少?实际上它会比问题中的循环慢
如果每一盎司的速度真的很重要,那么下标g
可能会减慢一点速度。 [k for k, (_t, _x, _y) in enumerate(zip(time, x, y)) if _t < 4 and _x > 2 and _y > 7]
可能会更快。一个元组解包可能比三个下标快。
@Harsh。无论如何都是 O(n)。 pandas 版本隐藏了 C 代码中的 O(n),但它仍然存在。【参考方案2】:
我%timeit
3 种方法。 apply 方法显示出最好的速度 - 比 py 循环快 25%,比 DF 基本比较快 2 倍。
def foo(df):
return list(df[(df.time < 4) & (df.x > 2) & (df.y > 7)].time)
print("\nMETHOD 1: DF comparison")
%timeit foo(df)
%timeit foo(df)
%timeit foo(df)
def foo(t, x, y):
idx = []
for i in range(len(t)):
if t[i] < 4 and x[i] > 2 and y[i] > 7:
idx.append(i)
return(idx)
print("\nMETHOD 2: py loop")
%timeit foo(time, x, y)
%timeit foo(time, x, y)
%timeit foo(time, x, y)
def foo(df):
return df.apply(lambda r: r.time if ((r.time < 4) & (r.x > 2)& (r.y > 7)) else np.nan, axis=1).unique()
print("\nMETHOD 3: DF apply")
%timeit foo(df)
%timeit foo(df)
%timeit foo(df)
METHOD 1: DF comparison
698 µs ± 19.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
696 µs ± 6.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
690 µs ± 16.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
METHOD 2: py loop
481 µs ± 11.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
468 µs ± 4.08 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
466 µs ± 4.71 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
METHOD 3: DF apply
355 ms ± 5.82 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
356 ms ± 10.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
360 ms ± 8.78 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
【讨论】:
OP 在 cmets 中声明他们不能使用 pandas 老实说,for 循环比 df 比较快 @StevenRumbalski - 有趣。我使用 [np.random.randint(1000) for n in range(10000)] 创建了 3 个列表......我在 MacPro 上使用 Py3.7。【参考方案3】:time = [1, 2, 3, 4, 5]
x = [3, 3, 3, 3, 3]
y = [5, 5, 8, 8, 8]
# Get True/False lists
t = [x<4 for x in time]
x1 = [i > 2 for i in x]
y2 = [i > 7 for i in y]
# Bitwise and
b = [x&y for x,y in zip(t,x1)]
# Bitwise and again, with index lookup of remianing True
time[[x&y for x,y in zip(b,y2)].index(True)]
输出
3
【讨论】:
这似乎效率更低以上是关于多个条件的过滤列表的主要内容,如果未能解决你的问题,请参考以下文章