更有效的循环方式?

2024-04-21

我有来自一个更大脚本的一小段代码。我发现当函数t_area被调用时,它负责大部分运行时间。我自己测试了这个函数,它并不慢,我相信它需要运行很多次,所以需要花费很多时间。这是调用该函数的代码:

tri_area = np.zeros((numx,numy),dtype=float)
for jj in range(0,numy-1):
    for ii in range(0,numx-1):
      xp = x[ii,jj]
      yp = y[ii,jj]
      zp = surface[ii,jj]
      ap = np.array((xp,yp,zp))

      xp = xp+dx
      zp = surface[ii+1,jj]
      bp = np.array((xp,yp,zp))

      yp = yp+dx
      zp = surface[ii+1,jj+1]
      dp = np.array((xp,yp,zp))

      xp = xp-dx
      zp = surface[ii,jj+1]
      cp = np.array((xp,yp,zp))

      tri_area[ii,jj] = t_area(ap,bp,cp,dp)

这里使用的数组的大小是216 x 217,值也是如此x and y。我对 python 编码很陌生,我过去使用过 MATLAB。所以我的问题是,有没有办法绕过这两个 for 循环,或者有没有一种更有效的方法来运行这段代码?寻求任何帮助来加快速度!谢谢!

EDIT:

感谢大家的帮助,这已经解决了很多困惑。我被问到循环中使用的功能区域,下面是代码:

def t_area(a,b,c,d):
ab=b-a
ac=c-a
tri_area_a = 0.5*linalg.norm(np.cross(ab,ac))

db=b-d
dc=c-d
tri_area_d = 0.5*linalg.norm(np.cross(db,dc))

ba=a-b
bd=d-b
tri_area_b = 0.5*linalg.norm(np.cross(ba,bd))

ca=a-c
cd=d-c
tri_area_c = 0.5*linalg.norm(np.cross(ca,cd))

av_area = (tri_area_a + tri_area_b + tri_area_c + tri_area_d)*0.5
return(av_area)

抱歉,令人困惑的符号,当时它是有道理的,现在回想起来我可能会改变它。谢谢!


在我们开始之前需要注意一下。range(0, numy-1),等于range(numy-1),生成从 0 到 numy-2 的数字,不包括 numy-1。那是因为你有从 0 到 numy-2 的 numy-1 值。虽然 MATLAB 具有基于 1 的索引,但 Python 具有基于 0 的索引,因此在转换中的索引时要小心一些。考虑到你有tri_area = np.zeros((numx, numy), dtype=float), tri_area[ii,jj]永远不会以您设置循环的方式访问最后一行或最后一列。因此,我怀疑正确的意图是写range(numy).

由于函数t_area()是可矢量化的,您可以完全消除循环。矢量化意味着 numpy 通过处理底层循环,同时对整个数组应用一些操作,这样它们会更快。

首先,我们将所有的aps 表示 (m, n, 3) 数组中的每个 (i, j) 元素,其中 (m, n) 是x。如果我们计算两个 (m, n, 3) 数组的叉积,则默认情况下该运算将应用于最后一个轴。这意味着np.cross(a, b)会做对于每个元素 (i, j) 取 3 个数字的叉积a[i,j] and b[i,j]。相似地,np.linalg.norm(a, axis=2)会做对于每个元素 (i, j) 计算 3 个数字的范数a[i,j]。这也将有效地将我们的数组大小减小到 (m, n)。不过这里要小心一点,因为我们需要明确声明我们希望在第二个轴上完成此操作。

请注意,在以下示例中,我的索引关系可能与您的不对应。完成这项工作的最低要求是surface多出一行和一列x and y.

import numpy as np

def _t_area(a, b, c):
    ab = b - a
    ac = c - a
    return 0.5 * np.linalg.norm(np.cross(ab, ac), axis=2)

def t_area(x, y, surface, dx):
    a = np.zeros((x.shape[0], y.shape[0], 3), dtype=float)
    b = np.zeros_like(a)
    c = np.zeros_like(a)
    d = np.zeros_like(a)

    a[...,0] = x
    a[...,1] = y
    a[...,2] = surface[:-1,:-1]

    b[...,0] = x + dx
    b[...,1] = y
    b[...,2] = surface[1:,:-1]

    c[...,0] = x
    c[...,1] = y + dx
    c[...,2] = surface[:-1,1:]

    d[...,0] = bp[...,0]
    d[...,1] = cp[...,1]
    d[...,2] = surface[1:,1:]

    # are you sure you didn't mean 0.25???
    return 0.5 * (_t_area(a, b, c) + _t_area(d, b, c) + _t_area(b, a, d) + _t_area(c, a, d))

nx, ny = 250, 250

dx = np.random.random()
x = np.random.random((nx, ny))
y = np.random.random((nx, ny))
surface = np.random.random((nx+1, ny+1))

tri_area = t_area(x, y, surface, dx)

x在此示例中支持索引 0-249,而surface 0-250. surface[:-1],简写为surface[0:-1],将返回从 0 开始到最后一行的所有行,但不包括它。-1具有相同的功能并且end在 MATLAB 中。所以,surface[:-1]将返回索引 0-249 的行。相似地,surface[1:]将返回索引 1-250 的行,这与您的效果相同surface[ii+1].


Note:我在知道这一点之前就写了这一部分t_area()可以完全矢量化。因此,虽然这里的内容对于这个答案来说已经过时了,但我将把它作为遗产保留下来,以展示如果函数不可矢量化,可以进行哪些优化。

您应该传递它,而不是为每个元素调用昂贵的函数x, y,, surface and dx并进行内部迭代。这意味着只需一次函数调用并且开销更少。

此外,您不应该为以下内容创建数组ap, bp, cp and dp每个循环,这又增加了开销。在循环外分配它们一次,然后更新它们的值。

最后一项更改应该是循环的顺序。 Numpy 数组默认是行优先(而 MATLAB 是列优先),所以ii作为外循环表现更好。您不会注意到您大小的数组的差异,但是嘿,为什么不呢?

总的来说,修改后的函数应该是这样的。

def t_area(x, y, surface, dx):
    # I assume numx == x.shape[0]. If not, pass it as an extra argument.
    tri_area = np.zeros(x.shape, dtype=float)

    ap = np.zeros((3,), dtype=float)
    bp = np.zeros_like(ap)
    cp = np.zeros_like(ap)
    dp = np.zeros_like(ap)

    for ii in range(x.shape[0]-1): # do you really want range(numx-1) or just range(numx)?
        for jj in range(x.shape[1]-1):
            xp = x[ii,jj]
            yp = y[ii,jj]
            zp = surface[ii,jj]
            ap[:] = (xp, yp, zp)

            # get `bp`, `cp` and `dp` in a similar manner and compute `tri_area[ii,jj]`
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

更有效的循环方式? 的相关文章

随机推荐

  • HTML 表单动作搜索,1 个文本框,2 个按钮,2 个可能的结果

    这些天我正在尝试做一个搜索表单 该表单发送到两个不同的页面 其中有两个不同的按钮和一个文本框 到目前为止我正在这样做
  • 如何在SceneKit中实现逼真的景深效果?

    我正在尝试渲染具有真实景深效果的帧 我已经尝试过景深属性camera节点 但它不会产生可用的结果 是否可以切换到景深效果的最大渲染质量 性能不是一个因素 我只需要渲染一帧 用户可以等待它 SceneKit 中逼真的景深效果 在SceneKi
  • 如何在 WordPress 短代码中使用 AJAX?

    我有一个代码来显示随机报价 有人编写了一个函数来实现这一切 但由于某种原因通过AJAX更新数据不起作用 当您按下 新报价 按钮时 什么也没有发生 也许有人知道为什么 以下代码中需要修复什么 以便当您单击 新报价 时加载新报价 The PHP
  • 如何实施IDEA?

    我必须制作一个可以使用 Java 或 C 中的 IDEA 国际数据加密算法 加密和解密文本文件的应用程序 我知道Java中有一个内置的JCE Java加密扩展 但是我该如何进一步进行 有人能给我一些建议吗 由于某种原因无法发表评论 所以我将
  • 将先前的提交分解为多个提交

    如果不创建分支并在新分支上做一堆时髦的工作 是否可以在将单个提交提交到本地存储库后将其分解为几个不同的提交 git rebase i http git scm com book en v2 Git Tools Rewriting Histo
  • 如何在 EF 4.1 RC 中的 DbContext 级别关闭更改跟踪?

    我遇到了一个似乎很常见的问题 我正在更新数据库中的值 但 EF 正在使用对象的原始内存副本 并且这些更改的值不会反映在显示的数据中 我明白这是为什么 但我无法找到解决方法 最常见的解决方案似乎是设置MergeOptions NoTracki
  • OpenCV SURF功能未实现

    当我尝试运行示例时find obj cpp或任何 OpenCV SURF 程序 在执行代码时 我在命令提示符中收到以下错误 该项目构建时没有错误和警告 我使用的是 VS2011 beta OpenCV 2 4 和 windows7 错误信息
  • 附加搜索词时如何重用 jquery-ui-autocomplete 缓存结果?

    我有以下 JS 方法将 jQuery UI 自动完成小部件绑定到搜索文本框 一切工作正常 包括缓存 但在附加搜索词时我进行了不必要的服务器调用 因为我不重用刚刚检索的结果 例如 搜索 ab 会从服务器获取一些结果 在搜索框中的 ab 后面键
  • 从网络下载已使用 wavesurfer.js 修改的音频

    我使用wavesurfer js 创建了一个多轨网络播放器 它可以调整不同轨道的级别和平移 我想要做的是将具有新级别的混合曲目导出并将平移作为单个 wav 文件 我对此做了一些研究 很多人都指出https github com mattdi
  • 如何使用 Oracle 清理死连接?

    现在 我正在针对 Oracle 数据库开发一些新应用程序 有时它们会崩溃或无法正确结束 等等 无论如何 问题是它们有时似乎保持连接打开 我需要在它们之后进行清理 我的问题是 是否有一种方法可以从数据库端确定死连接并清理它们 这是一个页面 涉
  • C# 3.5 ASP.net 文件 IO 问题,网络共享上的文件出现 UnauthorizedAccessException

    每次我尝试访问时都会收到 UnauthorizedAccessException 只是read 网络共享上的文件 服务器 文件夹1 文件夹2 文件 pdf 我正在模拟对上述文件夹具有读写访问权限的域 aspnet 用户 该文件不是只读的 我
  • TextInputLayout.passwordVisibilityToggleRequested 上的 NullPointerException

    我在 Firebase 崩溃报告中收到有关以下内容的错误Password toggle button在某些真实设备中处于发布模式的应用程序上 问题是堆栈跟踪错误的全部内容android support design您将在从 Firebase
  • livereload 不提供地址选择

    更新node js后 我发现了这个问题 当我运行 ionic cordova run android livereload 时 它在本地主机中运行 我该如何解决这个问题 请帮我 离子信息 Ionic CLI 5 2 1 Ionic Fram
  • 如何有条件地实例化不同的子类?

    例如 在main函数中 我想获取用户的输入 根据输入 我将创建一个Rectangle or a Circle 它们是子类Object 如果没有输入 或未知 那么我将只创建一个通用对象 class Object public Object v
  • Eclipse 指标插件建议[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个工具来为我提供一些代码指标 LOC 总数 LOC 类 外部引用 类的数量等 有谁知道一个
  • 哪个 XML 解析器可以处理不完整的 XML 文件?

    我正在尝试使用 SAX 解析器解析 XML 但不断出现XML document structures must start and end within the same entity 这是预料之中的 因为我从其他来源获得的 XML 文档不
  • 尝试上传到 aws s3 存储桶时收到 400 错误请求

    我在服务器上签署 URL 并将其发送回客户端 效果很好 这就是该函数的样子 const aws require aws sdk config require config crypto require crypto module expor
  • 安卓。谷歌 API 翻译

    我在集成 Google API Translate 时遇到一些问题 添加到 gradle 配置此依赖项 compile com google apis google api services translate v2 rev41 1 20
  • 使用 Google Oauth2 客户端访问 API 时 Rails 3.2.3 中出现 SSL 错误

    我对 OAuth2 相当陌生 我正在尝试使用 Omniauth 和 Google API 客户端通过 Google API 访问用户的 Blogger 帐户 我正在使用以下内容 轨道3 2 3 红宝石 1 9 3 oauth2 0 8 0
  • 更有效的循环方式?

    我有来自一个更大脚本的一小段代码 我发现当函数t area被调用时 它负责大部分运行时间 我自己测试了这个函数 它并不慢 我相信它需要运行很多次 所以需要花费很多时间 这是调用该函数的代码 tri area np zeros numx nu