4

例如,我有以下数组:

x = [0, 1, 2, 3, 4.5, 5]
y = [2, 8, 3, 7,   8, 1]

我希望能够做到以下几点x

>>> what_is_y_when_x_is(2)
(2, 3)
>>> what_is_y_when_x_is(3.1) # Perhaps set rules to round to nearest (or up or down)
(3, 7)

另一方面,当给定时y

>>> what_is_x_when_y_is(2)
(0, 2)
>>> what_is_x_when_y_is(max(y))
([1, 4.5], 8)

这个问题的情况

我可以绘制yx使用封闭分析函数的对比,只需调用foo_function(x). 但是,我正在运行其数据图没有封闭解析解的数值模拟。

尝试的解决方案

我以前解决过类似的问题,并大致以这种方式处理它们:

what_is_y_when_x_is(some_x)

  1. 在数组x中搜索some_x
  2. 获取它的索引,i.
  3. 拿起y[i]

问题

有一个更好的方法吗?也许是内置numpy函数或更好的算法?

4

6 回答 6

3

您应该查看 numpy.searchsorted 和 numpy.interp。这两个看起来他们都可以做到这一点。这是一个例子:

import numpy as np
x = np.array([0, 1, 2, 3, 4.5, 5])
y = np.array([2, 8, 3, 7,   8, 1])

# y should be sorted for both of these methods
order = y.argsort()
y = y[order]
x = x[order]

def what_is_x_when_y_is(input, x, y):
    return x[y.searchsorted(input, 'left')]

def interp_x_from_y(input, x, y):
    return np.interp(input, y, x)

print what_is_x_when_y_is(7, x, y)
# 3
print interp_x_from_y(1.5, x, y)
# 2.5
于 2012-07-13T22:23:08.880 回答
1

您可以为此使用bisect模块。这是纯 python - 这里没有 numpy:

>>> x = [0, 1, 2, 3, 4.5, 5]
>>> y = [2, 8, 3, 7,   8, 1]
>>> x_lookup = sorted(zip(x, y))
>>> y_lookup = sorted(map(tuple, map(reversed, zip(x, y))))
>>> 
>>> import bisect
>>> def pair_from_x(x):
...    return x_lookup[min(bisect.bisect_left(x_lookup, (x,)), len(x_lookup)-1)]
... 
>>> def pair_from_y(y):
...    return tuple(reversed(y_lookup[min(bisect.bisect_left(y_lookup, (y,)), len(y_lookup)-1)]))
... 

以及一些使用它的例子:

>>> pair_from_x(0)
(0, 2)
>>> pair_from_x(-2)
(0, 2)
>>> pair_from_x(2)
(2, 3)
>>> pair_from_x(3)
(3, 7)
>>> pair_from_x(7)
(5, 1)
>>> 
>>> pair_from_y(0)
(5, 1)
>>> pair_from_y(1)
(5, 1)
>>> pair_from_y(3)
(2, 3)
>>> pair_from_y(4)
(3, 7)
>>> pair_from_y(8)
(1, 8)
于 2012-07-13T10:58:22.803 回答
0

就我而言,您描述的方式是一个好方法。我不确定您是否是,但我认为您可以在数组上使用 .index(...) 方法:

>>> li
['I', 'hope', 'this', 'answer', 'helps', 'you']
>>> li.index("hope")
1

除此之外,您可能需要考虑一个具有 x 和 ay 的数组操作“Points”,尽管我不确定这当然是否可行。这样您就不必保持两个数组同步(相同数量的元素)。

于 2012-07-13T09:38:32.230 回答
0

我认为您的管道没有任何问题。您可以基于numpy.where编写一个代码片段来有效地实现它。请注意,您必须首先将列表作为 numpy 数组传递(这可以包含在函数中)。

下面是一个完成这项工作的函数的示例,带有一个对目标进行舍入的选项(我已经包含了一个which array参数,所以一切都可以在一个函数中完成,无论你想在 x 或 y 中搜索什么)。请注意,其中一个输出将是一个 numpy 数组,因此请对其进行修改以将其转换为您想要的任何内容(列表、元组等)。

import numpy as np

def pick(x_array, y_array, target, which_array='x', round=True):
    # ensure that x and y are numpy arrays
    x_array, y_array = np.array(x_array), np.array(y_array) 

    # optional: round to the nearest. True by default
    if round==True:
        target = np.round(target) 

    if which_array == 'x': # look for the target in x_array
        return target, y_array[np.where(x_array == target)[0]]
    if which_array == 'y': # look for the target in y_array
        return x_array[np.where(y_array == target)[0]], target

您的示例给出的结果:

# >>> what_is_y_when_x_is(2)
pick(x, y, 2, 'x')
(2, array([3]))

# >>> what_is_y_when_x_is(3.1)
pick(x, y, 3.1, 'x')
3.0, array([7]))

# >>> what_is_y_when_x_is(2)
pick(x, y, 2, 'y')
(array([ 0.]), 2)

# >>> what_is_x_when_y_is(max(y))
pick(x, y, max(y), 'y')
(array([ 1. ,  4.5]), 8)
于 2012-07-13T15:53:16.343 回答
0

这对我有用:

def what_is_y_when_x_is(value, x, y, tolerance=1e-3):
    return [(xi, yi) for (xi, yi) in zip(x, y) if abs(xi - value) <= tolerance]

请注意,上面的代码不是比较相等性,而是执行“足够接近”的相等性测试。默认容差设置为 0.001(您可以使用任何其他值)。以下是一些使用示例:

>>> x = [0, 1, 2, 3, 4.5, 5]
>>> y = [2, 8, 3, 7,   8, 1]
>>> what_is_y_when_x_is(0, x, y)
[(0, 2)]
>>> what_is_y_when_x_is(1, x, y, tolerance=.1)
[(1, 8)]
>>> what_is_y_when_x_is(2, x, y, tolerance=1)
[(1, 8), (2, 3), (3, 7)]
>>> what_is_y_when_x_is(4, x, y, tolerance=.5)
[(4.5, 8)]
于 2016-04-27T20:32:32.300 回答
0

这里是@Bi Rico提供的修改版代码:

import numpy as np
x = np.array([0, 1, 2, 3, 4.5, 5])
y = np.array([2, 8, 3, 7,   8, 1])

# y should be sorted for both of these methods
order = np.argsort(y)
y = y[order]
x = x[order]

def what_is_x_when_y_is(input, x, y):
    return x[y.searchsorted(input, 'left')]

print(what_is_x_when_y_is(7, x, y))
# 3
于 2016-04-27T03:55:26.187 回答