7.9 Working with NumPy arrays
NumPy是一个Python包,可帮助快速处理大型数据集。
NumPy是“numerical Python”的缩写,该软件包旨在支持科学计算。它通常发音为NUM-pie,但有时发音为NUM-pee。它是名为“SciPy(发音为Sigh-Pie)堆栈”的Python包的更大集合的一部分,该堆栈还包括Matplotlib、IPython和Pandas。NumPy使用称为NumPy数组的数据结构,也称为多维数组或n维数组。
为什么使用NumPy?首先,相对于使用其他模块或包执行类似任务,它通常工作得很快。第二,它包括许多其他软件包中没有的处理和分析算法。第三,许多其他包都使用NumPy数组数据结构,因此NumPy用于交换数据。在GIS环境中,NumPy通常用于处理大型光栅数据集,作为遥感或空间分析工作流的一部分。
Python使用几种不同的数据结构,通常分为两类。首先,有数字,包括整数和浮点数。
第二,有序列,包括字符串、列表和元组。NumPy使用称为 array 的不同数据结构。通过设计,这种结构更接近计算机硬件的工作方式,这也是它更快的原因之一。arrays 是为科学计算而设计的。他们类似于Python列表,但是是n维的,而列表只有一个维度。
注意:回想一下ArcPy包含一个名为Array的类。尽管该类与NumPy数组共享一些常见元素,但在使用ArcPy时处理几何对象的上下文中,它仅用于特定的目的。因此,ArcPy和NumPy数组中的数组对象不可互换。
NumPy数组通常由数字组成,这些值由正整数元组索引。数组是多维的,数组的每个维度都称为轴axis。阵列中的轴数也称为 rank。每个轴都有一个长度,这是该轴中元素的数量,就像列表一样。单个维度中数字都是相同的类型。数组(array)支持使用切片和索引,如列表。数组的一个例子是[0,1,2,3],这个数组的维数(dimension)或秩(rank)是一,因为只有一个轴(axis)。第一个(也是唯一的)轴的长度是四。一维(或1D)NumPy数组类似于列表。
考虑如何创建此数组,如下所示:
import numpy as np
a = np.array([0, 1, 2, 3])
NumPy包是导入的,按照惯例,它是作为np导入的,但不需要以这种方式导入。NumPy数组对象是使用array()函数创建的,该函数的参数是Python列表。示例有效地将列表转换为数组。
创建数组后,可以检查其一些财产。
ndim
属性返回数组的维度,如下所示:
这个属性返回值1。可以使用
len()
数确定数组的长度(或大小):
返回的结果为第一个维度的长度,结果为4。接下来,考虑二维数组:
b = np.array([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]])
print(b.ndim)
print(len(b))
结果范围维度 2 和第一个维度(第一个大括号)大小的值3。
shape
属性返回所有维度的大小:
返回值为(3,4),示例array也称为3×4 array。2D NumPy数组类似于表或矩阵。
在本例中,表有三列和四行,尽管行和列的概念不以相同的方式应用于数组。
可以按如下方式创建三维或3D阵列:
import numpy as np
c = np.array([[[1], [2], [3]], [[4], [5], [6]]])
这个代码创建一个三维数组,形状属性为(2,3,1)或2×3×1数组。虽然3D阵列有时被称为“三维矩阵”,但它没有等效的。同样的方法可以继续创建4D、5D和更高维度的阵列。这就是为什么NumPy数组被称为n维,其中n是正整数。
认识到维度的意义很重要。创建NumPy数组时,维度是数据维度,而不是坐标空间的维度。在GIS中,通常将2D视为水平空间(x,y坐标),将3D视为水平加垂直空间(x、y、z坐标)。在NumPy数组中,位置(x,y或x,y,z)只有一个维度。坐标通常以元组的形式存储在这个一维中。例如,2D空间中的点(例如,(1512768、3201482))的坐标本身是rank 1的阵列,因为它具有一个轴。因此,在考虑GIS中的坐标时,NumPy中的维度不是通常所认为的。基本上,坐标表示一个维度,其他维度可以是属性值和时间。以下示例将两个点表示为NumPy数组,每个点都有一个ID和一对x,y坐标:
import numpy as np
newarray = np.array([(1, (471316, 5130448)), (2, (470402, 5130249))])
这个代码表示2D数组,其中第一个维度表示属性值(在本例中为ID),第二维度表示坐标(在本示例中为x,y值的元组,但也可以是x,y,z)。
NumPy数组的创建方式多种多样。值可以直接输入到代码中,如前面的示例所示。Python序列(如列表和元组tuples)可以转换为数组。也可以转换现有数据源,包括表、要素类和光栅数据集。此外,还有几个NumPy函数可以从头创建数组。这包括
zeros()
函数用于创建一个只有零值的数组,
ones()
函数用于值为1,
arrange()
函数则用于数字序列。这些函数的shape参数设置数组的维度和每个维度的大小。例如,以下代码创建了一个值为零的二维3×5数组:
import numpy as np
zeroarray = np.zeros((3, 5))
结果为:
arrange()
函数可以将数字序列转换为数组,就像Python的内置
range()
函数一样<以下示例创建一维数组:
import numpy as np
newarray = np.arange(1, 10)
结果为:
数组对象的
reshape ()
方法可以将数值序列修改为所需的数组:
import numpy as np
array3x3 = np.arange(1, 10).reshape((3, 3))
结果是生成一个3*3的数组:
这里的示例只使用一维和二维数组,因为它们很容易可视化,但是可以对任何多维数组使用相同的函数和方法。
正如 Python 中常见的那样,数据类型是从值派生出来的:
import numpy as np
a = np.array([2, 3, 4])
print(a.dtype)
这个代码返回 int32 作为数据类型,一个32位的整数。可以在创建数组时显式指定数据类型,不依赖动态赋值,如下所示:
import numpy as np
b = np.array([2, 3, 4], dtype="float32")
即便是值为整数,也会被设置为32位浮点数。
从头开始创建NumPy数组并不常见,尽管它们允许您使用易于可视化的值来练习数组操作。GIS 工作流 中更常见的场景是将现有数据集转换为NumPy数组进行处理。ArcPy包含用于此转换的几个函数。为了在光栅数据和NumPy数组之间进行转换,ArcPy有两个函数,这两个函数是ArcPy的常规函数,而不是ArcPy.sa模块的函数:
NumPyArrayToRaster()
RasterToNumPyArray()
要在要素类和表以及NumPy阵列之间进行转换,
arcpy.da
模块有四个函数:
还有一个额外的函数,称为
ExtendeTable()
,它根据公共属性字段将NumPy数组的内容连接到现有表,这个函数相当于表连接,但位于表和NumPy数组之间。
arcpy.da模块的
FeatureClassToNumPyArray()
函数示例说明了这些函数的用法,该函数的语法如下:
此函数的第一个必需参数是输入要素类、图层、表格或表格视图,第二个必需参数是字段名称的列表或元组。字符串可用于单个字段。 可以使用星号(*)访问所有字段,但通常不建议使用此用法。为了提高性能,应该将字段缩小到当前任务所需的Aeld。可以使用几何标记(例如:[email protected]),但不是完整的几何体对象(即[email protected]),这个参数与arcpy.da模块游标类中使用的参数类似。创建光标对象时,第一个参数是要素类、图层、表或表视图,第二个参数是字段名称(包括几何图形标记)的列表或元组。
以下示例脚本将要素类的字段转换为NumPy数组,并确定一个简单的统计信息:
import arcpy
import numpy
input = "C:/Data/Usa.gdb/Counties"
c_array = arcpy.da.FeatureClassToNumPyArray(input,("POP2010"))
print(c_array["POP2010"].sum())
使用ArcGIS Pro中的工具或不使用NumPy的简单Python脚本进行计算非常简单,但NumPy通常速度更快,并且包含ArcPy中没有的其他功能。以下示例使用
corrcoeff()
函数确定数据库表中两个变量之间的二元相关系数:
import arcpy
import numpy
input = "C:/Project/health.dbf"
field1 = "VAR3"
field2 = "VAR4"
h_array = arcpy.da.TableToNumPyArray(input, (field1, field2))
print(numpy.corrcoef((h_array[field1], array[field2]))[0][1])
在此脚本中,ArcPy的
TableToNumPyArray()
函数用于基于两个感兴趣的字段创建二维NumPy数组,NumPy的
corrcoeff()
函数用来在数组的两个轴之间创建二元相关矩阵。因为该函数返回一个2×2矩阵(以数组的形式),所以末尾的两个索引仅用于获得一个感兴趣的值,即单个相关系数。
为了处理地理数据,我们通常需要一个结构化数组,其中包括字段或结构(structs),以将数据映射到表中的字段。以下是结构化阵列的简单示例:
import numpy
a = numpy.array([(1, 2.4, "Hello"), (2, 3.7, "World")],dtype=[("field0", "int32"), ("field1", "float32"), ("field2", (str, 10))])
为了将其分解,此数组中的每个元素都是包含三个元素的记录,这些元素已被指定为默认字段名称,field0、field1和field2。数据类型是32位整数、32位浮点数和10个字符或更少的字符串。注意值是如何作为元组输入的,因此它只是一个维度,结果是一个长度为2的一维数组。
NumPy中有许多数据类型,有时使用令人困惑的符号。例如,int32通常写成i4,float64通常写成f8,依此类推。
Working with NumPy in ArcGIS 中举例详细介绍了使用结构化数组创建地理数据作为NumPy数组 ,然后将其转换为要素类。
import arcpy
import numpy
outfc = "C:/Data/Texas.gdb/fd/pointlocations"
pt_array = numpy.array([(1, (471316.38, 5000448.78)),
(2, (470402.49, 5000049.21))],
numpy.dtype([("idfield", numpy.int32),
("XY", "<f8", 2)]))
sr = arcpy.Describe("C:/Data/Texas.gdb/fd").spatialReference
arcpy.da.NumPyArrayToFeatureClass(pt_array, outfc, ["XY"], sr)
NumPy数组由一个二维数组组成,其中包含ID 字段的值和具有x,y坐标的元组,NumPyArrayToFeatureClass()函数用于从阵列创建要素类。虽然将阵列转换为要素类的情况不如将阵列转换成要素类的常见,但示例语法有助于理解如何为地理数据创建结构化阵列。