physipy: 使 Python 具有单位感知

原文:towardsdatascience.com/physipy-make-python-unit-aware-846162522889

你是否曾经用 Python 进行过工程/科学计算,最终发现自己迷失或困惑于变量的单位,比如“那是米还是毫米的值”?或者你意识到在某个时刻你添加了一个电流和一个电阻——这是不可能的?就像每个物理老师都说过的一样:你不能把胡萝卜和西红柿加在一起。

好吧,**physipy**正是为了解决这类问题而存在的。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/48a489520af593c6f986187d72cd631c.png

Artturi JalliUnsplash上的照片


目录:

· 什么是 physipy? · 一次一个示例理解 physipy ∘使用 physipy 计算身体质量指数 BMI ∘ 使用 NumPy 数组牛顿运动定律 ∘ 使用 NumPy 函数的欧姆定律 ∘ 使用 favunit 计算常见粒子的爱因斯坦质能等价 ∘ 使用内置 favunit 进行自由落体 ∘ 使用 Matplotlib 绘制物体位置和速度 · 总结

所有图片均为作者所有。

什么是 physipy?

***physipy***是一个轻量级的包,它允许你非常容易地定义和声明物理单位,并跟踪所有变量的单位。换句话说,你永远不需要在变量后加上相应的单位(例如my_height_cm将变成my_height),如果你试图把胡萝卜和西红柿加在一起,将会抛出一个异常。

physipy为科学/工程工作提供了很好的功能:它与 NumPy 完美集成,提供了 Pandas 扩展,完整的文档,与 Matplotlib 无缝工作,并为 jupyter 提供了(ipy)小部件。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/50b8975149fd05132af07cb8b09828fc.png

导入米和秒,并开始使用具有单位感知的变量。

为了完全透明,我是 physipy 的创建者。另外请注意,physipy 在MIT 许可证下。

一次一个示例理解 physipy

在这篇第一篇文章中,我们将看到如何使用physipy,特别是它如何与 NumPy 和 Matplotlib 很好地集成,通过一些基本的示例。

这些示例的目的是按顺序阅读,因为在阅读过程中会逐渐添加概念和工具。另一方面,它们都旨在非常简单且注释良好,所以即使直接跳到最后一个也能理解。

您也可以直接访问 Physipy 的文档或 GitHub 上的项目仓库。

physipy : 使 python 具有单位感知功能

GitHub – mocquin/physipy: 一个透明的处理物理量(如 2…

要安装 physipy,您可以使用 pypi 通过简单的命令行:

pip install physipy 

或者如果您更喜欢从 GitHub 下载最新版本,您可以在本地下载并解压缩包,或者使用以下命令克隆 git 仓库:

git clone https://github.com/mocquin/physipy 

使用 physipy 计算身体质量指数 BMI

如您所知,一个常见的健康指标是身体质量指数。正如维基百科所述(As wikipedia states):

体质指数(BMI)是从一个人的质量(体重)和身高推导出的一个值。BMI 定义为身体质量除以身体高度的平方,并以 kg/m2 的单位表示,由千克(kg)的质量和米(m)的高度组成。

让我们看看没有 physipy 的代码会是什么样子:

#### BMI example, without physipy# no physipy → we need to keep track of the unit everywhere my_weight_kg =75 my_height_m =1.89defbmi_calculator(weight_kg, height_m):"Compute Body-Mass-Index from weight and height."return weight_kg / height_m**2print(bmi_calculator(my_weight_kg, my_height_m))# notice that the output is pure, unit-less number, while it is actually kg-per-meter-squared# 20.99605274208449

现在让我们看看使用 physipy 的代码是什么样的:

from physipy import kg, m # define physical quantities that are unit aware my_weight =75* kg my_height =1.89* m defbmi_calculator(weight, height):"Compute Body-Mass-Index from weight and height."return weight / height**2print(bmi_calculator(my_weight, my_height))# 20.99605274208449 kg/m**2

注意代码变化有多小:我们可以在变量名称中去除任何单位后缀,而不会失去对它们的跟踪。

另一方面,我们可以看到变量的值是明确定义的,使用了命名单位。另一个很好的特性是返回的输出仍然附有适当的单位,在这种情况下是 kg/m**2

好处在于我们可以使用任何单位,而不用担心任何转换:所有转换都由 Physipy 在后端完成。

例如,假设你记录了身高(厘米)和体重(克)。

# retrieve the unitsfrom physipy import units # units is just a dict cm = units['cm'] g = units['g']print(bmi_calculator(75000*g,189*cm))# 20.99605274208449 kg/m**2

因此,我们得到了相同的输出值,同时我们能够指定变量在其他单位中。

使用 numpy 数组进行牛顿运动定律

我们在这里演示如何仅使用常规乘法运算符(类似于浮点数和整数)将单位附加到常规 NumPy 数组上:

import numpy as np from physipy import m, kg, s m = np.array([10,20,30])* kg # mass a =2* m / s**2# acceleration# Calculate force using Newton's Second Law : force = mass * acceleration F = m * a print(F)# [ 200\. 800\. 1800.] kg**2/s**2 # 1 kg**s/s**2 is equivalent to 1 Newton

欧姆定律与 NumPy 函数

使用 NumPy 和 Physipy 几乎可以与所有 NumPy 的函数一起工作。在这里,我们可以使用具有单位感知值的 NumPy 函数,并且返回的数组仍然具有正确的单位。

import numpy as np from physipy import units V = units['V'] ohm = units['ohm'] V =12* V # voltage R = np.arange(1*ohm,5*ohm)# array with unit ohm# Calculate current using Ohm's Law I = V / R print(I)# [12\. 6\. 4\. 3.] A# If for some reason you forgot the unit of I, physipy knows and attaches# it to I for you - you get an output in Amps for free !

对于常见粒子,使用 favunit 的爱因斯坦质量-能量等价

对于常见粒子,使用 Favunit 在这个例子中,我们介绍了任何单位感知对象的 .favunit 属性,这意味着这个变量的“首选单位”。这个单位将用于打印变量。在国际单位制中,能量的标准单位是焦耳,等于 1 kg*m2/s2。

import numpy as np from physipy import constants, kg, units # constants is just a dict of physical constants c = constants['c'] J = units['J'] masses = np.array([9.1093837E-31,# mass of electron1.673E-27,# mass of proton1.675E-27,# mass of neutron])* kg # Calculate energy using Einstein's equation E = masses * c**2# indexing works just as usual, with the added output energy unitprint(E[0])# enery for proton : 8.187105775475753e-14 kg*m**2/s**2print(E)# [8.18710578e-14 1.50361741e-10 1.50541492e-10] kg*m**2/s**2# changing the display unit to Joule E.favunit = J print(E[0])# 8.187105775475753e-14 Jprint(E)# [8.18710578e-14 1.50361741e-10 1.50541492e-10] J

如您所见,相同的变量 favunit 可以随意修改以更改其字符串表示形式。Physipy 的酷之处在于,这个 .favunit 属性仅用于打印目的;实际的“真实”值和物理单位(kg*m2/s2)存储在后端。

使用内置的 favunit 进行自由落体

在这个例子中,我们正在模拟一个物体从 100 米的初始高度自由落体。我们使用自由落体的运动方程,h=h0−1/2gt²,其中 h 是物体在时间 t 的高度,h0 是初始高度,g 是重力加速度,t 是时间。

我们使用这个例子来展示如何设置 favunit —— 变量用于打印的单位,可以是函数中的“手动”设置,也可以使用 set_favunit 装饰器。

让我们先看看如何手动设置首选单位:

import numpy as np from physipy import m, s, units cm = units['cm']# we are using cm as the favunit# Constants initial_height =100* m # Initial height of the object gravity =9.81* m / s**2# Acceleration due to gravity# Time samples time_samples = np.linspace(0,3,50)* s # Time samples from 0 to 5 secondsdefcalculate_height(time_samples): heigth = initial_height -0.5* gravity * time_samples**2 heigth.favunit = cm return heigth # Calculate heights for each time sample heights = calculate_height(time_samples)# Print time samples and corresponding heightsfor t, h inzip(time_samples, heights):print(f"Time: {t}, Height: {h}")# Time: 0.0 s, Height: 10000.0 cm# ...# Time: 3.0 s, Height: 5585.5 cm

虽然设置高度 favunit 的方法很简单,但它与实际的数学计算无关。另一种方法是使用 set_favunit 装饰器。所以以下两个片段是等效的:

手动设置 favunit:

defcalculate_height(time_samples): heigth = initial_height -0.5* gravity * time_samples**2 heigth.favunit = cm return heigth 

在这里使用 set_favunit 装饰器

from physipy import set_favunit @set_favunit(cm)defcalculate_height(time_samples): heigth = initial_height -0.5* gravity * time_samples**2return heigth 

使用 set_favunit 装饰器可能更受欢迎,因为它将计算逻辑和单位打印分离开来。

使用 Matplotlib 绘制物体的位置和速度

在这个例子中,我们正在可视化物体在重力影响下的运动。具体来说,我们正在绘制其运动的两个重要方面:位移和速度,随时间的变化。

重要的语句是调用 setup_matplotlib(),这样 Matplotlib 就会意识到 Physipy,并且默认情况下会在绘制单位感知对象时设置相应的单位。

换句话说,你可以去掉 set_xlabel('s')set_ylabel('km') 来指定单位;physipy 会自动完成这项工作。

import numpy as np import matplotlib.pyplot as plt from physipy import units, s, setup_matplotlib, constants cm = units['cm']# centimeter ms = units["ms"]# millisecond g = constants['g']# this makes matplotlib aware of physipy setup_matplotlib() time = np.linspace(0,10,100)* s # Time values time.favunit = ms velocity = g * time # Velocity as a function of time (assuming constant acceleration) displacement =0.5* g * time**2# displace from origin position displacement.favunit = cm # Plotting fig, ax = plt.subplots(figsize=(10,4)) ax.plot(time, displacement, label="Displacement", color="blue") ax2 = ax.twinx() ax2.plot(time, velocity, label="Velocity", linestyle=" - ", color="red")

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/52357ccf04fe088d66f79b45995d90fc.png

注意,轴标签上添加了一些单位,但没有显式调用 set_xlabel/set_ylabel。

总结

希望这些例子能帮助你理解如何使用 physipy 的基础知识。你应该记住以下事项:

  • 使用 physipy 最简单的方法是导入一些单位/常量,这些单位/常量存储在经典的 Python 字典中,使用 from physipy import units, constants。注意,国际单位制(Système International units)可以直接使用 from physipy import m, s, kg
  • 要定义单位感知变量,只需将值乘以单位即可,例如 heights = np.linspace(1, 50)*km
  • 几乎所有的 numpy 函数都适用于单位感知数组,例如,你可以简单地使用 np.max(heights) 找到高度数组中的最大值,返回的值将是 50000 m
  • 默认情况下,单位感知值将使用 SI 单位打印,例如,焦耳将打印为 kg*m**2/s**2。如果你想使用特定的单位,只需设置 favunit 属性:heights.favunit = mm
  • 你可以使用 from physipy import setup_matplotlibsetup_matplotlib() 来使 matplotlib 识别 physipy 并处理单位。从那时起,任何图表都会将单位添加到轴标签中。

physipy 的优点是它轻量级(简单的示例,源代码简单),它与 numpy 和 matplotlib 高度集成

我们稍后会看到,它也是一个处理 Python 中单位的快速包,归功于其轻量级结构(因此开销小)。它还提供了pandas 扩展ipywidgets for jupyter/notebooks

在下一篇文章中,我们将稍微深入探讨 physipy,介绍 physipy 的 2 个(也是唯一 2 个)重要类,即DimensionQuantity

你可以在项目的文档中找到更多示例和大量信息:

physipy : 使 Python 具有单位感知

你可能喜欢我之前的一些帖子,我写关于 Python、机器学习/数据科学、信号处理、数值技术的内容:

Sklearn 教程

科学/数值 Python

数据科学和机器学习

时间序列的傅里叶变换

Read more

动态规划 路径类 DP 入门:3 道经典例题(最小路径和 + 迷雾森林 + 过河卒)全解析

动态规划 路径类 DP 入门:3 道经典例题(最小路径和 + 迷雾森林 + 过河卒)全解析

文章目录 * 矩阵的最小路径和 * 迷雾森林 * 过河卒 路径类 dp 是线性 dp 的⼀种,它是在⼀个 n × m 的矩阵中设置⼀个⾏⾛规则,研究从起点⾛到终点的 ⽅案数、最⼩路径和或者最⼤路径和等等的问题。 ⼊⻔阶段的《数字三⻆形》其实就是路径类 dp。 矩阵的最小路径和 题目描述 题目解析 1、状态表示 dp[i][j]表示从[1 1]格子走到[i j]格子时,所有方案下的最小路径和。 2、状态转移方程 我们还是以最后一步来推导状态转移方程,走到最后一个格子dp[n][m]

By Ne0inhk

优选算法——前缀和

👇作者其它专栏 《数据结构与算法》《算法》《C++起始之路》 前缀和相关题解 1.前缀和 算法思路: a.先预处理出来一个【前缀和】数组:         用dp[i]表示:[1,i]区间内所有元素的和,那么dp[i-1]里面存的就是[1,i-1]区间内所有元素的和,那么:可得到递推公式:dp[i]=dp[i-1]+arr[i]; b.使用前缀和数组,【快速】求出【某一个区间内】所有元素的和:         当访问的区间是[l,r]时:区间内所有元素的和为:dp[r]-dp[l-r]。 #include <

By Ne0inhk
【算法通关指南:算法基础篇】二分算法: 1.A-B 数对 2.烦恼的高考志愿

【算法通关指南:算法基础篇】二分算法: 1.A-B 数对 2.烦恼的高考志愿

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人等方向学习者 ❄️个人专栏:《C语言》《【初阶】数据结构与算法》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、A-B 数对 * 1.1题目 * 1.2 算法原理 * 1.3代码 * 二、烦恼的高考志愿 * 2.1 题目 * 2.2 算法原理 * 2.3 代码 * 总结与每日励志 前言 本文将通过两道经典二分查找例题 ——A-B 数对与烦恼的高考志愿,带你系统掌握二分查找的核心思想与实用技巧。从排序预处理到lower_bound、upper_bound的灵活运用,再到手动实现二分与边界细节处理,由浅入深讲解算法原理与代码实现,帮助你快速攻克二分查找题型,提升编程思维与解题效率 一、

By Ne0inhk
【数据结构与算法】环与相遇:链表带环问题的底层逻辑与工程实现

【数据结构与算法】环与相遇:链表带环问题的底层逻辑与工程实现

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人等方向学习者 ❄️个人专栏:《C语言》《【初阶】数据结构与算法》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、带环链表 * 1.1题目 * 1.2 算法原理 * 1.3 代码 * 1.4 数学证明 * 1.4.1 为什么带环slow与fast必定能相遇? * 1.4.2 fast一定只能走2步吗?可以是2步甚至更多吗? * 1.4.2.1 以3步为例 * 1.4.3结论 * 二、环形链表(寻找相遇点) * 2.1 题目

By Ne0inhk