首页 > 编程问答 >如何极其快速地修改多维 numpy 数组的值?

如何极其快速地修改多维 numpy 数组的值?

时间:2024-07-27 08:17:01浏览次数:14  
标签:python numpy numpy-ndarray numpy-slicing

我正在开发一个项目,涉及 跟踪 (640, 640) 网格上的数千个点。 跟踪这些点时,我将它们的运动以向量线性数组的格式存储,解释每个点的变化位置采用以下格式:

v = [starting_x, starting_y, distance_x, distance_y]

我(为了项目的缘故)必须创建一个与上述网格 (640, 640) 大小相同的矢量场。然而,给我的数据量只涵盖了该网格的几个点。因此 我迭代整个网格,计算每个单独的点与数组中存储的所有向量之间的距离 然后我按距离找到最接近的向量索引,并将该像素的值替换为该向量的 [dx, dy] 值。

我最初使用矩阵乘法和 Hadamard 乘积来实现此目的,但 最近数据量突然增加从 ~300 增加到超过 2000,导致大量内存溢出 ,因为我正在处理的矩阵大小几乎达到 13GB。 (为了正确减去所有点的坐标,我必须生成一个大小为 640x640x2000x2 的数组,其中包含每个点的坐标。) 考虑到我的项目将来应该在更大的数据集上运行,我已将初始方法更改为具有三个嵌套循环的简单迭代(是的,我知道这听起来有多可怕)。这样,通过一些优化和预先计算,我将同一数据集的主动使用数据量从 13GB 限制到最大 2.5GB。

然而,处理时间从之前的约 10 秒猛增到约 100 分钟,我不会真正考虑升级。

因此, 我需要找到一种以更高的效率处理大量数据的方法。

[编辑]: 这是当前形状的函数:

def spread_vectors_by_least_distance(mainvectors: np.array):
    length = mainvectors.shape[0]   # this is the amount of vectors we're working with
    # Pre-calculating repetitive data:
    mvectors_help = np.zeros((length, 3), np.uint16)
    for z in range(length):
        y_, x_ = mainvectors[z, :2]
        mvectors_help[z] = (y_*y_ + x_*x_, 2*y_, 2*x_)

    width, height = 640, 640
    deltas = np.zeros((height, width, length), np.uint16)

    for y in range(height):
        ysqr = y*y
        for x in range(width):
            xsqr = x*x
            xsqr_ysqr = ysqr + xsqr

            delta_min = 999_999_999
            index = 0
            for z in range(length):
                xy_sqr, y_dbl, x_dbl = mvectors_help[z]
                # delta = (x-x_)^2 + (y-y_)^2, which simplifies to:
                delta = xy_sqr + xsqr_ysqr - y*y_dbl - x*x_dbl

                # We only need the smallest distance
                if delta_min > delta:
                    delta_min = delta
                    index = z

            # The point's value is the closest vector's value:
            deltas[y, x] = mainvectors[index, 2:]
    return deltas

我知道现在可以采取两 (2) 条路径来解决我的问题:

1。我可以找到一种通过 numpy 优化的方式迭代该数组的内置方法,执行大约 800_000_000 次代数运算和数组元素替换将花费合理的时间。 2。我可以使用 python-c 或 python-c++ 绑定

以更快的语言执行所有数据处理(根据我收集的数据,速度快十倍甚至一百倍),但这意味着要花费无数的时间学习Python的新模块(例如cython)并用我不太理解的语言调试代码。 因此,我向世界各地的所有Python大师寻求

寻找最简单的方法,但对我的问题来说是最有效的解决方案。 search of the simplest, yet most efficient solution to my problem.


可以通过使用 NumPy 的广播和向量化操作来显著提高代码速度,而不是使用循环。这就是一种方法:

import numpy as np

def spread_vectors_by_least_distance_optimized(mainvectors: np.array):
    length = mainvectors.shape[0]
    # 创建坐标网格
    grid_x, grid_y = np.meshgrid(np.arange(640), np.arange(640))
    # 将坐标重塑为 (640*640, 2) 数组
    grid_points = np.stack((grid_x.ravel(), grid_y.ravel()), axis=1)
    # 使用广播计算所有点和所有向量的距离
    distances = np.sum((grid_points[:, np.newaxis, :] - mainvectors[:, :2])**2, axis=2)
    # 找到每个网格点最近的向量的索引
    closest_indices = np.argmin(distances, axis=1)
    # 从 mainvectors 中获取最近向量的 dx, dy 值
    deltas = mainvectors[closest_indices, 2:][:]
    # 将结果重塑回 (640, 640, 2) 数组
    return deltas.reshape(640, 640, 2)

解释:

  1. 创建坐标网格: np.meshgrid 用于创建网格上所有点的坐标。
  2. 重塑坐标: 坐标被展平成一个 (640*640, 2) 的数组,以便进行广播。
  3. 计算距离: 利用广播,计算所有网格点与所有 mainvectors 之间的平方距离。
  4. 找到最近的索引: np.argmin 用于找到 distances 数组中沿轴 1(即对于每个网格点)的最小值的索引,该索引对应于最近的向量。
  5. 提取 dx, dy 值: 使用找到的索引从 mainvectors 中提取最近向量的 dx, dy 值。
  6. 重塑结果: 最后,将 deltas 数组重塑回所需的 (640, 640, 2) 形状。

这段代码利用了 NumPy 的向量化操作,消除了 Python 循环并显著提高了性能。这种方法应该可以快速处理 2000 个向量,并且内存效率也更高,因为它避免创建大型中间数组。

标签:python,numpy,numpy-ndarray,numpy-slicing
From: 78799631

相关文章

  • Python,pandas从字符串中解析数字和字符串
    在Python中,我想解析一个字符串并将数字部分(可能有也可能没有小数点)作为浮点数返回,并将后缀作为字符串返回。示例为:7.1英寸->7.1,英寸7.1”->7.1,“7英寸->7.0,英寸-10dB->-10.0,dB-10.2dB->-10.2,dB数字部分和后缀之间没有空格。另外,我想将其应......
  • 如何在 Python 中加载站点的所有资源,包括 AJAX 请求等?
    我知道如何使用Python请求网站并读取其文本。过去,我曾尝试使用像BeautifulSoup这样的库来发出对网站上链接的所有请求,但这并没有得到看起来不像完整URL的内容,例如AJAX请求和大多数对原始域(因为“http://example.com”将丢失,更重要的是,它不是<ahref='url'>......
  • 使用Python进行PDF旋转
    使用python旋转扫描的pdf后,它工作得很好,但将pdf发送给第三方后,第三方仍然将pdf检测为90度pdf有什么办法可以解决旋转和这个问题importPyPDF2withopen('input.pdf','rb')asfile:#CreateaPDFreaderobjectreader=PyPDF2.PdfReader(file)......
  • Python win32serviceutil QueryServiceStatus:返回值是什么意思?
    我正在学习使用pywin32,并尝试在64位Python3.6.4上使用win32serviceutil模块以下代码:importwin32serviceutilasserviceserviceStatus=service.QueryServiceStatus("WinDefend")print(serviceStatus)返回以下元组:(16,4,197,0,0,0,0)我对wind......
  • Python request-html 未下载 Chromium
    importrequestsfrombs4importBeautifulSoupfromrequests_htmlimportHTMLSessionurl="https://dmarket.com/ingame-items/item-list/csgo-skins?title=recoil%20case"sesion=HTMLSession()response=sesion.get(url)response.html.render()soup=B......
  • VS Code 不改变 python 环境
    我正在使用VS-Code和anaconda环境作为python解释器。我通过ctrl+shift+`选择准确的anaconda基础环境,它也反映在vscode的下侧面板中。但是,当我检查python版本时,它显示我系统的默认python环境3.7.9如果您看到下面的截图,anaconda环境是3.......
  • 使用 Python 打开保存为 Parquet 文件中元数据的 R data.table
    使用R,我创建了一个Parquet文件,其中包含一个data.table作为主要数据,另一个data.table作为元数据。library(data.table)library(arrow)dt=data.table(x=c(1,2,3),y=c("a","b","c"))dt2=data.table(a=22222,b=45555)attr(dt,&......
  • Python 需要 Windows 长路径
    我尝试运行此安装:pip3installmsgraph-sdk它给了我这个错误:它说我需要使用此链接启用Windows长路径:https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry#enable-long-paths-in-windows-10-versi......
  • Python griddata() 和 Matlab griddata():某些网格点的结果不同
    在将一些(相当大的物理)Matlab代码转换为Python时,我偶然发现了这种情况。当对相同的二维离散数据进行插值时,Python/Scipy的griddata()函数给出的结果与Matlab的对应函数不同。griddata()Matlab示例代码:Python示例代码:%Samplepoints(x,y):7x5=3......
  • Ebay Python SDK 仅在特定项目类别上返回错误
    我在一个项目中使用ebaySDK一段时间了。最近我尝试导入一些商品,例如手表、手机壳等...并且我使用了eBay自己通过eBay返回的英国商店页面上的类别ID他们的“get_category_suggestions”API端点,但eBay似乎有选择地决定拒绝某些项目并引发服务器错误!为了测试,我做了......