python - 用列表理解解决方案替换 numpy isin
问题描述
一段时间以来,我一直试图让我的彗星程序的慢速部分运行得更快。我有一行如下
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 的可能性。
感谢您
解决方案
[更新]:在编写代码的过程中,我在测试的生成中犯了一个错误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
推荐阅读
- php - 当我们重定向该页面并编写 session_start(); 时,我的 PHP 会话变量在另一个页面中不起作用 功能
- django - django vs jsp 用于生产规模应用程序
- c# - 在 C# razor 代码中每 4 或 5 列创建一个新行
- sql - 在查询中使用案例
- mysql - "select cast(UUID() as VARBINARY(100))" MySQL 查询错误
- php - 如何在PHP中对作为结果获得的多维数组进行排序
- php - 面临来自 AWS S3 的图像加载问题
- r - 如何访问 tibble 列表以检查是否为“UTF-8”并运行 import R
- c# - 如何在控制器事件的会话变量中使用和存储数据
- javascript - react中点击div时需要找代码调用两个函数