原文:
zh.annas-archive.org/md5/123a7612a4e578f6816d36f968cfec22
译者:飞龙
第十一章:其他主题
在本章中,我们将讨论一些在本书前几章中没有涉及的主题。这些主题大多涉及不同的计算方式以及优化代码执行的其他方式。其他主题涉及处理特定类型的数据或文件格式。
在前两个内容中,我们将介绍帮助跟踪计算中的单位和不确定性的软件包。这些对于涉及具有直接物理应用的数据的计算非常重要。在下一个内容中,我们将讨论如何从 NetCDF 文件加载和存储数据。NetCDF 通常用于存储天气和气候数据的文件格式。(NetCDF 代表网络通用数据格式。)在第四个内容中,我们将讨论处理地理数据,例如可能与天气或气候数据相关的数据。之后,我们将讨论如何可以在不必启动交互式会话的情况下从终端运行 Jupyter 笔记本。接下来的两个内容涉及验证数据和处理从 Kafka 服务器流式传输的数据。我们最后两个内容涉及两种不同的方式,即使用诸如 Cython 和 Dask 等工具来加速我们的代码。
在本章中,我们将涵盖以下内容:
- 使用 Pint 跟踪单位
- 在计算中考虑不确定性
- 从 NetCDF 文件加载和存储数据
- 处理地理数据
- 将 Jupyter 笔记本作为脚本执行
- 验证数据
- 处理数据流
- 使用 Cython 加速代码
- 使用 Dask 进行分布式计算
让我们开始吧!
技术要求
由于本章包含的内容的性质,需要许多不同的软件包。我们需要的软件包列表如下:
- Pint
- 不确定性
- NetCDF4
- xarray
- GeoPandas
- Geoplot
- Papermill
- Cerberus
- Faust
- Cython
- Dask
所有这些软件包都可以使用您喜欢的软件包管理器(如pip
)进行安装:
python3.8 -m pip install pint uncertainties netCDF4 xarray geopandas geoplot papermill cerberus faust cython
安装 Dask 软件包,我们需要安装与软件包相关的各种额外功能。我们可以在终端中使用以下pip
命令来执行此操作:
python3.8 -m pip install dask[complete]
除了这些 Python 软件包,我们还需要安装一些支持软件。对于处理地理数据的内容,GeoPandas 和 Geoplot 库可能需要单独安装许多低级依赖项。详细说明在 GeoPandas 软件包文档中给出,网址为geopandas.org/install.html
。
对于处理数据流的内容,我们需要安装 Kafka 服务器。如何安装和运行 Kafka 服务器的详细说明可以在 Apache Kafka 文档页面上找到,网址为kafka.apache.org/quickstart
。
对于Cython 加速代码的内容,我们需要安装 C 编译器。如何获取GNU C 编译器(GCC)的说明在 Cython 文档中给出,网址为cython.readthedocs.io/en/latest/src/quickstart/install.html
。
本章的代码可以在 GitHub 存储库的Chapter 10
文件夹中找到,网址为github.com/PacktPublishing/Applying-Math-with-Python/tree/master/Chapter%2010
。
查看以下视频以查看代码的实际操作:bit.ly/2ZMjQVw
。
使用 Pint 跟踪单位
在计算中正确跟踪单位可能非常困难,特别是在可以使用不同单位的地方。例如,很容易忘记在不同单位之间进行转换 – 英尺/英寸转换成米 – 或者公制前缀 – 比如将 1 千米转换成 1,000 米。
在这个内容中,我们将学习如何使用 Pint 软件包来跟踪计算中的测量单位。
准备工作
对于这个示例,我们需要 Pint 包,可以按如下方式导入:
import pint
如何做…
以下步骤向您展示了如何使用 Pint 包在计算中跟踪单位:
- 首先,我们需要创建一个
UnitRegistry
对象:
ureg = pint.UnitRegistry(system="mks")
- 要创建带有单位的数量,我们将数字乘以注册对象的适当属性:
distance = 5280 * ureg.feet
- 我们可以使用其中一种可用的转换方法更改数量的单位:
print(distance.to("miles")) print(distance.to_base_units()) print(distance.to_base_units().to_compact())
这些print
语句的输出如下:
0.9999999999999999 mile 1609.3439999999998 meter 1.6093439999999999 kilometer
- 我们包装一个例程,使其期望以秒为参数并输出以米为结果:
@ureg.wraps(ureg.meter, ureg.second) def calc_depth(dropping_time): # s = u*t + 0.5*a*t*t # u = 0, a = 9.81 return 0.5*9.81*dropping_time*dropping_time
- 现在,当我们使用分钟单位调用
calc_depth
例程时,它会自动转换为秒进行计算:
depth = calc_depth(0.05 * ureg.minute) print("Depth", depth) # Depth 44.144999999999996 meter
它是如何工作的…
Pint 包为数字类型提供了一个包装类,为类型添加了单位元数据。这个包装类型实现了所有标准的算术运算,并在这些计算过程中跟踪单位。例如,当我们将长度单位除以时间单位时,我们将得到速度单位。这意味着您可以使用 Pint 来确保在复杂计算后单位是正确的。
UnitRegistry
对象跟踪会话中存在的所有单位,并处理不同单位类型之间的转换等问题。它还维护一个度量参考系统,在这个示例中是标准国际系统,以米、千克和秒作为基本单位,表示为mks
。
wrap
功能允许我们声明例程的输入和输出单位,这允许 Pint 对输入函数进行自动单位转换-在这个示例中,我们将分钟转换为秒。尝试使用没有关联单位或不兼容单位的数量调用包装函数将引发异常。这允许对参数进行运行时验证,并自动转换为例程的正确单位。
还有更多…
Pint 包带有一个大型的预设测量单位列表,涵盖了大多数全球使用的系统。单位可以在运行时定义或从文件加载。这意味着您可以定义特定于您正在使用的应用程序的自定义单位或单位系统。
单位也可以在不同的上下文中使用,这允许在不同单位类型之间轻松转换,这些单位类型通常是不相关的。这可以在需要在计算的多个点之间流畅地移动单位的情况下节省大量时间。
在计算中考虑不确定性
大多数测量设备并不是 100%准确的,通常只能准确到一定程度,通常在 0 到 10%之间。例如,温度计可能准确到 1%,而一对数字卡尺可能准确到 0.1%。在这两种情况下,报告的数值不太可能是真实值,尽管它会非常接近。跟踪数值的不确定性是困难的,特别是当您有多种不同的不确定性以不同的方式组合在一起时。与其手动跟踪这些,最好使用一个一致的库来为您完成。这就是uncertainties
包的作用。
在这个示例中,我们将学习如何量化变量的不确定性,并看到这些不确定性如何通过计算传播。
准备工作
对于这个示例,我们将需要uncertainties
包,我们将从中导入ufloat
类和umath
模块:
from uncertainties import ufloat, umath
如何做…
以下步骤向您展示了如何在计算中对数值的不确定性进行量化:
- 首先,我们创建一个不确定的浮点值为
3.0
加减0.4
:
seconds = ufloat(3.0, 0.4) print(seconds) # 3.0+/-0.4
- 接下来,我们进行涉及这个不确定值的计算,以获得一个新的不确定值:
depth = 0.5*9.81*seconds*seconds print(depth) # 44+/-12
- 接下来,我们创建一个新的不确定浮点值,并在与之前计算相反的方向上应用
umath
模块的sqrt
例程:
other_depth = ufloat(44, 12) time = umath.sqrt(2.0*other_depth/9.81) print("Estimated time", time) # Estimated time 3.0+/-0.4
它是如何工作的…
ufloat
类包装了float
对象,并在整个计算过程中跟踪不确定性。该库利用线性误差传播理论,使用非线性函数的导数来估计计算过程中传播的误差。该库还正确处理相关性,因此从自身减去一个值会得到 0,没有误差。
要跟踪标准数学函数中的不确定性,您需要使用umath
模块中提供的版本,而不是 Python 标准库或第三方包(如 NumPy)中定义的版本。
还有更多…
uncertainties
包支持 NumPy,并且前面示例中提到的 Pint 包可以与不确定性结合使用,以确保正确地将单位和误差边界归因于计算的最终值。例如,我们可以从本示例的步骤 2中计算出计算的单位,如下所示:
import pint from uncertainties import ufloat g = 9.81*ureg.meters / ureg.seconds ** 2 seconds = ufloat(3.0, 0.4) * ureg.seconds depth = 0.5*g*seconds**2 print(depth)
如预期的那样,最后一行的print
语句给出了我们预期的44+/-12 米
。
从 NetCDF 文件加载和存储数据
许多科学应用程序要求我们以稳健的格式开始大量的多维数据。NetCDF 是天气和气候行业用于开发数据的格式的一个例子。不幸的是,数据的复杂性意味着我们不能简单地使用 Pandas 包的实用程序来加载这些数据进行分析。我们需要netcdf4
包来能够读取和导入数据到 Python 中,但我们还需要使用xarray
。与 Pandas 库不同,xarray
可以处理更高维度的数据,同时仍提供类似于 Pandas 的接口。
在这个示例中,我们将学习如何从 NetCDF 文件中加载数据并存储数据。
准备就绪
对于这个示例,我们需要导入 NumPy 包作为np
,Pandas 包作为pd
,Matplotlib pyplot
模块作为plt
,以及从 NumPy 导入默认随机数生成器的实例:
import numpy as np import pandas as pd import matplotlib.pyplot as plt from numpy.random import default_rng rng = default_rng(12345)
我们还需要导入xarray
包并使用别名xr
。您还需要安装 Dask 包,如“技术要求”部分所述,以及 NetCDF4 包:
import xarray as xr
我们不需要直接导入这两个包。
操作方法…
按照以下步骤加载和存储样本数据到 NetCDF 文件中:
- 首先,我们需要创建一些随机数据。这些数据包括一系列日期、位置代码列表和随机生成的数字:
dates = pd.date_range("2020-01-01", periods=365, name="date") locations = list(range(25)) steps = rng.normal(0, 1, size=(365,25)) accumulated = np.add.accumulate(steps)
- 接下来,我们创建一个包含数据的 xarray
Dataset
对象。日期和位置是索引,而steps
和accumulated
变量是数据:
data_array = xr.Dataset({ "steps": (("date", "location"), steps), "accumulated": (("date", "location"), accumulated) }, {"location": locations, "date": dates} ) print(data_array)
print
语句的输出如下所示:
<xarray.Dataset> Dimensions: (date: 365, location: 25) Coordinates: * location (location) int64 0 1 2 3 4 5 6 7 8 ... 17 18 19 20 21 22 23 24 * date (date) datetime64[ns] 2020-01-01 2020-01-02 ... 2020-12-30 Data variables: steps (date, location) float64 geoplot.pointplot(cities, ax=ax, fc="r", marker="2") ax.axis((-180, 180, -90, 90))-1.424 1.264 ... -0.4547 -0.4873 accumulated (date, location) float64 -1.424 1.264 -0.8707 ... 8.935 -3.525
- 接下来,我们计算每个时间索引处所有位置的平均值:
means = data_array.mean(dim="location")
- 现在,我们在新的坐标轴上绘制平均累积值:
fig, ax = plt.subplots() means["accumulated"].to_dataframe().plot(ax=ax) ax.set(title="Mean accumulated values", xlabel="date", ylabel="value")
生成的绘图如下所示:
图 10.1:随时间累积平均值的绘图
- 使用
to_netcdf
方法将此数据集保存到新的 NetCDF 文件中:
data_array.to_netcdf("data.nc")
- 现在,我们可以使用
xarray
的load_dataset
例程加载新创建的 NetCDF 文件:
new_data = xr.load_dataset("data.nc") print(new_data)
前面代码的输出如下所示:
<xarray.Dataset> Dimensions: (date: 365, location: 25) Coordinates: * location (location) int64 0 1 2 3 4 5 6 7 8 ... 17 18 19 20 21 22 23 24 * date (date) datetime64[ns] 2020-01-01 2020-01-02 ... 2020-12-30 Data variables: steps (date, location) float64 -1.424 1.264 ... -0.4547 -0.4873 accumulated (date, location) float64 -1.424 1.264 -0.8707 ... 8.935 -3.525
Python 数学应用(四)(2)https://developer.aliyun.com/article/1506409