最基础的知识
什么是数组?
数组是 NumPy 库的核心数据结构。数组是网格化的值,它包含有关原始数据、如何定位元素以及如何解释元素的信息。它有一个可以以各种方式索引的元素网格。元素都是相同的类型,称为数组dtype。
数组可以通过非负整数元组、布尔值、另一个数组或整数来索引。数组的rank是维数。shape数组的结果是一个整数元组,给出了数组沿每个维度的大小。
NumPy 中的索引从 0 开始。
Python 列表和 NumPy 数组有什么区别?
虽然 Python 列表可以在单个列表中包含不同的数据类型,但 NumPy 数组中的所有元素都应该是同质的。如果数组不是同质的,则打算在数组上执行的数学运算将非常低效。
NumPy 数组比 Python 列表更快、更紧凑。数组占用内存少,使用方便。NumPy 使用更少的内存来存储数据,它提供了一种指定数据类型的机制,这允许进一步优化代码。
关于数组的更多信息
我们可能偶尔会听到称为“ndarray”的数组,它是“N-dimensional array”的简写。N 维数组只是具有任意维数的数组。您可能还会听到1-D或一维数组、2-D或二维数组等。NumPy ndarray类用于表示matrix和vector。vector是一维数组(行向量和列向量没有区别),而matrix是指二维数组。对于3-D或更高维的数组,术语tensor也很常用。
数组的属性是什么?
数组通常是具有相同类型和大小的items的固定大小容器。数组中的维数和项数由其形状定义。数组的形状是指定每个维度大小的非负整数元组。
在 NumPy 中,维度称为轴。这意味着如果有一个如下所示的二维数组:
[[0., 0., 0.],
[1., 1., 1.]]
阵列有 2 个轴。第一个轴的长度为 2,第二个轴的长度为 3。
就像在其他 Python 容器对象中一样,可以通过索引或切片数组来访问和修改数组的内容。与典型的容器对象不同,不同的数组可以共享相同的数据,因此对一个数组所做的更改可能会在另一个数组中可见。
数组属性反映了数组本身固有的信息。如果需要在不创建新数组的情况下获取甚至设置数组的属性,通常可以通过其属性访问数组。
导入numpy
将numpy缩写为np是约定好的
import numpy as np
如何创建一个基本数组
数组的类型可以在创建时显式指定
np.array()
要创建 NumPy 数组,可以使用函数np.array().
创建一个简单数组所需要做的就是将一个列表传递给它,还可以指定列表中的数据类型。
>>> import numpy as np
>>> a = np.array([1, 2, 3])
注意,这些可视化的示意图旨在简化想法并让我们对 NumPy 概念和机制有基本的了解。数组和数组操作比这里捕获的要复杂得多!
np.zeros()
创建一个用0’s 填充的数组:
>>> np.zeros(2)
array([0., 0.])
np.empty()
empty函数创建一个数组,它里面的初始内容是随机的,取决于内存的状态。我们使用empty, zeros方法是因为速度快——只需后面填充每个元素。
>>> np.empty(2) # 创建带两个元素的空数组
array([1., 1.])
np.arrange()
创建一个含一系列元素或一系列相同间隔的数组
>>> np.arange(4)
array([0, 1, 2, 3])
>>> np.arange(2, 9, 2) # start, end, step
array([2, 4, 6, 8])
np.linspace()
它创建数组,自动计算每个元素的线性间隔
>>> np.linspace(0, 10, num=5)
array([ 0. , 2.5, 5. , 7.5, 10. ])
np.ones()
创建一个全1的数组,虽然默认数据类型是浮点 (np.float64),但可以使用关键字dtype明确指定想要的数据类型。
>>> x = np.ones(2)
>>> x
array([1., 1.])
>>> y = np.ones(2, dtype=np.int64)
>>> y
array([1, 1], dtype=int64)
数组元素添加、删除、排序
数组排序
np.sort()
在调用该函数时指定axis,kind,order,它返回的深拷贝之后排序序列
>>> arr = np.array([2,6,8,1])
>>> sortArr = np.sort(arr)
>>> sortArr
array([1, 2, 6, 8])
>>> sortArr is arr
False
>>> sortArr.base is arr
False
源码定义
参数分析
numpy.sort(a, axis=- 1, kind=None, order=None)
'''
返回数组的排序副本。
参数
a:array_like
要排序的数组。
axis:int or None, optional
要排序的轴。如果为 None,则数组在排序前被展平。默认值为 -1,沿最后一个轴排序。
kind:{‘quicksort’, ‘mergesort’, ‘heapsort’, ‘stable’}, optional
排序算法。默认值为“快速排序”。请注意,'stable' 和 'mergesort' 都在后台使用 timsort 或 radix 排序,通常,实际实现会因数据类型而异。保留“mergesort”选项是为了向后兼容。在 1.15.0 添加了“stable”选项。
order:str or list of str, optional
当a是定义了字段的数组时,该参数指定首先比较哪些字段,第二个等。单个字段可以指定为字符串,不需要指定所有字段,但仍会使用未指定的字段。
Returns
sorted_array ndarray
与a具有相同类型和形状的数组。
'''
各种排序算法的特点是它们的平均速度、最坏情况下的性能、工作空间大小以及它们是否稳定。稳定的排序使具有相同键的项目保持相同的相对顺序。NumPy 中实现的四种算法具有以下属性:
kind | speed | wort case | work space | stable |
---|---|---|---|---|
quicksort(快速排序) | 1 | O(n^2) | 0 | no |
heapsort(堆排序) | 3 | O(n*log(n)) | 0 | no |
mergesort(归并排序) | 2 | O(n*log(n)) | ~n/2 | yes |
timsort | 2 | O(n*log(n)) | ~n/2 | yes |
数据类型决定了实际使用的是“mergesort”还是“timsort”,即使指定了“mergesort”。
复数的排序顺序是字典顺序。如果实部和虚部都不是nan,则顺序由实部确定,除非它们相等,在这种情况下,顺序由虚部确定。
在 numpy 1.4.0 之前,对包含 nan 值的实数和复数数组进行排序会导致未定义的行为。在 numpy 版本中 >= 1.4.0 nan 值被排序到最后。扩展排序顺序为:
实部:[R,nan]
虚部:[R + Rj,R + nanj,nan + Rj,nan + nanj]
其中 R 是一个非 nan 实数值。具有相同 nan 位置的复杂值根据 non-nan 部分(如果存在)进行排序。非 nan 值像以前一样排序。
1.12.0 版本中的新功能
快速排序已更改为introsort。当排序没有取得足够的进展时,它会切换到 heapsort。此实现在最坏的情况下使快速排序 O(n*log(n))。
‘stable’ 自动为被排序的数据类型选择最稳定的排序算法。它与 ‘mergesort’ 目前 根据数据类型映射到timsort 或radix sort 。API 前向兼容性目前限制了选择实现的能力,并且对于不同的数据类型是硬连线的。
1.17.0版本中的新功能
添加 Timsort 是为了在已排序或几乎排序的数据上获得更好的性能。在随机数据上,timsort 几乎与 mergesort 相同。它现在用于稳定排序,而如果没有选择快速排序,它仍然是默认排序。‘mergesort’ 和 ‘stable’ 映射到整数数据类型的基数排序。基数排序是 O(n) 而不是 O(n log n)。
1.18.0 版中的更改。
NaT 现在排序到数组的末尾以与 NaN 保持一致。
例子
>>> a = np.array([[1, 4], [3, 1]])
>>> np.sort(a) # 沿最后一个轴排序
array([[1, 4],
[1, 3]])
>>> np.sort(a, axis=None) # 对展平的数组进行排序
array([1, 1, 3, 4])
>>> np.sort(a, axis=0) # 沿第一个轴排序
array([[1, 1],
[3, 4]])
使用order关键字指定在对结构化数组进行排序时要使用的字段:
>>> dtype = [('name', 'S10'), ('height', float), ('age', int)]
>>> value = [('Arthur', 1.8, 41), ('Lancelot', 1.9, 38), ('Galahad', 1.7, 38)]
>>> a = np.array(value, dtype=dtype) # 创建结构化数组
>>> a
array([(b'Arthur', 1.8, 41), (b'Lancelot', 1.9, 38),
(b'Galahad', 1.7, 38)],
dtype=[('name', 'S10'), ('height', '<f8'), ('age', '<i4')])
>>> np.sort(a, order='height')
array([(b'Galahad', 1.7, 38), (b'Arthur', 1.8, 41),
(b'Lancelot', 1.9, 38)],
dtype=[('name', 'S10'), ('height', '<f8'), ('age', '<i4')])
按年龄排序,如果年龄相等,则按身高排序:
>>> np.sort(a, order=['age', 'height'])
array([(b'Galahad', 1.7, 38), (b'Lancelot', 1.9, 38),
(b'Arthur', 1.8, 41)],
dtype=[('name', 'S10'), ('height', '<f8'), ('age', '<i4')])
np.argsort()
沿指定轴的间接排序,返回将对数组进行排序的索引。
使用kind关键字指定的算法沿给定轴执行间接排序。它返回一个索引数组,其形状与索引数据沿给定轴按排序顺序排列。
源码定义
参数分析
numpy.argsort(a, axis=- 1, kind=None, order=None)[source]
参数
a: array_like
要排序的数组。
axis: int or None, optional
要排序的轴。默认值为 -1(最后一个轴)。如果为 None,则使用展平数组。
kind: {‘quicksort’, ‘mergesort’, ‘heapsort’, ‘stable’}, optional
排序算法
order: str or list of str, optional
当a是定义了字段的数组时,该参数指定首先比较哪些字段,第二个等。单个字段可以指定为字符串,不需要指定所有字段,但仍会使用未指定的字段。
Returns
index_array: ndarray, int
沿指定轴对a进行排序的索引数组。如果a是一维的,则产生一个已排序的a。更一般地说,无论维度如何, 总是产生排序的a 。
例子
一维数组:
>>> x = np.array([3, 1, 2])
>>> np.argsort(x)
array([1, 2, 0], dtype=int64)
二维数组:
>>> x = np.array([3, 1, 2])
>>> np.argsort(x)
array([1, 2, 0], dtype=int64)
>>> x = np.array([[0, 3], [2, 2]])
>>> x
array([[0, 3],
[2, 2]])
>>> ind = np.argsort(x, axis=0) # 沿第一轴排序(纵)
>>> ind
array([[0, 1],
[1, 0]], dtype=int64)
>>> np.take_along_axis(x, ind, axis=0) # 与 np.sort(x, axis=0) 相同
array([[0, 2],
[2, 3]])
>>> ind = np.argsort(x, axis=1) # 沿最后一个轴(横)排序
>>> ind
array([[0, 1],
[0, 1]], dtype=int64)
>>> np.take_along_axis(x, ind, axis=1) # 与 np.sort(x, axis=1) 相同
array([[0, 3],
[2, 2]])
N 维数组的已排序元素的索引:
>>> ind = np.unravel_index(np.argsort(x, axis=None), x.shape)
>>> ind
(array([0, 1, 1, 0], dtype=int64), array([0, 0, 1, 1], dtype=int64))
>>> x[ind] # 同np.sort(x, axis=None)
array([0, 2, 2, 3])
按键排序:
>>> x = np.array([(1, 0), (0, 1)], dtype=[('x', '<i4'), ('y', '<i4')])
>>> x
array([(1, 0), (0, 1)], dtype=[('x', '<i4'), ('y', '<i4')])
>>> np.argsort(x, order=('x', 'y'))
array([1, 0], dtype=int64)
>>> np.argsort(x, order=('y', 'x'))
array([0, 1], dtype=int64)
np.lexsort()
使用一系列键执行间接稳定排序。
给定多个排序键(可以解释为电子表格中的列),lexsort 返回一个整数索引数组,该数组描述了多列的排序顺序。序列中的最后一个键用于主排序顺序,倒数第二个键用于辅助排序顺序,依此类推。keys 参数必须是可以转换为相同形状的数组的对象序列。如果为 keys 参数提供了二维数组,则其行被解释为排序键,并且根据最后一行、倒数第二行等进行排序。
参数分析
numpy.lexsort(keys, axis=- 1)
Parameters
keys: (k, N) 数组或包含 k (N,) 形序列的元组
要排序的k个不同的“列”。最后一列(如果键是二维数组,则为行)是主排序键。
axis: int, optional
要间接排序的轴。默认情况下,对最后一个轴进行排序。
Returns
indices: (N,) 整数数组
沿指定轴对键进行排序的索引数组。
例子
姓名排序:先按姓,再按名:
>>> surnames = ('Hertz', 'Galilei', 'Hertz')
>>> first_names = ('Heinrich', 'Galileo', 'Gustav')
>>> ind = np.lexsort((first_names, surnames))
>>> ind
array([1, 2, 0], dtype=int64)
>>> [surnames[i] + "," + first_names[i] for i in ind]
['Galilei,Galileo', 'Hertz,Gustav', 'Hertz,Heinrich']
对两列数字进行排序:
>>> a = [1,5,1,4,3,4,4]
>>> b = [9,4,0,4,0,2,1]
>>> ind = np.lexsort((b,a)) # 先对a排序,再对b排序
>>> ind
array([2, 0, 4, 6, 5, 3, 1], dtype=int64)
>>> [(a[i],b[i]) for i in ind]
[(1, 0), (1, 9), (3, 0), (4, 1), (4, 2), (4, 4), (5, 4)]
np.searchsorted()
在排序数组中查找元素。
查找应插入元素以保持顺序的索引。
找到排序数组a中的索引,这样,如果v中的相应元素插入到索引之前,则a的顺序将被保留。
假设a已排序:
side | returned index/ satisfies |
---|---|
left | a[i-1] < v <= a[i] |
right | a[i-1] <= v < a[i] |
源码定义
参数分析
numpy.searchsorted(a, v, side='left', sorter=None)
Parameters
a: 1-D array_like
输入数组。如果sorter为 None,则它必须按升序排序,否则sorter必须是对其进行排序的索引数组。
v: array_like
要插入的值。
side: {‘left’, ‘right’}, optional
如果'left',则给出找到的第一个合适位置的索引。如果'right',则返回最后一个此类索引。如果没有合适的索引,则返回 0 或 N(其中 N 是a的长度)。
sorter: 1-D array_like, optional
可选的整数索引数组,将数组 a 排序为升序。它们通常是 argsort 的结果。1.7.0 中的新功能。
Returns
indices: int or array of ints
与v形状相同的插入点数组,如果v是标量,则为整数。
例子
>>> np.searchsorted([1,2,3,4,5], 3)
2
>>> np.searchsorted([1,2,3,4,5], 3, side='right')
3
>>> np.searchsorted([1,2,3,4,5], [-10, 10, 2, 3])
array([0, 5, 1, 2], dtype=int64)
-10在0之前,10在5之后,2在2之前,3在3之前
np.partition()
部分排序
返回数组的分区副本。
创建数组的副本,其元素以这样的方式重新排列,即第 k 个位置的元素的值位于它在排序数组中的位置。所有小于第 k 个元素的元素都移到该元素之前,所有等于或大于第 k 个元素的元素都移到它后面。两个分区中元素的顺序未定义。
各种选择算法的特点是它们的平均速度、最坏情况下的性能、工作空间大小以及它们是否稳定。稳定的排序使具有相同键的项目保持相同的相对顺序。可用的算法具有以下属性:
kind | speed | worst case | work space | stable |
---|---|---|---|---|
introselect | 1 | O(n) | 0 | no |
当沿除最后一个轴以外的任何轴进行分区时,所有分区算法都会制作数据的临时副本。因此,沿最后一个轴的分区比沿任何其他轴的分区更快且使用的空间更少。
复数的排序顺序是字典顺序。如果实部和虚部都不是nan,则顺序由实部确定,除非它们相等,在这种情况下,顺序由虚部确定。
源码定义
参数分析
numpy.partition(a, kth, axis=- 1, kind='introselect', order=None)
Parameters
a: array_like
要排序的数组。
kth: int or sequence of ints
要分区的元素索引。元素的第 k 个值将处于其最终排序位置,所有较小的元素将移到它之前,所有相等或更大的元素都将移到它后面。分区中所有元素的顺序未定义。如果提供第 k 个序列,它将立即将由第 k 个索引的所有元素分区到它们的排序位置。
!!!1.22.0 版后已弃用:不推荐将布尔值作为索引传递。!!!
axis: int or None, optional
要排序的轴。如果为 None,则数组在排序前被展平。默认值为 -1,沿最后一个轴排序。
kind: {‘introselect’}, optional
选择算法。默认为“introselect”。
order: str or list of str, optional
当a是定义了字段的数组时,此参数指定要比较第一个、第二个等哪些字段。单个字段可以指定为字符串。并非所有字段都需要指定,但仍将使用未指定的字段,按照它们在 dtype 中出现的顺序来打破平局。
Returns
partitioned_array: ndarray
与a具有相同类型和形状的数组。
例子
>>> a = np.array([3, 4, 2, 1])
>>> np.partition(a, 3)
array([2, 1, 3, 4])
>>> np.partition(a, (1, 3))
array([1, 2, 3, 4])