我有一个Numpy的True和False值数组,例如:
test = np.array([False, False, False, True, False, True, False, True, False,False, False, False, True, True, False, True])
我想知道以下模式(False,True,False)在数组中发生的次数。在上面的测试中,它将是4。这不是唯一的模式,但是我认为当我理解这段代码时,我可能还会制作其他代码。
当然,我可以遍历数组。如果第一个值相等,则比较下一个,否则转到循环中的下一个值。像这样:
totalTimes=0
def swapToBegin(x):
if(x>=len(test)):
x-=len(test)
return(x)
for i in range(len(test)):
if(test[i]==False):
if(test[swapToBegin(i+1)]==True):
if test[swapToBegin(i+2)]==False:
totalTimes += 1
但是,由于我需要多次执行此操作,因此这段代码非常慢。由于可以快速显示我的需求,因此无法进行任何改进。但是必须有更好的解决方案。
有没有更好的方法来搜索数组中的模式?它不需要合并数组的结尾和开头,因为我以后可以做到这一点。但是,如果可以包含它,那就太好了。
答案 0 :(得分:0)
您可以使用包含[False,True,False]的数组,然后搜索它。
searchfor = np.array([False, True, False])
答案 1 :(得分:0)
您尚未提供test
的大小的详细信息,因此对于我使用的方法的基准,它有1000个元素。下一个重要的部分是实际分析代码。您不能说它慢(或快),直到有可靠的数字来备份它。您的代码在我的计算机上运行大约1.49毫秒。
您通常可以通过删除python循环并将其替换为numpy函数来获得numpy的改进。
因此,与其单独测试每个元素(很多if
条件可能会减慢速度),不如将它们全部放入一个数组比较中,然后使用all
来检查每个元素是否匹配。
check = array([False, True, False])
sum([(test[i:i+3]==check).all() for i in range(len(test) - 2)])
分析显示它运行在1.91毫秒内。
实际上是倒退了一步。那么,是什么原因导致减速?好吧,使用[]
进行数组访问会创建一个新的数组对象,该对象可能是其中的一部分。更好的方法可能是使用偏移创建一个大数组,然后使用广播进行比较。
sum((c_[test[:-2], test[1:-1], test[2:]] == check).all(1))
这次将check
与数组c_[test[:-2], test[1:-1], test[2:]]
的每一行进行比较。 all
的轴参数(1)仅用于计算每个元素匹配的行。这运行在40.1us。这是一个巨大的进步。
当然,就复制元素而言,创建要广播的数组将花费大量成本。为什么不直接进行比较?
sum(all([test[i:len(test)-2+i]==v for i, v in enumerate(check)], 0))
运行时间为18.7us。
加快速度的最后一个想法是使用as_strided
。这是一个高级技巧,可以更改数组的步幅以获取偏移数组而不复制任何数据。通常这不值得付出努力,但我在这里只是为了好玩而已。
sum((np.lib.index_tricks.as_strided(test, (len(test) - len(check) + 1, len(check)), test.strides + (1, )) == check).all(1))
这也大约需要40us。因此,在这种情况下,无需付出额外的努力。