多个条件的过滤列表

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 &lt; 4 and _x &gt; 2 and _y &gt; 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

【讨论】:

这似乎效率更低

以上是关于多个条件的过滤列表的主要内容,如果未能解决你的问题,请参考以下文章

如何根据多个条件过滤列表?

过滤具有多个条件的列表

高级过滤器,为1行选择了多个条件

React:使用多个复选框过滤数组列表

基于Python中的多个条件进行过滤

使用多个条件过滤对象,包括比较两个对象字段