返回介绍

第21单元 创建数组

发布于 2024-01-28 22:01:16 字数 3093 浏览 0 评论 0 收藏 0

numpy数组比原生的Python列表更为紧凑和高效,尤其是在多维的情况下。但与列表不同的是,数组的语法要求更为严格:数组必须是同构的。这意味着数组项不能混合使用不同的数据类型,而且不能对不同数据类型的数组项进行匹配操作。

创建numpy数组的方法很多。可以使用函数array(),基于类数组(array-like)数据创建数组。所谓的类数组数据可以是列表、元组或另一个数组。numpy基于数据本身推断出数组元素的类型,当然,你也可以给array()传递确定的dtype参数。numpy支持的数据类型接近二十种,例如bool_、int64、uint64、float64和<U32(针对Unicode字符串)。

为获得较高的效率,numpy在创建一个数组时,不会将数据从源复制到新数组,而是建立起数据间的连接。也就是说,在默认情况下,numpy数组相当于是其底层数据的视图,而不是其副本。如果底层数据对象发生改变,则相应的数组数据也会随之改变。如果你不喜欢这种方式(这是默认的处理方式,除非复制的数据量过大),可以给构造函数传递copy=True。

 列表即数组,数组亦是数组

实际上,Python的“列表”(list)是以数组的方式实现的,而并非列表的方式2,这与“列表”(list)的字面含义并不一致。由于未使用前向指针,所以Python并没有给列表预留前向指针的存储空间。Python的大型列表只比“真正的”numpy数组多使用约13%的存储空间,但对于一些简单的内置操作,比如sum(),使用列表则要比数组快五到十倍。因此在使用numpy之前,应该问问自己是否真的需要用到某些numpy特有的功能!

2这里的列表实现方式可以理解为链表(linked list)。——译者注

接下来,我们来创建第一个数组——前10个正整数组成的简单数组:

   import numpy as np
   numbers = np.array(range(1, 11), copy=True)

➾ array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

函数ones()、zeros()和empty()分别构造全1数组、全零数组和尚未初始化的数组。这些函数必须有数组的形状参数,该参数用一个与数组的维度相同的列表或元组来表征。

   ones = np.ones([2, 4], dtype=np.float64)

➾ array([[ 1., 1., 1., 1.],[ 1., 1., 1., 1.]])

   zeros = np.zeros([2, 4], dtype=np.float64)

➾ array([[ 0., 0., 0., 0.],[ 0., 0., 0., 0.]])

   empty = np.empty([2, 4], dtype=np.float64)
   # 用这种方式创建的数组,其元素值不一定为零!

➾ array([[ 0., 0., 0., 0.],[ 0., 0., 0., 0.]])

numpy使用数组的ndim、shape和dtype属性分别存储数组的维数、形状和数据类型。

   ones.shape # 只要没有经过变形(reshape),该属性给出的就是数组的原始形状

➾ (2, 4)

   numbers.ndim # 等价于len(numbers.shape)

➾ 1

   zeros.dtype

➾ dtype('float64')

函数eye(N, M=None, k=0, dtype=np.float)用于构造一个N×M的眼形单位矩阵,其第k对角线上的值为1,其他地方的值为零。当k为正数时,对应的对角线位于主对角线上方的第k条。M为None(默认值)等价于M=N。

   eye = np.eye(3, k=1)

➾ array([[ 0., 1., 0.],[ 0., 0., 1.],[ 0., 0., 0.]])

当需要将几个矩阵相乘时,可以使用单位矩阵作为乘法链累积器中的初始值。

除了经典的内置函数range()外,numpy有其独有的、更高效的生成等间隔数值数组的方式:函数arange([start,] stop [, step,], dtype=None)。

   np_numbers = np.arange(2, 5, 0.25)

➾ array([ 2. , 2.25, 2.5 , 2.75, 3. , 3.25, 3.5 , 3.75, 4. ,4.25, 4.5 , 4.75])

和range()函数一样,stop的值可以小于start,但必须保证step为负数且数组中的数值按顺序减小。

numpy会在创建数组时记录每一项的数据类型,不过该数据类型并非不可变的。可在数组创建后,调用函数astype(dtype, casting ="unsafe", copy=True)来改变它。对于类型缩小的情况(将较抽象的数据类型转换为更具体的数据类型),可能会丢失一些信息。这并非numpy特有的,任何缩小变换都可能会丢失信息。

   np_inumbers = np_numbers.astype(np.int)

➾ array([2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4])

大多数numpy操作(例如第22单元讨论的转置操作)返回的是一个视图,而非原始数组的副本。为了保留原始数据,可使用copy()函数创建现有数组的副本。这样一来,对原始数组的任何更改都不会影响到副本。但如果数组较为庞大,比如有十亿个数组项,那就不要轻易进行复制。

np_inumbers_copy = np_inumbers.copy()

现在,让我们向更加高级的操作迈进。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文