在numpy中如何找到x或y,或者反过来给定y找到x?

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) 即可轻松实现。但是,我正在运行数值模拟,其数据绘图没有封闭解析解。

尝试的解决方案

我之前处理过类似的问题,并大致采用了以下方法:

当 x 是某个值时,y 是什么?

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

问题

有更好的方法吗?或者有内置的 numpy 函数或更好的算法可以使用吗?


我只能想到一种更有效的解决方案:对数组进行排序,然后使用线性插值来找到y(或x)的最可能索引,然后从那个初始猜测开始越来越远,直到到达目的地。 - user529758
你熟悉scipy.interpolate模块吗?对于你的使用情况,我认为该模块中的几个函数在实践中比仅四舍五入到最近的数更有用。 - DSM
6个回答

5
你应该看一下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

@Stryker 为什么?你对方法有问题吗 :) - Bi Rico
我对方法没有问题 :) 。只是我尝试了代码 order = y.argsort(),但它没有起作用。所以我不得不在ipython笔记本中将其更改为order = np.argsort(y)。 :) - Stryker
1
@Stryker 如果 y 是一个数组,那么 y.argsort() 应该可以工作,因为数组有一个 argsort 方法。如果 y 是其他类型的变量,比如列表,则可以使用 np.argsort(y) - Bi Rico

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)

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

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

0

就我所知,你所描述的方法是一个不错的方式。我不确定你是否已经这样做了,但我认为你可以在数组上使用.index(...)方法:

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

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


.index() 方法只返回找到的第一个匹配项的索引,这也引出了一个问题:“如果没有完全匹配的项,该怎么办?” - Kit
你是完全正确的,那么我会考虑“点”这个东西,只需迭代单个列表,检查所有x值,并将它们的y值添加到一个数组中。然后返回此数组。如果没有匹配的值,它将返回一个空数组,这是有意义的。对于检查y值也是一样的。(使用x数组和y数组也可以做同样的事情,但我认为使用“点”更清晰) - The Oddler

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接