我有两个长度相等的数组(x1
和x2
),这些数组具有重叠的值范围。
我需要找到一个值q
,以使l1-l2
最小化,
l1 = x1[np.where(x1 > q)].shape[0]
l2 = x2[np.where(x2 < q)].shape[0]
我需要这个才能获得相当高的性能,因为数组可能很大。使用原生numpy例程的解决方案将是首选。
答案 0 :(得分:2)
可能有更聪明的方法来查找值,但您可以按如下方式进行详尽搜索:
>>> x1 = np.random.rand(10)
>>> x2 = np.random.rand(10)
>>> x1.sort()
>>> x2.sort()
>>> x1
array([ 0.12568451, 0.30256769, 0.33478133, 0.41973331, 0.46493576,
0.52173197, 0.72289189, 0.72834444, 0.78662283, 0.78796277])
>>> x2
array([ 0.05513774, 0.21567893, 0.29953634, 0.37426842, 0.40000622,
0.54602497, 0.7225469 , 0.80116148, 0.82542633, 0.86736597])
如果l1
是q
中的其中一项,我们可以计算x1
:
>>> l1_x1 = len(x1) - np.arange(len(x1)) - 1
>>> l1_x1
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
l2
与q
相同:
>>> l2_x1 = np.searchsorted(x1, x2)
>>> l2_x1
array([ 0, 1, 1, 3, 3, 6, 6, 10, 10, 10], dtype=int64)
当l1
位于l2
时,您可以同样获取q
和x2
的值:
>>> l2_x2 = np.arange(len(x2))
>>> l2_x2
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> l1_x2 = len(x1) - np.searchsorted(x1, x2, side='right')
>>> l1_x2
array([10, 9, 9, 7, 7, 4, 4, 0, 0, 0], dtype=int64)
然后,您只需检查l1 - l2
的最小值:
>>> np.concatenate((l1_x1 - l2_x1, l1_x2 - l2_x2))
array([ 9, 7, 6, 3, 2, -2, -3, -8, -9, -10, 10, 8, 7,
4, 3, -1, -2, -7, -8, -9], dtype=int64)
>>> q_idx = np.argmin(np.abs(np.concatenate((l1_x1 - l2_x1, l1_x2 - l2_x2))))
>>> q = x1[q_idx] if q_idx < len(x1) else x2[q_idx - len(x1)]
>>> q
0.54602497466094291
>>> x1[x1 > q].shape[0]
4L
>>> x2[x2 < q].shape[0]
5L
答案 1 :(得分:2)
我想我可能已经找到了一种相当简单的方法。
x1 = (50 - 10) * np.random.random(10000) + 10
x2 = (75 - 25) * np.random.random(10000) + 25
x1.sort()
x2.sort()
x2 = x2[::-1] # reverse the array
# The overlap point should fall where the difference is smallest
diff = np.abs(x1 - x2)
# get the index of where the minimum occurs
loc = np.where(diff == np.min(diff))
q1 = x1[loc] # 38.79087351
q2 = x2[loc] # 38.79110941
M4rtini的解决方案产生q = 38.7867527
。
答案 2 :(得分:2)
这基本上是一个区间问题,因此您可能希望对Interval trees进行一些阅读,但是您不需要了解间隔树来解决此问题。
如果您认为每个(x1[i], x2[i])
都是一个区间,那么您需要查找值q
,它会将区间分成两组,尽可能均匀地忽略重叠的区间{{1} }}。让我们先来看看这个简单的案例:
q
@ xvtk的解决方案在这种情况下效果很好,并为我们提供了一系列[44,47]。由于没有区间与范围重叠,因此范围内的from numpy import array
x1 = array([19, 32, 47, 13, 56, 1, 87, 48])
x2 = array([44, 38, 50, 39, 85, 26, 92, 64])
x1sort = np.sort(x1)
x2sort = np.sort(x2)[::-1]
diff = abs(x2sort - x1sort)
mindiff = diff.argmin()
print mindiff, x2sort[mindiff], x1sort[mindiff]
# 4 44 47
的所有值都是等效的,并产生最佳结果。这是一个更棘手的例子:
q
这里的解决方案为我们提供了[59,71]的范围,但请注意,并非范围内的所有值都是等价的。绿线左侧的任何内容将分别在左侧和右侧产生3和4个区间,而绿线右侧的任何区域将在两侧产生3个区间。
我非常确定最佳解决方案可以保证在@ xvtk解决方案产生的范围内。可能有一条红线保证是最佳解决方案,尽管我不确定这一点。希望有所帮助。
答案 3 :(得分:1)
也许在scipy中使用一些优化函数来最小化差异。
像这样的例子
import numpy as np
from scipy.optimize import fmin
def findQ(q, *x):
x1, x2 = x
l1 = x1[np.where(x1 > q)].shape[0]
l2 = x2[np.where(x2 < q)].shape[0]
return abs(l1-l2)
x1 = (50 - 10) * np.random.random(10000) + 10
x2 = (75 - 25) * np.random.random(10000) + 25
q0 = (min(x2) + max(x1))/2.0
q = fmin(findQ, q0, (x1,x2))