【问题标题】:Substituting a list comprehension solution for numpy isin用列表理解解决方案替换 numpy isin
【发布时间】:2021-11-20 07:02:33
【问题描述】:

一段时间以来,我一直试图让我的彗星程序的慢速部分运行得更快。我有一行如下

s1=np.isin(secondsplit,file2new)

secondsplit 是一个 numpy 数组。平均而言,它的大小约为 600 x 600,并且充满了浮动。 file2new 是一个浮点数列表,大小通常为 300-700。

我在堆栈交换论坛上讨论了这个问题,并得到了一个解决方案,它使用列表理解和将 file2new 转换为集合来加快处理速度。 我的小规模测试代码有效,列表理解速度提高了 5 倍。当我扩大规模并将彗星程序更改为以相同方式使用列表时,问题就出现了。随着数据量的增加,这段代码的运行速度会慢 4 倍!

有人建议我应该制作一个大型示例供人们查看我所做的。由于今天帮助论坛上的人不多,所以我现在将其发布在这里。

import numpy  as np
import timeit

mylist=[]
for i in range (0,700):
    mylist.append(i)


myarray = np.empty((600, 600))
for x in range (0,600):
    for y in range (0,600):
        p=y+(x*0.25)
        myarray[y,x]=p

myarray=np.asarray(myarray)


# object here is to produce an array of 600 x 600 with True/False values depending 
# on whether elements in myarray are in mylist.
# The question is - what ia thw fastest way to do so? Note that all array values and
# mylist values are floats. There must be an exact match. One 
# can't use isclose because it is slower 
    
    
# Example 1 - using isin (loop of 10000 used for timing illustration)

starttime = timeit.default_timer()

for i in range (0,10):
 s1=np.isin(myarray,mylist)

print (s1[0][0:10])
print (s1[1][0:10])
print (s1[2][0:10])

print("The time difference is :", timeit.default_timer() - starttime)
   
# Example 2- using list comprehension and conversion of mylist to a set (it runs way 
# slower without set conversion)

def quickisin(array,mylist):

    mylist=set(mylist)
    
    p=[]
    t=len(array)
    
    for j in range (0,t):
        h=array[j]
        s1 = [item in mylist for item in h]
        p.append(s1)
    
    q=np.asarray(p)
     
    return q    

starttime = timeit.default_timer()

for i in range (0,10):
    s1=quickisin(myarray,mylist)

 
print (s1[0][0:10])
print (s1[1][0:10])
print (s1[2][0:10])

print("The time difference is :", timeit.default_timer() - starttime)

如您所见,代码的第一部分设置了示例变量。我使用 myarray 和 mylist 让人们更容易理解。 myarray 是 600x 600 数组,mylist 是大小为 700 的列表,所有浮点数。

预期的输出应该是一个与 myarray 大小相同但具有 True 和 False 值的 numpy 数组。每第 4 项为 True。

运行时产生的输出如下。

runfile('C:/A/untitled7.py', wdir='C:/A')
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
The time difference is : 0.5151480000000674
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
The time difference is : 2.0399810999999772

我的问题,如果你选择接受它,你的挑战是使用列表推导来使 quickisin 函数比使用 numpy 的 isin 更快。最快的列表理解解决方案的奖品是吹牛。

请注意,数组中的浮点数与列表的匹配必须准确,因此排除了使用 isclose 的可能性。

谢谢你

【问题讨论】:

  • 您可以用这样的列表理解替换您的 for 循环:p = [[item in mylist for item in h] for h in array] 但恐怕您可以从中获得很多。在我看来,您的代码中没有太多可以优化的东西,而且列表推导的使用在这里对您没有帮助。

标签: python list performance list-comprehension isin


【解决方案1】:

[更新]:在编写代码的过程中,我在测试myarray的生成中犯了一个错误(暂时减小了大小),忘记重置一些值。现在已修复。我的变体现在显示出不那么令人印象深刻的结果,但速度更快。

我同意 qouify 的观点,即列表推导无济于事。因此,我展示了另一种 numpy 解决方案,它比原始解决方案更快,但可能需要更多内存。

基本思路是对mylist进行排序,使用二等分np.searchsorted找到小于或等于的最接近的值,最后检查是否真的相等。

我已将其附加为quickisin2 函数:

import numpy  as np
import timeit

mylist=[]
for i in range (0,700):
    mylist.append(i)


myarray = np.empty((600, 600))
for x in range (0,600):
    for y in range (0,600):
        p=y+(x*0.25)
        myarray[y,x]=p

myarray=np.asarray(myarray)


# object here is to produce an array of 600 x 600 with True/False values depending 
# on whether elements in myarray are in mylist.
# The question is - what ia thw fastest way to do so? Note that all array values and
# mylist values are floats. There must be an exact match. One 
# can't use isclose because it is slower 
    
    
# Example 1 - using isin (loop of 10000 used for timing illustration)

starttime = timeit.default_timer()

for i in range (0,10):
 s1=np.isin(myarray,mylist)

print (s1[0][0:10])
print (s1[1][0:10])
print (s1[2][0:10])

print("The time difference is :", timeit.default_timer() - starttime)
   
# Example 2- using list comprehension and conversion of mylist to a set (it runs way 
# slower without set conversion)

def quickisin(array,mylist):

    mylist=set(mylist)
    
    p=[]
    t=len(array)
    
    for j in range (0,t):
        h=array[j]
        s1 = [item in mylist for item in h]
        p.append(s1)
    
    q=np.asarray(p)
     
    return q


def quickisin2(array,mylist):

    mylist=np.sort(mylist)
    shape = myarray.shape
    myarrayflat = np.reshape(myarray, -1)
    foundindices = np.searchsorted(mylist, myarrayflat)
    foundindices[foundindices >= mylist.shape[0]] = 0
    
    foundarray = mylist[foundindices]
    mask = myarrayflat == foundarray

    return np.reshape(mask, shape)



starttime = timeit.default_timer()

for i in range (0,10):
    s1=quickisin(myarray,mylist)

 
print (s1[0][0:10])
print (s1[1][0:10])
print (s1[2][0:10])

print("The time difference is :", timeit.default_timer() - starttime)




starttime = timeit.default_timer()

for i in range (0,10):
    s1=quickisin2(myarray,mylist)

 
print (s1[0][0:10])
print (s1[1][0:10])
print (s1[2][0:10])

print("The time difference is :", timeit.default_timer() - starttime)
print("The time difference is :", timeit.default_timer() - starttime)

在我的机器上使用 Python 3.7 64bit 我得到了(最后一个是新方法):

[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
The time difference is : 0.26915568
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
The time difference is : 1.052180994
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
[ True False False False  True False False False  True False]
The time difference is : 0.1133786440000002

【讨论】:

  • 谢谢。这对我来说将那段代码的处理时间减半,这将为我节省大量时间。 cuda 能否以某种方式使其更快?
猜你喜欢
  • 1970-01-01
  • 2021-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多