当前位置: 首页 > news >正文

【Python性能优化实例】计算 numpy 数组首尾为 0 的数量

import numpy as np
import timeit
测试数据

开头有 30000 个 0 元素,中间有 100000 个非 0 元素,结尾有 70000 个为 0 元素的 numpy 数组。下面以计算数组末尾的零的数量为例。

array = np.array([0] * 30000 + [i for i in range(1, 1000001)] + [0] * 70000)
方法 1

使用 Python 的循环,从后向前遍历 numpy 数组并统计为 0 元素的个数,当遇到非 0 元素时,则跳出循环。

res1 = 0
for i in range(array.shape[0] - 1, -1, -1):
    if array[i] == 0:
        res1 += 1
    else:
        break
方法 2

先使用 numpy 的切片器倒序数组,然后使用 numpy 的 consum 的函数计算前缀和;此时除原数组末尾的 0 元素外的其他元素均已变为非 0 元素。于是,先使用 numpy 的 count_nonzero 方法统计满足元素值等于 0 的元素数量。

numpy 的 参考文档:https://numpy.org/doc/stable/reference/generated/numpy.cumsum.html

res2 = np.count_nonzero(np.cumsum(array[::-1]) == 0)
方法 3

在方法 2 的基础上,先直接统计非 0 元素数量,再使用元素总数减去非 0 元素数量得到 0 元素数量。

res3 = array.shape[0] - np.count_nonzero(np.cumsum(array[::-1]))
结果检查
assert res1 == res2 == res3
性能检查

方法 1 计算时间:1.6362712000000001

print(timeit.timeit(
    "res = 0\n"
    "for i in range(array.shape[0] - 1, -1, -1):\n"
    "    if array[i] == 0:\n"
    "        res += 1\n"
    "    else:\n"
    "        break",
    setup="import numpy as np\n"
          "array = np.array([0] * 30000 + [i for i in range(1, 1000001)] + [0] * 70000)",
    number=100
))

方法 2 计算时间:0.4067506000000001

因为使用了 numpy 函数替代了 Python 的原生循环,因此性能提升较多。

print(timeit.timeit(
    "np.count_nonzero(np.cumsum(array[::-1]) == 0)",
    setup="import numpy as np\n"
          "array = np.array([0] * 30000 + [i for i in range(1, 1000001)] + [0] * 70000)",
    number=100
))

方法 3 计算时间:0.33288949999999984

因为节省了一次计算数组中元素是否等于 0 的判断操作,因此性能有所提升。

print(timeit.timeit(
    "array.shape[0] - np.count_nonzero(np.cumsum(array[::-1]))",
    setup="import numpy as np\n"
          "array = np.array([0] * 30000 + [i for i in range(1, 1000001)] + [0] * 70000)",
    number=100
))
http://www.dtcms.com/a/169.html

相关文章:

  • C语言百日刷题第九天
  • 「避坑宝典」为大家分享笔者在22 年所遇到“匪夷所思”的 Bug 趣事
  • 什么是JUC
  • 图解LeetCode——775. 全局倒置与局部倒置(难度:中等)
  • apache 组件下载地址
  • 【JavaSE】继承那些事儿
  • 【数据结构】栈基本操作的实现(C语言)
  • MySQL纯代码复习
  • akshare复权算法-港股复权后数据代码分享
  • 通俗易懂话GC-C#的内存管理
  • 使用小程序制作一个电子木鱼,功德+1
  • Android Studio App开发之实现底部标签栏BottomNavigationView和自定义标签按钮实战(附源码 超详细必看)
  • Vue/Vuex (actions) 核心概念 使用方法、辅助函数 mapActions使用方法说明
  • Flink学习:Flink支持的数据类型
  • 【论文复现】——FEC: Fast Euclidean Clustering for Point Cloud Segmentation
  • 第十三届蓝桥杯C++B组省赛 I 题——李白打酒加强版 (AC)
  • 队列的简单实现
  • java毕业设计家庭理财记账系统(附源码、数据库)
  • 【ASM】字节码操作 工具类与常用类 asm-utils 与 asm-commons
  • 用Python把附近的足浴店都给采集了一遍,好兄弟:针不戳~
  • 计算机毕业设计之java+javaweb的医院门诊挂号系统
  • 【Linux】基本指令(一)
  • 刷题记录 -- 面试题
  • 信息学奥赛一本通:1308:【例1.5】高精除
  • 【Linux】关于进程的理解、状态、优先级和进程切换
  • 一文吃透JavaScript中的DOM知识及用法
  • 中断和异常理论详解,Linux操作系统原理与应用
  • 对象的比较(上)PriorityQueue中的底层源码解析
  • 【面试官让我十分钟实现一个链表?一个双向带头循环链表甩给面试官】
  • 以太网交换机自学习、转发帧的流程