作者 |ANIRUDDHA BHANDARI
编译 |VK
来源 |Analytics Vidhya
概述
- NumPy 是一个 Python 库,每个数据科学专业人员都应该熟悉它
- 这个全面的 NumPy 教程从头开始介绍 NumPy,从基本的数学运算到 NumPy 如何处理图像数据
- 本文中有大量的 Numpy 概念和 Python 代码
介绍
我非常喜欢 Python 中的 NumPy 库。在我的数据科学之旅中,我无数次依赖它来完成各种任务,从基本的数学运算到使用它进行图像分类!
简而言之,NumPy 是 Python 中最基本的库之一,也许是其中最有用的库。NumPy 高效地处理大型数据集。作为一名数据科学家或一名有抱负的数据科学专业人士,我们需要对 NumPy 及其在 Python 中的工作原理有一个扎实的掌握。
在本文中,我将首先描述一下 NumPy 库是什么,以及为什么你应该选择它而不是繁琐的 Python 列表。然后,我们将介绍一些最基本的 NumPy 操作,这些操作将使你喜欢这个很棒的库!
目录
- NumPy 库是什么?
- Python 列表与 NumPy 数组有什么区别?
-
创建 NumPy 数组
- 基本的 ndarray
- 全零数组
- 全一数组
- ndarray 中的随机数
- 定制的数组
- NumPy 的 Imatrix
- 等间距的 ndarray
-
NumPy 数组的形状与重塑
- NumPy 数组的维数
- NumPy 数组的形状
- NumPy 数组的大小
- 重塑 NumPy 数组
- 展开 NumPy 数组
- NumPy 数组的转置
-
扩展和压缩一个 NumPy 数组
- 展开 NumPy 数组
- 压缩 NumPy 数组
-
NumPy 数组的索引与切片
- 一维数组的切片
- 二维数组切片
- 三维数组切片
- NumPy 数组的负切片
-
堆叠和级联 Numpy 数组
- 堆叠 ndarrays
- 级联 ndarrays
- Numpy 数组广播
- NumPy Ufuncs
-
用 NumPy 数组计算
- 平均值、中位数和标准差
- 最小最大值及其索引
- 在 NumPy 数组中排序
- NumPy 数组和图像
NumPy 库是什么?
NumPy 是 Python 数值库,是 Python 编程中最有用的科学库之一。它支持大型多维数组对象和各种工具。各种其他的图书馆,如 Pandas、Matplotlib 和 Scikit-learn,都建立在这个令人惊叹的库之上。
数组是元素 / 值的集合,可以有一个或多个维度。一维数组称为向量,二维数组称为矩阵。
NumPy 数组称为 ndarray 或 N 维数组,它们存储相同类型和大小的元素。它以其高性能而闻名,并在数组规模不断扩大时提供高效的存储和数据操作。
下载 Anaconda 时,NumPy 会预先安装。但是如果你想在你的机器上单独安装 NumPy,只需在你的终端上键入以下命令:
pip install numpy
现在需要导入库:
import numpy as np
np 实际上是数据科学界使用的 NumPy 的缩写。
Python 列表与 NumPy 数组有什么区别?
如果你熟悉 Python,你可能会想,既然我们已经有了 Python 列表,为什么还要使用 NumPy 数组?毕竟,这些 Python 列表充当一个数组,可以存储各种类型的元素。这是一个完全正确的问题,答案隐藏在 Python 在内存中存储对象的方式中。
Python 对象实际上是一个指向内存位置的指针,该内存位置存储有关该对象的所有详细信息,如字节和值。尽管这些额外的信息使 Python 成为一种动态类型语言,但它也付出了代价,这在存储大量对象(如在数组中)时变得显而易见。
Python 列表本质上是一个指针数组,每个指针指向一个包含与元素相关信息的位置。这在内存和计算方面增加了很多开销。当列表中存储的所有对象都是同一类型时,大多数信息都是冗余的!
为了解决这个问题,我们使用只包含同构元素的 NumPy 数组,即具有相同数据类型的元素。这使得它在存储和操作数组方面更加高效。
当数组包含大量元素(比如数千或数百万个元素)时,这种差异就变得明显了。另外,使用 NumPy 数组,你可以执行元素操作,这是使用 Python 列表不可能做到的!
这就是为什么在对大量数据执行数学操作时,NumPy 数组比 Python 列表更受欢迎的原因。
创建 NumPy 数组
基本的 ndarray
考虑到 NumPy 数组解决的复杂问题,它很容易创建。要创建一个非常基本的 ndarray,可以使用 np.array() 方法。你只需将数组的值作为列表传递:
np.array([1,2,3,4])
输出:
array([1, 2, 3, 4])
此数组包含整数值。可以在 dtype 参数中指定数据类型:
np.array([1,2,3,4],dtype=np.float32)
输出:
array([1., 2., 3., 4.], dtype=float32)
由于 NumPy 数组只能包含同构数据类型,因此如果类型不匹配,则将向上转换值:
np.array([1,2.0,3,4])
输出:
array([1., 2., 3., 4.])
在这里,NumPy 将整数值上移到浮点值。
NumPy 数组也可以是多维的。
np.array([[1,2,3,4],[5,6,7,8]])
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
在这里,我们创建了一个二维数组。
注:矩阵只是一个 NxM 形状的数字矩形数组,其中 N 是行数,M 是矩阵中的列数。你刚才看到的是一个 2 ×4 矩阵。
全零数组
NumPy 允许你使用 np.zeros()方法。你只需传递所需数组的形状:
np.zeros(5)
array([0., 0., 0., 0., 0.])
上面一个是一维数组,下面一个是二维数组:
np.zeros((2,3))
array([[0., 0., 0.],
[0., 0., 0.]])
全一数组
你还可以使用 np.ones()方法获得全一数组:
np.ones(5,dtype=np.int32)
array([1, 1, 1, 1, 1])
ndarray 中的随机数
创建 ndarray 的另一个非常常用的方法是随机随机数方法。它创建一个给定形状的数组,其随机值来自[0,1]:
# 随机的
np.random.rand(2,3)
array([[0.95580785, 0.98378873, 0.65133872],
[0.38330437, 0.16033608, 0.13826526]])
定制的数组
或者,实际上,可以使用 np.full()方法。只需传入所需数组的形状和所需的值:
np.full((2,2),7)
array([[7, 7],
[7, 7]])
NumPy 的 Imatrix
另一个伟大的方法是 np.eye() 返回一个数组,其对角线上有 1,其他地方都有 0。
一个单位矩阵是一个正方形矩阵,它的主对角线上有 1,其他地方都有 0。下面是形状为 3x 3 的单位矩阵。
注:正方形矩阵是 N x N 的形状。这意味着它具有相同数量的行和列。
# 单位矩阵
np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
但是,NumPy 允许你灵活地更改对角线,值必须为 1。你可以将其移到主对角线上方:
# 不是单位矩阵
np.eye(3,k=1)
array([[0., 1., 0.],
[0., 0., 1.],
[0., 0., 0.]])
或将其移到主对角线下方:
np.eye(3,k=-2)
array([[0., 0., 0.],
[0., 0., 0.],
[1., 0., 0.]])
注:只有当 1 沿主对角线而不是任何其他对角线时,矩阵才称为单位矩阵!
等间距的 ndarray
你可以使用 np.arange() 方法:
np.arange(5)
array([0, 1, 2, 3, 4])
通过分别传递三个数字作为这些值的参数,可以显式定义值间隔的开始、结束和步长。这里要注意的一点是,间隔定义为[开始,结束),其中最后一个数字将不包含在数组中:
np.arange(2,10,2)
array([2, 4, 6, 8])
由于步长定义为 2,因此下图展示了输出的元素。注意,10 不会打印出来,因为它是最后一个元素。
另一个类似的功能是 np.linspace(),但它将从间隔中获取需要检索的样本数,而不是步长。这里要注意的一点是,最后一个数字包含在返回的值中,这与 np.arange()不同
np.linspace(0,1,5)
array([0. , 0.25, 0.5 , 0.75, 1.])
太好了!现在你知道了如何使用 NumPy 创建数组。但了解数组的形状也很重要。
NumPy 数组的形状与重塑
创建了 ndarray 之后,接下来要做的是检查 ndarray 的轴数、形状和大小。
NumPy 数组的维数
可以使用 ndims 属性轻松确定 NumPy 数组的维数或轴数:
# 轴数
a = np.array([[5,10,15],[20,25,20]])
print('Array :','\n',a)
print('Dimensions :','\n',a.ndim)
Array :
[[5 10 15]
[20 25 20]]
Dimensions :
2
这个数组有两个维度:2 行 3 列。
NumPy 数组的形状
形状是 NumPy 数组的一个属性,它显示每个维度上有多少行元素。你可以进一步索引 ndarray 返回的形状,以便沿每个维度获取值:
a = np.array([[1,2,3],[4,5,6]])
print('Array :','\n',a)
print('Shape :','\n',a.shape)
print('Rows =',a.shape[0])
print('Columns =',a.shape[1])
Array :
[[1 2 3]
[4 5 6]]
Shape :
(2, 3)
Rows = 2
Columns = 3
NumPy 数组的大小
可以使用 size 属性确定数组中有多少值。它只是将行数乘以 ndarray 中的列数:
# size of array
a = np.array([[5,10,15],[20,25,20]])
print('Size of array :',a.size)
print('Manual determination of size of array :',a.shape[0]*a.shape[1])
Size of array : 6
Manual determination of size of array : 6
重塑 NumPy 数组
可以使用 np.reshape() 方法。它在不更改 ndarray 中的数据的情况下更改 ndarray 的形状:
# 重塑
a = np.array([3,6,9,12])
np.reshape(a,(2,2))
array([[3, 6],
[9, 12]])
在这里,我将 ndarray 从一维重塑为二维 ndarray。
重塑时,如果你不确定任何轴的形状,只需输入 -1。当 NumPy 看到 - 1 时,它会自动计算形状:
a = np.array([3,6,9,12,18,24])
print('Three rows :','\n',np.reshape(a,(3,-1)))
print('Three columns :','\n',np.reshape(a,(-1,3)))
Three rows :
[[3 6]
[9 12]
[18 24]]
Three columns :
[[3 6 9]
[12 18 24]]
展开 NumPy 数组
有时,当你有多维数组并希望将其折叠为一维数组时,可以使用 flatten()方法或 ravel() 方法:
a = np.ones((2,2))
b = a.flatten()
c = a.ravel()
print('Original shape :', a.shape)
print('Array :','\n', a)
print('Shape after flatten :',b.shape)
print('Array :','\n', b)
print('Shape after ravel :',c.shape)
print('Array :','\n', c)
Original shape : (2, 2)
Array :
[[1. 1.]
[1. 1.]]
Shape after flatten : (4,)
Array :
[1. 1. 1. 1.]
Shape after ravel : (4,)
Array :
[1. 1. 1. 1.]
但是 flatten() 和 ravel()之间的一个重要区别是前者返回原始数组的副本,而后者返回对原始数组的引用。这意味着对 ravel()返回的数组所做的任何更改也将反映在原始数组中,而 flatten()则不会这样。
b[0] = 0
print(a)
[[1. 1.]
[1. 1.]]
所做的更改没有反映在原始数组中。
c[0] = 0
print(a)
[[0. 1.]
[1. 1.]]
但在这里,更改后的值也反映在原始 ndarray 中。
这里发生的事情是 flatten()创建了 ndarray 的深层副本,而 ravel()创建了 ndarray 的浅层副本。
深层副本意味着在内存中创建了一个全新的 ndarray,flatten()返回的 ndarray 对象现在指向这个内存位置。因此,此处所做的任何更改都不会反映在原始 ndarray 中。
另一方面,浅拷贝返回对原始内存位置的引用。这意味着 ravel()返回的对象指向与原始 ndarray 对象相同的内存位置。因此,毫无疑问,对该 ndarray 所做的任何更改也将反映在原始 ndarray 中。
NumPy 数组的转置
NumPy 的另一个非常有趣的重塑方法是 transpose() 方法。它接受输入数组并用列值交换行,用行值交换列值:
a = np.array([[1,2,3],
[4,5,6]])
b = np.transpose(a)
print('Original','\n','Shape',a.shape,'\n',a)
print('Expand along columns:','\n','Shape',b.shape,'\n',b)
Original
Shape (2, 3)
[[1 2 3]
[4 5 6]]
Expand along columns:
Shape (3, 2)
[[1 4]
[2 5]
[3 6]]
在转置一个 2x 3 数组时,我们得到了一个 3 ×2 数组。转置在线性代数中有着重要的意义。
扩展和压缩一个 NumPy 数组
展开 NumPy 数组
通过提供要展开的数组和轴,可以使用 expand_dims()方法将新轴添加到数组中:
# 展开维度
a = np.array([1,2,3])
b = np.expand_dims(a,axis=0)
c = np.expand_dims(a,axis=1)
print('Original:','\n','Shape',a.shape,'\n',a)
print('Expand along columns:','\n','Shape',b.shape,'\n',b)
print('Expand along rows:','\n','Shape',c.shape,'\n',c)
Original:
Shape (3,)
[1 2 3]
Expand along columns:
Shape (1, 3)
[[1 2 3]]
Expand along rows:
Shape (3, 1)
[[1]
[2]
[3]]
压缩 NumPy 数组
另一方面,如果希望减小数组的轴,请使用 squeeze() 方法。它将删除具有单个条目的轴。这意味着,如果创建了一个 2 x 2 x 1 矩阵,则 squeze()将从矩阵中删除第三个维度:
# squeeze
a = np.array([[[1,2,3],
[4,5,6]]])
b = np.squeeze(a, axis=0)
print('Original','\n','Shape',a.shape,'\n',a)
print('Squeeze array:','\n','Shape',b.shape,'\n',b)
Original
Shape (1, 2, 3)
[[[1 2 3]
[4 5 6]]]
Squeeze array:
Shape (2, 3)
[[1 2 3]
[4 5 6]]
但是,如果你已经有一个 2×2 的矩阵,在这种情况下使用 squeeze()会给你一个错误:
# squeeze
a = np.array([[1,2,3],
[4,5,6]])
b = np.squeeze(a, axis=0)
print('Original','\n','Shape',a.shape,'\n',a)
print('Squeeze array:','\n','Shape',b.shape,'\n',b)
NumPy 数组的索引与切片
到目前为止,我们已经看到了如何创建一个 NumPy 数组以及如何处理它的形状。在本节中,我们将看到如何使用索引和切片从数组中提取特定值。
一维数组的切片
切片意味着从一个索引检索元素到另一个索引。我们要做的就是像这样[start: end]
然而,你也可以定义步长。例如你可以将步长定义为 2,这意味着让元素远离当前索引 2 个位置进行取值。
将所有这些内容合并到一个索引中看起来像这样:[start:end:step-size]。
a = np.array([1,2,3,4,5,6])
print(a[1:5:2])
[2 4]
注意,没有考虑最后一个元素。这是因为切片包括开始索引,但不包括结束索引。
解决方法是将下一个更高的索引写入要检索的最终索引值:
a = np.array([1,2,3,4,5,6])
print(a[1:6:2])
[2 4 6]
如果不指定起始索引或结束索引,则默认值分别为 0 或数组大小。默认情况下步长为 1。
a = np.array([1,2,3,4,5,6])
print(a[:6:2])
print(a[1::2])
print(a[1:6:])
[1 3 5]
[2 4 6]
[2 3 4 5 6]
二维数组切片
现在,二维数组有行和列,所以对二维数组进行切片会有点困难。但是一旦你理解了它,你就可以分割任何维度数组!
在学习如何分割二维数组之前,让我们先看看如何从二维数组中检索元素:
a = np.array([[1,2,3],
[4,5,6]])
print(a[0,0])
print(a[1,2])
print(a[1,0])
1
6
4
在这里,我们提供了行值和列值来标识要提取的元素。在一维数组中,我们只提供列值,因为只有一行。
因此,要对二维数组进行切片,需要同时提到行和列的切片:
a = np.array([[1,2,3],[4,5,6]])
# 打印第一行值
print('First row values :','\n',a[0:1,:])
# 具有列的步长
print('Alternate values from first row:','\n',a[0:1,::2])
#
print('Second column values :','\n',a[:,1::2])
print('Arbitrary values :','\n',a[0:1,1:3])
First row values :
[[1 2 3]]
Alternate values from first row:
[[1 3]]
Second column values :
[[2]
[5]]
Arbitrary values :
[[2 3]]
三维数组切片
到目前为止我们还没有看到三维数组。首先让我们想象一下三维数组的样子:
a = np.array([[[1,2],[3,4],[5,6]],# 第一个轴数组
[[7,8],[9,10],[11,12]],# 第二个轴数组
[[13,14],[15,16],[17,18]]])# 第三个轴数组
# 3-D array
print(a)
[[[1 2]
[3 4]
[5 6]]
[[7 8]
[9 10]
[11 12]]
[[13 14]
[15 16]
[17 18]]]
除了行和列之外,在二维数组中,三维数组还有一个深度轴,在这个深度轴上,它将一个二维数组放在另一个数组后面。所以,当你在切片一个三维数组时,你还需要提到你要切片哪个二维数组。这通常作为索引中的第一个值出现:
# value
print('First array, first row, first column value :','\n',a[0,0,0])
print('First array last column :','\n',a[0,:,1])
print('First two rows for second and third arrays :','\n',a[1:,0:2,0:2])
First array, first row, first column value :
1
First array last column :
[2 4 6]
First two rows for second and third arrays :
[[[7 8]
[9 10]]
[[13 14]
[15 16]]]
如果希望将值作为一维数组,则可以始终使用 flatten()方法来完成此项工作!
print('Printing as a single array :','\n',a[1:,0:2,0:2].flatten())
Printing as a single array :
[7 8 9 10 13 14 15 16]
NumPy 数组的负切片
对数组进行切片的一个有趣的方法是使用负切片。负切片从末尾而不是开头打印元素。请看下面:
a = np.array([[1,2,3,4,5],
[6,7,8,9,10]])
print(a[:,-1])
[5 10]
这里,打印了每行的最后一个值。但是,如果我们想从末尾提取,我们必须显式地提供负步长,否则结果将是空列表。
print(a[:,-1:-3:-1])
[[5 4]
[10 9]]
尽管如此,切片的基本逻辑保持不变,即输出中从不包含结束索引。
负切片的一个有趣的用途是反转原始数组。
a = np.array([[1,2,3,4,5],
[6,7,8,9,10]])
print('Original array :','\n',a)
print('Reversed array :','\n',a[::-1,::-1])
Original array :
[[1 2 3 4 5]
[6 7 8 9 10]]
Reversed array :
[[10 9 8 7 6]
[5 4 3 2 1]]
也可以使用 flip() 方法来反转 ndarray。
a = np.array([[1,2,3,4,5],
[6,7,8,9,10]])
print('Original array :','\n',a)
print('Reversed array vertically :','\n',np.flip(a,axis=1))
print('Reversed array horizontally :','\n',np.flip(a,axis=0))
Original array :
[[1 2 3 4 5]
[6 7 8 9 10]]
Reversed array vertically :
[[5 4 3 2 1]
[10 9 8 7 6]]
Reversed array horizontally :
[[6 7 8 9 10]
[1 2 3 4 5]]
堆叠和级联 Numpy 数组
堆叠 ndarrays
可以通过组合现有数组来创建新数组。你可以通过两种方式来完成:
- 使用 vstack() 方法垂直组合数组(即沿行),从而增加结果数组中的行数
- 或者使用 hstack() 以水平方式(即沿列)组合数组,从而增加结果数组中的列数
a = np.arange(0,5)
b = np.arange(5,10)
print('Array 1 :','\n',a)
print('Array 2 :','\n',b)
print('Vertical stacking :','\n',np.vstack((a,b)))
print('Horizontal stacking :','\n',np.hstack((a,b)))
Array 1 :
[0 1 2 3 4]
Array 2 :
[5 6 7 8 9]
Vertical stacking :
[[0 1 2 3 4]
[5 6 7 8 9]]
Horizontal stacking :
[0 1 2 3 4 5 6 7 8 9]
这里要注意的一点是,组合数组的轴应该具有相同的大小,否则一定会出错!
a = np.arange(0,5)
b = np.arange(5,9)
print('Array 1 :','\n',a)
print('Array 2 :','\n',b)
print('Vertical stacking :','\n',np.vstack((a,b)))
print('Horizontal stacking :','\n',np.hstack((a,b)))
组合数组的另一个有趣的方法是使用 dstack()方法。它按索引组合数组元素,并沿深度轴堆叠它们:
a = [[1,2],[3,4]]
b = [[5,6],[7,8]]
c = np.dstack((a,b))
print('Array 1 :','\n',a)
print('Array 2 :','\n',b)
print('Dstack :','\n',c)
print(c.shape)
Array 1 :
[[1, 2], [3, 4]]
Array 2 :
[[5, 6], [7, 8]]
Dstack :
[[[1 5]
[2 6]]
[[3 7]
[4 8]]]
(2, 2, 2)
级联 ndarrays
虽然堆叠数组是组合旧数组以获得新数组的一种方法,但也可以使用 concatenate()方法,其中传递的数组沿现有轴连接:
a = np.arange(0,5).reshape(1,5)
b = np.arange(5,10).reshape(1,5)
print('Array 1 :','\n',a)
print('Array 2 :','\n',b)
print('Concatenate along rows :','\n',np.concatenate((a,b),axis=0))
print('Concatenate along columns :','\n',np.concatenate((a,b),axis=1))
Array 1 :
[[0 1 2 3 4]]
Array 2 :
[[5 6 7 8 9]]
Concatenate along rows :
[[0 1 2 3 4]
[5 6 7 8 9]]
Concatenate along columns :
[[0 1 2 3 4 5 6 7 8 9]]
此方法的缺点是原始数组必须具有要合并的轴。否则,准备好迎接错误。
另一个非常有用的函数是 append 方法,它将新元素添加到 ndarray 的末尾。当你已经有了一个现有的 ndarray,但希望向其添加新值时,这显然很有用。
# 将值附加到 ndarray
a = np.array([[1,2],
[3,4]])
np.append(a,[[5,6]], axis=0)
array([[1, 2],
[3, 4],
[5, 6]])
Numpy 数组广播
广播是 ndarrays 最好的功能之一。它允许你在不同大小的 ndarray 之间或 ndarray 与简单数字之间执行算术运算!
广播基本上延伸较小的 ndarray,使其与较大 ndarray 的形状相匹配:
a = np.arange(10,20,2)
b = np.array([[2],[2]])
print('Adding two different size arrays :','\n',a+b)
print('Multiplying an ndarray and a number :',a*2)
Adding two different size arrays :
[[12 14 16 18 20]
[12 14 16 18 20]]
Multiplying an ndarray and a number : [20 24 28 32 36]
它的工作可以看作是拉伸或复制标量,即数字,[2,2,2]以匹配 ndarray 的形状,然后按元素执行操作。但是实际上并没有生成该数组,这只是一种思考广播如何运作的方式。
这非常有用,因为用标量值乘一个数组比用另一个数组更有效!需要注意的是,只有当两个 ndarray 兼容时,它们才能一起广播。
Ndarrays 在以下情况下兼容:
- 两者都有相同的尺寸
- 其中一个 ndarrays 的维数是 1。尺寸为 1 的广播会满足尺寸更大的 ndarray 的大小要求
如果数组不兼容,你将得到一个 ValueError。
a = np.ones((3,3))
b = np.array([2])
a+b
array([[3., 3., 3.],
[3., 3., 3.],
[3., 3., 3.]])
在这里,假设第二个 ndarray 被拉伸成 3x 3 形状,然后计算结果。
NumPy Ufuncs
Python 是一种动态类型语言。这意味着在赋值时不需要知道变量的数据类型。Python 将在运行时自动确定它。虽然这意味着编写更干净、更容易的代码,但也会使 Python 变得迟缓。
当 Python 必须重复执行许多操作(比如添加两个数组)时,这个问题就会显现出来。这是因为每次需要执行操作时,Python 都必须检查元素的数据类型。使用 ufuncs 函数的 NumPy 可以解决这个问题。
NumPy 使这个工作更快的方法是使用向量化。向量化在编译的代码中以逐元素的方式对 ndarray 执行相同的操作。因此,不需要每次都确定元素的数据类型,从而执行更快的操作。
ufuncs 是 NumPy 中的通用函数,只是数学函数。它们执行快速的元素功能。当对 NumPy 数组执行简单的算术操作时,它们会自动调用,因为它们充当 NumPy ufuncs 的包装器。
例如,当使用“+”添加两个 NumPy 数组时,NumPy ufunc add()会在场景后面自动调用,并悄悄地发挥其魔力:
a = [1,2,3,4,5]
b = [6,7,8,9,10]
%timeit a+b
a = np.arange(1,6)
b = np.arange(6,11)
%timeit a+b
你可以看到,在 NumPy ufuncs 的帮助下,两个数组的相同添加是如何在更短的时间内完成的!
用 NumPy 数组计算
下面是一些最重要和最有用的操作,你将需要在你的 NumPy 数组上执行这些操作。
NumPy 数组的基本运算
基本的算术运算可以很容易地在 NumPy 数组上执行。要记住的重要一点是,这些简单的算术运算符号只是作为 NumPy ufuncs 的包装器。
print('Subtract :',a-5)
print('Multiply :',a*5)
print('Divide :',a/5)
print('Power :',a**2)
print('Remainder :',a%5)
Subtract : [-4 -3 -2 -1 0]
Multiply : [5 10 15 20 25]
Divide : [0.2 0.4 0.6 0.8 1.]
Power : [1 4 9 16 25]
Remainder : [1 2 3 4 0]
平均值、中位数和标准差
要查找 NumPy 数组的平均值和标准偏差,请使用 mean()、std()和 median()方法:
a = np.arange(5,15,2)
print('Mean :',np.mean(a))
print('Standard deviation :',np.std(a))
print('Median :',np.median(a))
Mean : 9.0
Standard deviation : 2.8284271247461903
Median : 9.0
最小最大值及其索引
使用 Min()和 Max()方法可以轻松找到 ndarray 中的 Min 和 Max 值:
a = np.array([[1,6],
[4,3]])
# 最小值
print('Min :',np.min(a,axis=0))
# 最大值
print('Max :',np.max(a,axis=1))
Min : [1 3]
Max : [6 4]
还可以使用 argmin()和 argmax()方法轻松确定 ndarray 中沿特定轴的最小值或最大值的索引:
a = np.array([[1,6,5],
[4,3,7]])
# 最小值
print('Min :',np.argmin(a,axis=0))
# 最大值
print('Max :',np.argmax(a,axis=1))
Min : [0 1 0]
Max : [1 2]
让我给你把输出分解一下。第一列的最小值是该列的第一个元素。对于第二列,它是第二个元素。对于第三列,它是第一个元素。
类似地,你可以确定最大值的输出指示什么。
在 NumPy 数组中排序
对于任何程序员来说,任何算法的时间复杂性都是最重要的。排序是一项重要且非常基本的操作,作为一名数据科学家,你可能每天都会用到它。因此,采用一种时间复杂度最小的排序算法是非常重要的。
当谈到排序数组元素时,NumPy 库有一系列排序函数,可用于对数组元素进行排序。当你使用 sort()方法时,它已经为你实现了快速排序、堆排序、合并排序和时间排序:
a = np.array([1,4,2,5,3,6,8,7,9])
np.sort(a, kind='quicksort')
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
你甚至可以沿着你想要的任何轴对数组进行排序:
a = np.array([[5,6,7,4],
[9,2,3,7]])# 沿列排序
print('Sort along column :','\n',np.sort(a, kind='mergresort',axis=1))
# 沿行排序
print('Sort along row :','\n',np.sort(a, kind='mergresort',axis=0))
Sort along column :
[[4 5 6 7]
[2 3 7 9]]
Sort along row :
[[5 2 3 4]
[9 6 7 7]]
NumPy 数组和图像
NumPy 数组在存储和操作图像数据方面有着广泛的用途。但图像数据到底是什么呢?
图像由以数组形式存储的像素组成。每个像素的值介于 0 到 255 之间–0 表示黑色像素,255 表示白色像素。
彩色图像由三个二维数组组成,每个彩色通道一个:红色、绿色和蓝色,背靠背放置,从而形成三维数组。数组中的每个值构成一个像素值。因此,数组的大小取决于每个维度上的像素数。
请看下图:
Python 可以使用 scipy.misc.imread() 方法(SciPy 库中的方法)。当我们输出它时,它只是一个包含像素值的三维数组:
import numpy as np
import matplotlib.pyplot as plt
from scipy import misc
# 读取图像
im = misc.imread('./original.jpg')
# 图像
im
array([[[115, 106, 67],
[113, 104, 65],
[112, 103, 64],
...,
[160, 138, 37],
[160, 138, 37],
[160, 138, 37]],
[[117, 108, 69],
[115, 106, 67],
[114, 105, 66],
...,
[157, 135, 36],
[157, 135, 34],
[158, 136, 37]],
[[120, 110, 74],
[118, 108, 72],
[117, 107, 71],
...,
我们可以检查这个 NumPy 数组的形状和类型:
print(im.shape)
print(type(type))
(561, 997, 3)
numpy.ndarray
现在,由于图像只是一个数组,我们可以使用本文中介绍的数组函数轻松地对其进行操作。比如,我们可以使用 np.flip() 方法:
# 翻转
plt.imshow(np.flip(im, axis=1))
或者你可以规范化或更改像素值的范围。这有时对更快的计算很有用。
im/255
array([[[0.45098039, 0.41568627, 0.2627451],
[0.44313725, 0.40784314, 0.25490196],
[0.43921569, 0.40392157, 0.25098039],
...,
[0.62745098, 0.54117647, 0.14509804],
[0.62745098, 0.54117647, 0.14509804],
[0.62745098, 0.54117647, 0.14509804]],
[[0.45882353, 0.42352941, 0.27058824],
[0.45098039, 0.41568627, 0.2627451],
[0.44705882, 0.41176471, 0.25882353],
...,
[0.61568627, 0.52941176, 0.14117647],
[0.61568627, 0.52941176, 0.13333333],
[0.61960784, 0.53333333, 0.14509804]],
[[0.47058824, 0.43137255, 0.29019608],
[0.4627451 , 0.42352941, 0.28235294],
[0.45882353, 0.41960784, 0.27843137],
...,
[0.6 , 0.52156863, 0.14117647],
[0.6 , 0.52156863, 0.13333333],
[0.6 , 0.52156863, 0.14117647]],
...,
请记住,这是使用我们在文章中看到的 ufuncs 和广播的相同概念!
当你使用神经网络对图像进行分类时,你可以做更多的事情来操作你的图像。
结尾
我们在这篇文章中涉及了很多方面。希望你对 NumPy 数组的使用非常熟悉,并且非常热衷于将其融入到日常的分析任务中。
要了解更多关于任何 NumPy 函数的信息,请查看他们的官方文档,在那里你可以找到每个函数的详细描述。
文档链接:https://numpy.org/doc/
原文链接:https://www.analyticsvidhya.c…
欢迎关注磐创 AI 博客站:
http://panchuang.net/
sklearn 机器学习中文官方文档:
http://sklearn123.com/
欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/