是否可以矢量化 scipy.optimize.fminbound?

2024-04-26

我有一些按时间参数化的轨迹数据点,我想知道每个点到拟合它们的曲线的最短距离。似乎有几种方法可以解决这个问题(例如here https://kitchingroup.cheme.cmu.edu/blog/2013/02/14/Find-the-minimum-distance-from-a-point-to-a-curve/ or here https://stackoverflow.com/a/19869154/5472354),但我选择了scipy.optimize.fminbound https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fminbound.html?highlight=scipy%20optimize%20fminbound#scipy.optimize.fminbound,如提议的here https://stackoverflow.com/a/19102112/5472354(因为这似乎是最巧妙的方法,而且因为我实际上让它发挥了作用):

import numpy as np
import pandas as pd
from scipy.optimize import fminbound


data = np.array(
    [
        (212.82275865, 1650.40828168, 0., 0),
        (214.22056952, 1649.99898924, 10.38, 0),
        (212.86786868, 1644.25228805, 116.288, 0),
        (212.78680031, 1643.87461108, 122.884, 0),
        (212.57489485, 1642.01124032, 156.313, 0),
        (212.53483954, 1641.61858242, 162.618, 0),
        (212.43922274, 1639.58782771, 196.314, 0),
        (212.53726315, 1639.13842423, 202.619, 0),
        (212.2888428, 1637.24641296, 236.306, 0),
        (212.2722447, 1636.92307229, 242.606, 0),
        (212.15559302, 1635.0529813, 276.309, 0),
        (212.17535631, 1634.60618711, 282.651, 0),
        (212.02545613, 1632.72139574, 316.335, 0),
        (211.99988779, 1632.32053329, 322.634, 0),
        (211.33419846, 1631.07592039, 356.334, 0),
        (211.58972239, 1630.21971902, 362.633, 0),
        (211.70332122, 1628.2088542, 396.316, 0),
        (211.74610735, 1627.67591368, 402.617, 0),
        (211.88819518, 1625.67310022, 436.367, 0),
        (211.90709414, 1625.39410321, 442.673, 0),
        (212.00090348, 1623.42655008, 476.332, 0),
        (211.9249017, 1622.94540583, 482.63, 0),
        (212.34321938, 1616.32949197, 597.329, 0),
        (213.09638942, 1615.2869643, 610.4, 0),
        (219.41313491, 1580.22234313, 1197.332, 0),
        (220.38660128, 1579.20043302, 1210.37, 0),
        (236.35472669, 1542.30863041, 1798.267, 0),
        (237.41755384, 1541.41679119, 1810.383, 0),
        (264.08373622, 1502.66620597, 2398.244, 0),
        (265.65655239, 1501.64308908, 2410.443, 0),
        (304.66999824, 1460.94068336, 2997.263, 0),
        (306.22550945, 1459.75817211, 3010.38, 0),
        (358.88879764, 1416.472238, 3598.213, 0),
        (361.14046402, 1415.40942931, 3610.525, 0),
        (429.96379858, 1369.7972467, 4198.282, 0),
        (432.06565776, 1368.22265539, 4210.505, 0),
        (519.30493383, 1319.01141844, 4798.277, 0),
        (522.12134083, 1317.68234967, 4810.4, 0),
        (630.00294242, 1265.05368942, 5398.236, 0),
        (633.67624272, 1263.63633508, 5410.431, 0),
        (766.29767476, 1206.91262814, 5997.266, 0),
        (770.78300649, 1205.48393374, 6010.489, 0),
        (932.92308019, 1145.87780431, 6598.279, 0),
        (937.54373403, 1141.55438694, 6609.525, 0),
    ], dtype=[
        ('x', 'f8'), ('y', 'f8'), ('t', 'f8'), ('dmin', 'f8'),
    ]
)

# fyi my data comes as a structured array; unfortunately, simply passing
# data[['x', 'y']] to np.polyfit does not work. using
# pd.DataFrame(data[['x', y']]).values seems to be the easiest solution:
# https://stackoverflow.com/a/26175750/5472354
coeffs = np.polyfit(
    data['t'], pd.DataFrame(data[['x', 'y']]).values, 3
)


def curve(t):
    # this can probably also be done in one statement, but I don't know how
    x = np.polyval(coeffs[:, 0], t)
    y = np.polyval(coeffs[:, 1], t)

    return x, y


def f(t, p):
    x, y = curve(t)
    return np.hypot(x - p['x'], y - p['y'])


# instead of this:
for point in data:
    tmin = fminbound(f, -50, 6659.525, args=(point, ))
    point['dmin'] = f(tmin, point)


# do something like this:
# tmin = fminbound(f, -50, 6659.525, args=(data, ))
# data['dmin'] = f(tmin, data)

但正如你所看到的,我使用for-循环来计算每个数据点的最短距离,这会显着减慢我的程序速度,因为这会执行数千次。因此我想向量化操作/提高性能,但还没有找到方法。有与此相关的帖子(例如here https://stackoverflow.com/q/59371930/5472354 or here https://stackoverflow.com/q/10828477/5472354),但我不知道建议的解决方案如何适用于我的情况。


不,不可能矢量化fminbound因为它期望单变量的标量函数。但是,您仍然可以通过重新表述底层数学优化问题来向量化循环:

The N标量优化问题

min f_1(t) s.t. t_l <= t <= t_u
min f_2(t) s.t. t_l <= t <= t_u
.
.
.
min f_N(t) s.t. t_l <= t <= t_u

对于标量函数f_i等价于一个优化问题 在N变量:

min f_1(t_1)**2 + ... + f_N(t_N)**2  s.t. t_l <= t_i <= t_u for all i = 1, .., N

可以通过以下方式解决scipy.optimize.minimize https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html#scipy.optimize.minimize。根据您的整个算法,您可以使用这种方法来进一步消除更多循环,即您只解决一个大规模优化问题,而不是数千个标量优化问题。

清理代码后,可以按如下方式完成:

import numpy as np
from scipy.optimize import minimize

data = np.array([
    (212.82275865, 1650.40828168, 0., 0),
    (214.22056952, 1649.99898924, 10.38, 0),
    (212.86786868, 1644.25228805, 116.288, 0),
    (212.78680031, 1643.87461108, 122.884, 0),
    (212.57489485, 1642.01124032, 156.313, 0),
    (212.53483954, 1641.61858242, 162.618, 0),
    (212.43922274, 1639.58782771, 196.314, 0),
    (212.53726315, 1639.13842423, 202.619, 0),
    (212.2888428, 1637.24641296, 236.306, 0),
    (212.2722447, 1636.92307229, 242.606, 0),
    (212.15559302, 1635.0529813, 276.309, 0),
    (212.17535631, 1634.60618711, 282.651, 0),
    (212.02545613, 1632.72139574, 316.335, 0),
    (211.99988779, 1632.32053329, 322.634, 0),
    (211.33419846, 1631.07592039, 356.334, 0),
    (211.58972239, 1630.21971902, 362.633, 0),
    (211.70332122, 1628.2088542, 396.316, 0),
    (211.74610735, 1627.67591368, 402.617, 0),
    (211.88819518, 1625.67310022, 436.367, 0),
    (211.90709414, 1625.39410321, 442.673, 0),
    (212.00090348, 1623.42655008, 476.332, 0),
    (211.9249017, 1622.94540583, 482.63, 0),
    (212.34321938, 1616.32949197, 597.329, 0),
    (213.09638942, 1615.2869643, 610.4, 0),
    (219.41313491, 1580.22234313, 1197.332, 0),
    (220.38660128, 1579.20043302, 1210.37, 0),
    (236.35472669, 1542.30863041, 1798.267, 0),
    (237.41755384, 1541.41679119, 1810.383, 0),
    (264.08373622, 1502.66620597, 2398.244, 0),
    (265.65655239, 1501.64308908, 2410.443, 0),
    (304.66999824, 1460.94068336, 2997.263, 0),
    (306.22550945, 1459.75817211, 3010.38, 0),
    (358.88879764, 1416.472238, 3598.213, 0),
    (361.14046402, 1415.40942931, 3610.525, 0),
    (429.96379858, 1369.7972467, 4198.282, 0),
    (432.06565776, 1368.22265539, 4210.505, 0),
    (519.30493383, 1319.01141844, 4798.277, 0),
    (522.12134083, 1317.68234967, 4810.4, 0),
    (630.00294242, 1265.05368942, 5398.236, 0),
    (633.67624272, 1263.63633508, 5410.431, 0),
    (766.29767476, 1206.91262814, 5997.266, 0),
    (770.78300649, 1205.48393374, 6010.489, 0),
    (932.92308019, 1145.87780431, 6598.279, 0),
    (937.54373403, 1141.55438694, 6609.525, 0)])

# the coefficients
coeffs = np.polyfit(data[:, 2], data[:, 0:2], 3)

# the points
points = data[:, :2]

# vectorized version of your objective function
# i.e. evaluates f_1, ..., f_N
def f(t, points):
    poly_x = np.polyval(coeffs[:, 0], t)
    poly_y = np.polyval(coeffs[:, 1], t)
    return np.hypot(poly_x - points[:, 0], poly_y - points[:, 1])

# the scalar objective function we want to minimize
def obj_vec(t, points):
    vals = f(t, points)
    return np.sum(vals**2)

# variable bounds
bnds = [(-50, 6659.525)]*len(points)

# solve the optimization problem
res = minimize(lambda t: obj_vec(t, points), x0=np.zeros(len(points)), bounds=bnds)
dmins = f(res.x, points)

为了进一步加速优化,强烈建议将目标函数的精确梯度传递给minimize。目前,梯度是通过有限差分来近似的,速度相当慢:

In [7]: %timeit res = minimize(lambda t: obj_vec(t, points), x0=np.zeros(len(points)), bounds=bnds)
91.5 ms ± 868 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Since the gradient can easily be computed by the chain rule, I'll leave it as an exercise for the reader :). By the chain rule, the gradient reads as

def grad(t, points):
    poly_x = np.polyval(coeffs[:, 0], t)
    poly_y = np.polyval(coeffs[:, 1], t)
    poly_x_deriv = np.polyval(np.polyder(coeffs[:, 0], m=1), t)
    poly_y_deriv = np.polyval(np.polyder(coeffs[:, 1], m=1), t)
    return 2*poly_x_deriv*(poly_x - points[:, 0]) + 2*(poly_y_deriv)*(poly_y - points[:, 1])

并将其传递给minimize显着减少运行时间:

In [9]: %timeit res = minimize(lambda t: obj_vec(t, points), jac=lambda t: grad(t, points), x0=np.zeros(len(points)),
     ...: bounds=bnds)
6.13 ms ± 63.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

最后,正如您在评论中已经指出的那样,设置另一个起点也可能会导致迭代次数减少。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以矢量化 scipy.optimize.fminbound? 的相关文章

  • 多处理与 gevent

    目前我正在使用带有发布 订阅模式的 Zeromq 我有一个要发布的工作人员和许多 8 个订阅者 所有人都会订阅 相同的模式 现在我尝试使用多处理来生成订阅者 它可以工作 我错过了一些消息 我使用多重处理的原因是在每条消息到达时对其进行处理
  • 保存散点图动画

    我一直在尝试使用 matplotlib 保存动画散点图 并且我希望它不需要完全不同的代码来查看动画图形和保存副本 该图完美显示了保存完成后的所有数据点 这段代码是修改后的版本Giggi s https stackoverflow com a
  • 将逻辑回归从 R 迁移到 rpy2

    我正在尝试使用 ryp2 进行逻辑回归 我设法执行它 但不知道如何从结果中提取系数和 p 值 我不想在屏幕上打印这些值 而是创建一个函数来独立使用它们 import rpy2 robjects as ro mydata ro r data
  • Spark 中的广播 Annoy 对象(对于最近邻居)?

    由于 Spark 的 mllib 没有最近邻居功能 我正在尝试使用Annoy https github com spotify annoy为近似最近邻 我尝试广播 Annoy 对象并将其传递给工人 然而 它并没有按预期运行 下面是可重复性的
  • 嵌套列表递归python的序列

    给定一些数字 n 我想生成一个大小为 n 的列表 其中以下示例显示列表中的第 n 个元素应该如何 对于 n 0 返回 对于 n 1 返回 对于 n 2 返回 对于 n 3 返回 基本上 它采用先前的列表并将它们附加到新列表中 我尝试过以下方
  • 我知道 scipy curve_fit 可以做得更好

    我使用 python numpy scipy 来实现此算法 用于根据地形坡向和坡度对齐两个数字高程模型 DEM 用于量化冰川厚度变化的卫星高程数据集的联合配准和偏差校正 C Nuth 和 A K b doi 10 5194 tc 5 271
  • 当数据帧预排序时 pandas.groupby.nsmallest 会丢弃多索引

    我正在使用 pandas 0 22 0 python 版本 3 6 4 groupby与 nsmallest方法查找数据帧每组中的最小项目 这是一个示例数据框 gt gt gt import pandas as pd gt gt gt df
  • 将 Django 模型映射到外部 API

    上下文 我有一个外部 API 提供数据并允许发布新数据或修补现有数据 API 响应示例 response requests get http api band 4 print response json id 4 name The Beat
  • 在 python 中读取具有恶意字节 0xc0 的文件,导致 utf-8 和 ascii 出错

    尝试将制表符分隔的文件读入 pandas 数据帧 gt gt gt df pd read table fn na filter False error bad lines False 它会出错 如下所示 b Skipping line 58
  • Pandas 随机样本删除

    我知道DataFrame sample 但是我怎样才能做到这一点并从数据集中删除样本呢 注意 据我所知 这与替换采样无关 例如这里是精华我想要实现的目标 这实际上不起作用 len df 1000 df subset df sample 30
  • 如何获取 ndarray 的 x 和 y 维度 - Numpy / Python

    我想知道是否可以分别获取 ndarray 的 x 和 y 维度 我知道我可以使用ndarray shape获取表示维度的元组 但如何在 x 和 y 信息中分离它 先感谢您 您可以使用元组拆包 y x a shape
  • 在Python中获取目录基名的优雅方法?

    我有几个脚本将目录名称作为输入 并且我的程序在这些目录中创建文件 有时我想获取给程序的目录的基本名称 并用它在目录中创建各种文件 例如 directory name given by user via command line output
  • subprocess.Popen args 参数的最大长度是多少?

    我在用Popen http docs python org library subprocess html using the subprocess modulesubprocess 模块中的函数来执行命令行工具 subprocess Po
  • 将画布的鼠标坐标转换为地理坐标

    我正在尝试使用 Python Tkinter 创建包含意大利所有城市的地图Canvas 我在网上找到了一张意大利地图的图片 其中突出显示了一些城市 并将其插入到我的Canvas 之后 我使用一个函数来确定 2 个突出显示的城市的画布坐标 i
  • 如何防止模块被导入两次?

    在编写python模块时 有没有办法防止它被客户端代码导入两次 就像 c c 头文件一样 ifndef XXX define XXX endif 非常感谢 Python 模块不会被多次导入 仅运行两次 import 不会重新加载模块 如果你
  • 从纪元到相对日期的秒数

    我正在处理自纪元以来的日期 并且已经得到了 例如 date 6928727 56235 我想将其转换为另一种相对格式 以便我能够将其转换为与纪元相关的格式 使用 time gmtime date 它返回 year 1970 mon 3 da
  • 在 Django 查询中与父级一起获取子级数据

    我有两个模型产品和产品包 产品包有一个产品型号的外键 我如何访问包含产品包的所有产品的列表 class Product models Model title models CharField verbose name Product Tit
  • 如何在 Windows 上的 Python 2.7 上安装 Tensorflow?

    我尝试通过 pip 安装 TensorFlow pip install tensorflow 但是得到这个错误 找不到满足tensorflow要求的版本 来自版本 这个问题有解决办法吗 我还是想通过pip安装 如果您只因为 Keras 而需
  • 在 Pandas 中按索引分组

    如何使用 groupby by 索引 1 2 3 它们的顺序相同 并获得属于每个索引范围的列分数的总和 基本上我有这个 index score 1 2 2 2 3 2 1 3 2 3 3 3 我想要的是 index score sum 1
  • 如何使用 Python 从 Azure Functions 中的辅助线程重定向日志

    我正在使用 Azure 函数运行启动多个线程的 Python 脚本 出于性能原因 一切都按预期工作 但 Azure Functions 日志中仅显示来自 main 线程的信息日志 我在 main 中启动的 辅助 线程中使用的所有日志都不会出

随机推荐