我有以下优化问题,我可以通过"蛮力"但是我想知道是否有人已经实现了一个我可以用来更快更优雅的解算器。
我有两个不相交的整数列表。这些实际上是独一无二的所以我可以说这是两套。一个是关于s
元素的(S=90000
)短,另一个是关于l
元素的长(L=2.5M
)。我需要的是从l
提取长度恰好为l2
的子集S
,以便整体s
和l2
的元素之间的距离最小所有l
长度为S
的子集。 s
和l
元素之间的成对距离只是它们差异的绝对值。
因此,如果s
和l
不是不相交且l
是s
的超集,则生成的l2
将与{{1}完全相同}}
由于数组很长,通过测试s
的各种子集来进行暴力破解是不切实际的。
是否存在某种类型的现有优化库或其他可用于解决此问题的软件包?
顺便说一句,测量两组之间的距离可能有不同的方法,我并不关心它是哪一个,只要它为上述极端超集示例给出0。
答案 0 :(得分:1)
我知道你说这些是列表,但有没有理由不暂时将它们转换为numpy数组?这可以是直接的(如果您不知道如何进行转换):
s = np.array(s)
l = np.array(l)
从那里,您可以使用" searchsorted"功能。我的测试运行时间不到1.5秒。
from __future__ import division, print_function
import numpy as np
import datetime as dt
# build numpy array
s = np.random.rand(90000)
l = np.random.rand(2.5E6)
# sort
s.sort()
l.sort()
# searchsorted finds where values in array2 should be inserted in array1 to
# maintain the "sortedness" of a new list
# define index locations where "s" should be inserted in "l"
indices = np.searchsorted(l,s)
# build dummy list to store "s2"
# this is faster than repeatedly resizing an array
s2 = s*0
# using "indices" determine which adjacent value is the nearest match
# need to be careful here since we cannot look "below" the first index
# nor can we look "above" the last value
d1 = dt.datetime.now()
for r in np.arange(s.shape[0]):
ix = indices[r]
if indices[r]==0:
s2[ix] = l[0]
elif indices[r]==l.shape[0]:
s2[ix] = l[r-1]
else:
tmp = l[ix:ix+2]
s2[r] = tmp[ np.abs(s[r]-tmp)==np.min(np.abs(s[r]-tmp)) ]
print('Execution time: ',dt.datetime.now()-d1)
我已经进行了几次试验,看起来这样可行,但请自行确认。如果这不起作用,那么调整它就不会有太多的努力。
将for循环更改为:
for r in np.arange(s.shape[0]):
ix = indices[r]
if indices[r]==0:
s2[ix] = l[0]
l[0] = np.nan
elif indices[r]==l.shape[0]:
s2[ix] = l[r-1]
l[r-1] = np.nan
else:
width = 0
while width<min([10,r]) and np.isnan(l[ix-width:ix+2+width].mean()):
width += 1
tmp = l[ix-width:ix+2+width]
s2[r] = tmp[ np.abs(s[r]-tmp)==np.nanmin(np.abs(s[r]-tmp)) ][0]
l[l==s2[r]] = np.nan
这有两件事: 1.删除l中的最近邻居,以免在将来的迭代中考虑 2.它逐渐增加l内的搜索宽度,以确保找到最近邻居
同样,这可能需要调整才能拨入。
答案 1 :(得分:0)
距离函数可能很关键。如果将距离函数定义为集合s和l2中元素总和之间的绝对差值,则问题实际上是NP难度。基本上,您正在尝试查找集合l的子集,其总和接近于s中元素的总和。而且子集和问题(https://en.wikipedia.org/wiki/Subset_sum_problem)可以映射到这个;这意味着没有多项式时间算法来解决这个问题。但是,您也可以修改针对您的情况的子集和问题的伪多项式时间解决方案。