假设我有相同长度的n = 3列表,例如:
R1 = [7,5,8,6,0,6,7]
R2 = [8,0,2,2,0,2,2]
R3 = [1,7,5,9,0,9,9]
我需要找到第一个索引t,它验证n = 3,下面是一个句点p = 2的条件。编辑:句号p的意思是连续“方框”的数目。
R1[t] >= 5, R1[t+1] >= 5.在这里,t +p -1 = t+1,我们只需要验证两个盒子t和t+1。如果p等于3,则需要验证t、t+1和t+2。请注意,我们测试的数字总是相同的,对于每个索引,我们总是测试它是否大于5。对于所有"boxes".R2[t] >= 2, R2[t+1] >= 2R3[t] >= 9, R3[t+1] >= 9,条件总是相同的。
总共存在3 *p条件。
在这里,我要寻找的t是5 (索引从0开始)。
这样做的基本方法是使用for循环循环所有索引。如果为某些索引t找到条件,则将其存储在某个局部变量temp中,并验证索引在t+1和t+p -1之间的每个元素的条件仍然有效。如果在检查时,我们找到一个不满足条件的索引,我们就会忘记temp,然后继续前进。
如果我有大列表(比如10000个元素),那么在中最有效的方法是什么?有比for循环更有效的方法吗?
发布于 2020-07-05 23:40:31
由于您的所有条件都是相同的(>=),我们可以利用这一点。
此解决方案适用于任意数量的条件和任意大小的分析窗口,而不使用for循环。
您有一个数组:
>>> R = np.array([R1, R2, R3]).T
>>> R
array([[7, 8, 1],
[5, 0, 7],
[8, 2, 5],
[6, 2, 9],
[0, 0, 0],
[6, 2, 9],
[7, 2, 9]]你有阈值:
>>> thresholds = [5, 2, 9]因此,您可以检查条件在哪里得到满足:
>>> R >= thresholds
array([[ True, True, False],
[ True, False, False],
[ True, True, False],
[ True, True, True],
[False, False, False],
[ True, True, True],
[ True, True, True]])他们在同一时间相遇的地方:
>>> R_cond = np.all(R >= thresholds, axis=1)
>>> R_cond
array([False, False, False, True, False, True, True])从这里开始,您希望满足给定窗口的条件。
我们将利用布尔值可以加在一起的事实,并使用卷积来应用窗口:
>>> win_size = 2
>>> R_conv = np.convolve(R_cond, np.ones(win_size), mode="valid")
>>> R_conv
array([0., 0., 1., 1., 1., 2.])在满足窗口范围内所有条件的索引处,结果数组的值将等于win_size。
因此,让我们检索第一个索引:
>>> index = np.where(R_conv == win_size)[0][0]
>>> index
5如果不存在这样的索引,它将引发一个IndexError,我让您处理这个问题。
因此,作为一个单线函数,它给出了:
def idx_conditions(arr, thresholds, win_size, condition):
return np.where(
np.convolve(
np.all(condition(arr, thresholds), axis=1),
np.ones(win_size),
mode="valid"
)
== win_size
)[0][0]我将条件作为参数添加到函数中,以便更通用。
>>> from operator import ge
>>> idx_conditions(R, thresholds, win_size, ge)
5发布于 2020-07-05 22:31:07
这可能是一种方式:
R1 = [7,5,8,6,0,6,7]
R2 = [8,0,2,2,0,2,2]
R3 = [1,7,5,9,0,9,9]
for i,inext in zip(range(len(R1)),range(len(R1))[1:]):
if (R1[i]>=5 and R1[inext]>=5)&(R2[i]>=2 and R2[inext]>=2)&(R3[i]>=9 and R3[inext]>=9):
print(i)输出:
5编辑:泛化可以是:
def foo(ls,conditions):
index=0
for i,inext in zip(range(len(R1)),range(len(R1))[1:]):
if all((ls[j][i]>=conditions[j] and ls[j][inext]>=conditions[j]) for j in range(len(ls))):
index=i
return index
R1 = [7,5,8,6,0,6,7]
R2 = [8,0,2,2,0,2,2]
R3 = [1,7,5,9,0,9,9]
R4 = [1,7,5,9,0,1,1]
R5 = [1,7,5,9,0,3,3]
conditions=[5,2,9,1,3]
ls=[R1,R2,R3,R4,R5]
print(foo(ls,conditions))输出:
5而且,如果数组多次匹配条件,则可以返回索引列表:
def foo(ls,conditions):
index=[]
for i,inext in zip(range(len(R1)),range(len(R1))[1:]):
if all((ls[j][i]>=conditions[j] and ls[j][inext]>=conditions[j]) for j in range(len(ls))):
print(i)
index.append(i)
return index
R1 = [6,7,8,6,0,6,7]
R2 = [2,2,2,2,0,2,2]
R3 = [9,9,5,9,0,9,9]
R4 = [1,1,5,9,0,1,1]
R5 = [3,3,5,9,0,3,3]
conditions=[5,2,9,1,3]
ls=[R1,R2,R3,R4,R5]
print(foo(ls,conditions))输出:
[0,5]发布于 2020-07-05 22:38:24
下面是一个使用numpy的解决方案,没有for循环:
import numpy as np
R1 = np.array([7,5,8,6,0,6,7])
R2 = np.array([8,0,2,2,0,2,2])
R3 = np.array([1,7,5,9,0,9,9])
a = np.logical_and(np.logical_and(R1>=5,R2>=2),R3>=9)
np.where(np.logical_and(a[:-1],a[1:]))[0].item()输出
5编辑:
Generalization
假设您有一个列表( R )和一个条件列表( c )
R = [[7,5,8,6,0,6,7],
[8,0,2,2,0,2,2],
[1,7,5,9,0,9,9]]
c = [5,2,9]首先,我们将它们转换为numpy数组。重塑(-1,1)将c转换为列矩阵,这样我们就可以在>=运算符中使用pythons广播功能。
R = np.array(R)
c = np.array(c).reshape(-1,1)
R>=c
output:
array([[ True, True, True, True, False, True, True],
[ True, False, True, True, False, True, True],
[False, False, False, True, False, True, True]])然后,我们使用reduce函数在所有行之间执行逻辑操作
a = np.logical_and.reduce(R>=c)
a
output:
array([False, False, False, True, False, True, True])接下来,我们通过删除a的第一个和最后一个元素来创建两个数组,并在它们之间执行一个逻辑&这表明哪两个后续元素满足所有列表中的条件:
np.logical_and(a[:-1],a[1:])
output:
array([False, False, False, False, False, True])现在np.where只显示True元素的索引
np.where(np.logical_and(a[:-1],a[1:]))[0].item()
output:
5https://stackoverflow.com/questions/62746907
复制相似问题