找到同样分区两个Numpy数组的值

时间:2014-03-12 14:29:17

标签: python numpy partitioning

我有两个长度相等的数组(x1x2),这些数组具有重叠的值范围。

我需要找到一个值q,以使l1-l2最小化,

l1 = x1[np.where(x1 > q)].shape[0]
l2 = x2[np.where(x2 < q)].shape[0]

我需要这个才能获得相当高的性能,因为数组可能很大。使用原生numpy例程的解决方案将是首选。

4 个答案:

答案 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])

如果l1q中的其中一项,我们可以计算x1

>>> l1_x1 = len(x1) - np.arange(len(x1)) - 1
>>> l1_x1
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])

l2q相同:

>>> l2_x1 = np.searchsorted(x1, x2)
>>> l2_x1
array([ 0,  1,  1,  3,  3,  6,  6, 10, 10, 10], dtype=int64)

l1位于l2时,您可以同样获取qx2的值:

>>> 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

enter image description here

@ 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

enter image description here

这里的解决方案为我们提供了[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))