【python】如何包装 numpy 的数组

一、说明

        Numpy的数组是强大的对象,通常用作更复杂的对象(如pandas或xarray)的基本数据结构。话虽如此,您当然也可以在自己的类中使用numpy的强大数组 - 为此,您基本上有2种方法:

  • 子类方法:创建从 Numpy.ndarray 继承的类
  • 容器方法:创建将数组作为属性的类

在本文中,我们将看到如何使用容器方法来包装 numpy 的数组来正确创建自己的自定义类。

二、 物理格式的项目

        让我们举一个示例项目:我们想创建一个简单的项目来处理物理单位和尺寸,创建长度或重量的数组,然后使用这些数组来计算平均身高或[身体质量指数](https://en.wikipedia.org/wiki/Body_mass_index)。我们希望依靠 numpy 来完成繁重的数值计算(如加法、减法、幂),但我们也希望能够处理像 numpy 数组这样的实例,比如 or .[1, 2, 3] meter [55 65 8] kilogramnp.sort(weights)np.min(heights)

        为此,我们将创建一个使用容器方法来包装 numpy 数组的新类。数值将存储为普通 numpy 数组,物理维度存储为字符串:

import numpy as np

class Physical():

    def __init__(self, value, unit=""):
        self.value = value # store the numerical value as a plain numpy array
        self.unit = unit

    def __repr__(self):
        return f"<Physical:({self.value}, {self.unit})"

    def __str__(self):
        return f"{self.value} {self.unit}"

weights = Physical(np.array([55.6, 45.7, 80.3]), "kilogram")
print(weights) # [55.6 45.7 80.3] kilogram

物理阵列的第一个实现

这将简单地打印:。同样,此字符串后面的数字列表是存储在 中的实际 numpy 数组。[55.6 45.7 80.3] kilogramself.value

现在这是毫无用处的:我们不能让这个对象与其他任何东西交互,所以我们添加了基本操作,如加法或乘法与其他实例:Physical

import numpy as np

class Physical():
    
    def __init__(self, value, unit=""):
        self.value = value
        self.unit = unit
    
    def __repr__(self):
        return f"<Physical:({self.value}, {self.unit})"
    
    def __str__(self):
        return f"{self.value} {self.unit}"
    
    def __add__(self, other):
        if self.unit == other.unit:
            return Physical(self.value + other.value, self.unit)
        else:
            raise ValueError("Physical objects must have same unit to be added.")
    
    def __sub__(self, other):
        if self.unit == other.unit:
            return Physical(self.value - other.value, self.unit)
        else:
            raise ValueError("Physical objects must have same unit to be subtracted.")

    def __mul__(self, other):
        return Physical(self.value * other.value, f"{self.unit}*{other.unit}")
    
    def __truediv__(self, other):
        return Physical(self.value / other.value, f"{self.unit}/{other.unit}")
        
    def __pow__(self, powfac):
        return Physical(self.value**powfac, f"{self.unit}^{powfac}")
        
weights = Physical(np.array([55.6, 45.7, 80.3]), "kilogram")
heights = Physical(np.array([1.64, 1.85, 1.77]), "meter")
print(weights) # [55.6 45.7 80.3] kilogram
print(heights) # [1.64 1.85 1.77] meter
print(heights + heights) # [3.28 3.7  3.54] meter
# print(height + weights) # raises ValueError
print(heights**2) # [2.6896 3.4225 3.1329] meter^2

现在可以将物理阵列与其他物理阵列相加或相乘。

请注意,在添加或减去物理之前,我们首先检查它们是否具有相同的单位:您不能用重量添加长度(或土豆加胡萝卜,或马用驴)。

这很好,我们现在可以计算一个身体质量指数 (BMI) 数组,给定一个以米为单位的高度数组和一个以公斤为单位的重量数组。BMI 只是通过将重量除以平方高度来给出的,即:

BMI =体重(公斤)/身高(米)^2

weights = Physical(np.array([55.6, 45.7, 80.3]), "kilogram")
heights = Physical(np.array([1.64, 1.85, 1.77]), "meter")
bmi = weights/heights**2
print(bmi) # [20.67221892 13.35281227 25.63120432] kilogram/meter^2

        万岁!我们使用身高数组和身高数组计算了一个身体质量指数数组,使用后面的numpy数组来执行实际的数值计算。但是numpy的数组还有很多东西可以提供,这就是它变得非常有趣的地方。

三、实现 numpy 函数支持

Numpy 提供了许多用于数组的有用函数。仅举几例:

  • np.sinnp.cosnp.tan
  • np.expnp.lognp.log10
  • np.addnp.multiplynp.divide
  • np.minnp.maxnp.argminnp.argmax
  • np.floornp.ceilnp.trunc
  • np.concatenatenp.vstack

等等。您可以在他们的网站上找到numpy提供的所有内容:Routines — NumPy v1.25 Manual。

让我们尝试在我们的类中使用其中之一:

np.mean(bmi)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
...
<ipython-input-10-538e4626f6f7> in __truediv__(self, other)
     31 
     32     def __truediv__(self, other):
---> 33         return Physical(self._value / other._value, f"{self._unit}/{other._unit}")
     34 
     35     def __pow__(self, powfac):

AttributeError: 'numpy.int64' object has no attribute '_value'

尝试调用我们的物理实例会引发一个 因为 numpy 依赖于整数的加法和除法,而我们的类没有正确实现这种操作。所以我们必须在某个地方告诉 numpy 我们想要如何表现。np.meanbmiAttributeErrornp.mean(bmi)

这就是界面发挥作用的地方。__array_function__

该接口只是一个规范化过程,用于重载(某些)numpy 函数如何处理类中的参数。__array_function__

让我们看一个轻量级的例子来处理我们的调用:np.mean(bmi)

import numpy as np

# FIRST
HANDLED_FUNCTIONS = {}

class Physical():
    
    def __init__(self, value, unit=""):
        self._value = value
        self._unit = unit
    
    # ... other methods here, see above
       
    # SECOND
    def __array_function__(self, func, types, args, kwargs):
        if func not in HANDLED_FUNCTIONS:
            return NotImplemented
        # Note: this allows subclasses that don't override
        # __array_function__ to handle MyArray objects
        if not all(issubclass(t, Physical) for t in types):
            return NotImplemented
        return HANDLED_FUNCTIONS[func](*args, **kwargs)
    
# THIRD
def implements(numpy_function):
    """Register an __array_function__ implementation for Physical objects."""
    def decorator(func):
        HANDLED_FUNCTIONS[numpy_function] = func
        return func
    return decorator
    
# FOURTH
@implements(np.mean)
def np_mean_for_physical(x, *args, **kwargs):
    # first compute the numerical value, with no notion of unit
    mean_value = np.mean(x._value, *args, **kwargs)
    # construct a Physical instance with the result, using the same unit
    return Physical(mean_value, x._unit)
 
weights = Physical(np.array([55.6, 45.7, 80.3]), "kilogram")
heights = Physical(np.array([1.64, 1.85, 1.77]), "meter")
bmi = weights/heights**2

print(np.mean(bmi)) # 19.885411834844252 kilogram/meter^2

使用 __array_function__ 接口实现 np.mean 支持

再次欢呼,返回我们物理数组的“平均值”,这确实是一个物理量,单位为“千克/米^2”。np.mean(bmi)

让我们回顾一下我们添加到代码中以实现此目的的内容。有 4 点需要注意:

  1. 首先,我们在类定义之上创建一个空字典,称为 。HANDLED_FUNCTION = {}
  2. 其次,我们在类中添加一个调用的方法,该方法采用一个名为 .我们将在一分钟内回到此方法的内容。__array_function__func
  3. 第三,我们创建一个装饰器构造函数:这是一个返回装饰器的函数(即,另一个将函数作为参数的函数)。我们的装饰器只是在我们的字典中创建 numpy 函数和 之间的对应关系,后者是我们版本的 numpy 函数。implementsHANDLED_FUNCTIONfunc
  4. 第四,我们实现了 numpy 处理物理实例的平均值,当调用时是物理实例。它具有与 大致相同的签名,并执行以下操作:np.mean(x)xnp.mean
  • 使用 x 的值计算数值平均值,这是一个普通数组。x._value
  • 然后使用平均值作为值和输入的单位作为单位创建新的物理实例。
  • 最后,我们在该函数上使用装饰器。implements

那么当我们打电话时会发生什么?np.mean(bmi)

好吧,由于 numpy 无法计算平均值,正如我们上面看到的,它检查是否有方法,并使用在 上使用的函数调用它,即 : 。bmi__array_function__bminp.meanbmi.__array_function__(np.mean, *args, **kwargs)

由于已经在 中注册,我们用它来调用我们的版本:这里相当于 。np.meanHANDELED_FUNCTIONSnp.meanHANDLED_FUNCTIONS[np.mean](*args, **kwargs)np_mean_for_physical(*args, **kwargs)

这就是如何使 numpy 的函数与您的自定义类一起工作。

不幸的是,这并不完全正确。此接口仅适用于某些 numpy 函数,但不适用于全部。

还记得上面的功能列表吗?好吧,我们可以将它们分为 2 个子列表:常规 numpy 函数和 numpy 通用函数 — 或简称“ufuncs”:

  • Numpy 函数 : , , , , ,np.minnp.maxnp.argminnp.argmaxnp.concatenatenp.vstack.
  • Numpy ufuncs : , , ,, , ,, , , , ,np.sinnp.cosnp.tannp.expnp.lognp.log10np.addnp.multiplynp.dividenp.floornp.ceilnp.trunc

我们看到了如何使用 实现 numpy 函数支持。在下一篇文章中,我们现在将看到如何使用该接口添加对“ufuncs”的支持。__array_function____array_ufunc__

四、总结一下 

  • 使用 numpy 数组的容器方法包括在自定义类实例中将数组设置为属性(与子类化数组相反)。
  • 要使类使用 numpy 函数调用(如 ),必须在类中实现接口。np.mean(my_array_like_instance)__array_function__
  • 这基本上是通过向类添加一个方法,编写自己的包装器(就像我们对 ) 所做的那样,并将它们链接在一起(就像我们对查找字典所做的那样)。__array_function__np_mean_for_physicalHANDLED_FUNCTIONS
  • 请注意,这仅适用于“常规”numpy 函数。对于numpy的“通用”函数,您还需要实现该接口。__array_ufunc__

这个主题相当广泛,所以这里有几个链接,你应该阅读,以更好地掌握利害关系:

  • 容器方法:Writing custom array containers — NumPy v1.25 Manual
  • __array_function__参考资料: Standard array subclasses — NumPy v1.25 Manual
  • 参考资料: Universal functions (ufunc) — NumPy v1.25 Manual

以下是我们在本文中编写的完整代码:

import numpy as np

HANDLED_FUNCTIONS = {}

class Physical():
    
    def __init__(self, value, unit=""):
        self._value = value
        self._unit = unit
    
    def __repr__(self):
        return f"<Physical:({self._value}, {self._unit})"
    
    def __str__(self):
        return f"{self._value} {self._unit}"
    
    def __add__(self, other):
        if self._unit == other._unit:
            return Physical(self._value + other._value, self._unit)
        else:
            raise ValueError("Physical objects must have same unit to be added.")
    
    def __sub__(self, other):
        if self._unit == other._unit:
            return Physical(self._value - other._value, self._unit)
        else:
            raise ValueError("Physical objects must have same unit to be subtracted.")

    def __mul__(self, other):
        return Physical(self._value * other._value, f"{self._unit}*{other._unit}")
    
    def __truediv__(self, other):
        return Physical(self._value / other._value, f"{self._unit}/{other._unit}")
    
    def __pow__(self, powfac):
        return Physical(self._value**powfac, f"{self._unit}^{powfac}")
        
    def __array_function__(self, func, types, args, kwargs):
        if func not in HANDLED_FUNCTIONS:
            return NotImplemented
        # Note: this allows subclasses that don't override
        # __array_function__ to handle Physical objects
        if not all(issubclass(t, Physical) for t in types):
            return NotImplemented
        return HANDLED_FUNCTIONS[func](*args, **kwargs)
    
    
def implements(numpy_function):
    """Register an __array_function__ implementation for Physical objects."""
    def decorator(func):
        HANDLED_FUNCTIONS[numpy_function] = func
        return func
    return decorator
    
    
@implements(np.mean)
def np_mean_for_physical(x, *args, **kwargs):
    # first compute the numerical value, with no notion of unit
    mean_value = np.mean(x._value, *args, **kwargs)
    # construct a Physical instance with the result, using the same unit
    return Physical(mean_value, x._unit)
 
    
weights = Physical(np.array([55.6, 45.7, 80.3]), "kilogram")
heights = Physical(np.array([1.64, 1.85, 1.77]), "meter")
print(weights)
print(heights)
print(heights + heights)
print(heights**2)
ratio = weights/heights
print(ratio)
bmi = weights/heights**2
print(bmi)
print(np.mean(bmi))

干杯!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/43440.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【STL】模拟实现简易 list

目录 1. 读源码 2. 框架搭建 3. list 的迭代器 4. list 的拷贝构造与赋值重载 拷贝构造 赋值重载 5. list 的常见重要接口实现 operator--() insert 接口 erase 接口 push_back 接口 push_front 接口 pop_back 接口 pop_front 接口 size 接口 clear 接口 别…

Window环境RabbitMq搭建部署

Erlang下载安装及配置环境变量 下载erlang&#xff0c;原因在于RabbitMQ服务端代码是使用并发式语言Erlang编写的 Erlang下载 Erlang官网下载&#xff1a; http://www.erlang.org/downloads Erlang国内镜像下载&#xff08;推荐&#xff09;&#xff1a; http://erlang.org/d…

旧版Xcode文件较大导致下载总是失败但又不能断点续传重新开始的解决方法

问题&#xff1a; 旧版mac下载旧版Xcode时需要进入https://developer.apple.com/download/all/?qxcode下载&#xff0c;但是下载这些文件需要登录。登录后下载中途很容易失败&#xff0c;失败后又必须重新下载。 解决方案&#xff1a; 下载这里面的内容都需要登录&#xff0…

Appium+python自动化(十九)- Monkey(猴子)参数(超详解)

前边几篇介绍了Monkey以及Monkey的事件&#xff0c;今天就给小伙伴们介绍和分享一下Monkey的参数。 首先我们看一下这幅图来大致了解一下&#xff1a; 1、Monkey 命令 基本参数介绍 -p <允许的包名列表> 用此参数指定一个或多个包。指定包之后&#xff0c;mon…

用html+javascript打造公文一键排版系统7:落款排版

一、公文落款的格式 公文落款包括单位署名和成文日期两个部分&#xff0c;其中成文日期中的数字 用阿拉伯数字将年、月、日标全&#xff0c;年份应标全称&#xff0c;月、日不编虚位&#xff08;即 1 不编为 01&#xff09;。 在实际应用工作中分为三种情况&#xff1a; &am…

【Selenium+Pytest+allure报告生成自动化测试框架】附带项目源码和项目部署文档

目录 前言 【文章末尾给大家留下了大量的福利】 测试框架简介 首先管理时间 添加配置文件 conf.py config.ini 读取配置文件 记录操作日志 简单理解POM模型 简单学习元素定位 管理页面元素 封装Selenium基类 创建页面对象 简单了解Pytest pytest.ini 编写测试…

保护数字世界的壁垒

随着科技的不断发展和互联网的普及&#xff0c;我们的生活日益依赖于数字化的世界。然而&#xff0c;随之而来的是网络安全威胁的不断增加。网络攻击、数据泄露和身份盗窃等问题已经成为我们所面临的现实。因此&#xff0c;网络安全变得尤为重要&#xff0c;我们需要采取措施来…

什么是分布式操作系统?我们为什么需要分布式操作系统?

分布式操作系统是一种特殊的操作系统&#xff0c;本质上属于多机操作系统&#xff0c;是传统单机操作系统的发展和延伸。它是将一个计算机系统划分为多个独立的计算单元(或者也可称为节点)&#xff0c;这些节点被部署到每台计算机上&#xff0c;然后被网络连接起来&#xff0c;…

Win10环境下Android Studio中运行Flutter HelloWorld项目

一、引言 Android Studio是Android的官方IDE(Integrated Development Environment)。它专为Android而打造&#xff0c;可以加快开发速度&#xff0c;为Android设备构建最高品质的应用。 Flutter是Google推出并开源的移动应用开发框架&#xff0c;主打跨平台、高保真、高性能。开…

【STL】list用法试做_底层实现

目录 一&#xff0c;list 使用 1. list 文档介绍 2. 常见接口 1. list中的sort 2. list sort 与 vector sort效率对比 3. 关于迭代器失效 4. clear 二&#xff0c;list 实现 1.框架搭建 2. 迭代器类——核心框架 3. operator-> 实现 4. const——迭代…

【计算机网络 01】说在前面 信息服务 因特网 ISP RFC技术文档 边缘与核心 交换方式 定义与分类 网络性能指标 计算机网络体系结构 章节小结

第一章--概述 说在前面1.1 计算机网络 信息时代作用1.2 因特网概述1.3 三种交换方式1.4 计算机网络 定义与分类1.5 计算机网络的性能指标1.6 计算机网络体系结构1 常见的计算机网络体系结构2 计算机网络体系结构分层的必要性3 计算机网络体系结构分层思想举例4 计算机网络体系结…

RuntimeError: DataLoader worker (pid 2105929) is killed by signal: Killed.

PyTorch DataLoader num_workers Test - 加快速度 可以利用PyTorch DataLoader类的多进程功能来加快神经网络训练过程。 加快训练进程 为了加快训练过程&#xff0c;我们将利用DataLoader类的num_workers可选属性。 num_workers属性告诉DataLoader实例要使用多少个子进程进…

23.多项式与非多项式曲线拟合对比(matlab程序)

1.简述 拟合标准&#xff1a; (1)原始数据向量与拟合向量之间的距离最小&#xff0c;该距离的度量一般使用误差平方和表示&#xff0c;即均方误差&#xff1a;R||Q-Y||22 (2)当均方误差最小时&#xff0c;说明构造的拟合向量与原始向量最为接近&#xff0c;这种曲线拟合的方法…

git commit -m时候没有保存package.json等文件

项目场景&#xff1a; 提示&#xff1a;git add . 和 git commit -m "保存" 操作&#xff0c;没有保存package.json等文件。 解决方案&#xff1a; 1.确保 package.json 文件没有被列在 .gitignore 文件中。打开 .gitignore 文件&#xff0c;检查是否有类似于 packa…

论文工具——ChatGPT结合PlotNeuralNet快速出神经网络深度学习模型图

文章目录 引言正文PlotNeuralNet安装使用使用python进行编辑使用latex进行编辑 样例利用chatGPT使用chatGPT生成Latex代码利用chatGPT生成对应的python代码 总结引用 引言 介绍如何安装PlotNeuralNet工具&#xff0c;并结合chatGPT减少学习成本&#xff0c;快速出图。将按照软…

4.2 Bootstrap HTML编码规范

文章目录 Bootstrap HTML编码规范语法HTML5 doctype语言属性IE 兼容模式字符编码引入 CSS 和 JavaScript 文件HTML5 spec links 实用为王属性顺序布尔&#xff08;boolean&#xff09;型属性减少标签的数量JavaScript 生成的标签 Bootstrap HTML编码规范 语法 用两个空格来代替…

通过 EXPLAIN 分析 SQL 的执行计划

通过 EXPLAIN 分析 SQL 的执行计划 EXPLAIN SELECTleave_station_area_id,ROUND( ( SUM( station_dist ) / 1000 ) / ( SUM( station_travel_time ) / 60 ), 2 ) evnPeakAvgSpeedFROMV3_SHIFT_ANALYSISWHERESTAT_DATE DATE_SUB( CURRENT_DATE, INTERVAL 1 DAY )AND LEAVE_STA…

NetSuite财务报表General Ledger Report的缺陷及改造案例

本周有用户提到一个特殊的业务场景&#xff0c;比较有代表性&#xff0c;在此分享。 问题 “如果在一张JE中&#xff0c;某个科目既有借又有贷&#xff0c;金额相同。那么在General Ledger Report中此JE的借贷都显示为0。这与事实不符&#xff0c;所以是不对的。” JE 155&a…

vue3-element-plus,控制表格多选的数量

1. 需求描述 控制表格的多选&#xff0c;最多只能选择5条数据&#xff0c;并且其他项禁用 2. 需求描述 <!-- selection-change 当选择项发生变化时会触发该事件--><template><el-tableref"multipleTableRef"v-loading"loading":data"…

[Linux] CentOS7 中 pip3 install 可能出现的 ssl 问题

由于解决问题之后, 才写的博客, 所以没有图片记录. 尽量描述清楚一些 今天写代码的时候, 突然发现 文件里用了#define定义宏之后, coc.nvim的coc-clangd补全就用不了 :checkhealth了一下, 发现nvim忘记支持python3了 尝试pip3 install neovim的时候, 发现会警告然后安装失败.…
最新文章