• NumPy教程


    作者|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是矩阵中的列数。你刚才看到的是一个2x4矩阵。

    全零数组

    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 :','
    ',a)
    print('Dimensions :','
    ',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 :','
    ',a)
    print('Shape :','
    ',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 :','
    ',np.reshape(a,(3,-1)))
    print('Three columns :','
    ',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 :','
    ', a)
    print('Shape after flatten :',b.shape)
    print('Array :','
    ', b)
    print('Shape after ravel :',c.shape)
    print('Array :','
    ', 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','
    ','Shape',a.shape,'
    ',a)
    print('Expand along columns:','
    ','Shape',b.shape,'
    ',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数组时,我们得到了一个3x2数组。转置在线性代数中有着重要的意义。

    扩展和压缩一个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:','
    ','Shape',a.shape,'
    ',a)
    print('Expand along columns:','
    ','Shape',b.shape,'
    ',b)
    print('Expand along rows:','
    ','Shape',c.shape,'
    ',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','
    ','Shape',a.shape,'
    ',a)
    print('Squeeze array:','
    ','Shape',b.shape,'
    ',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','
    ','Shape',a.shape,'
    ',a)
    print('Squeeze array:','
    ','Shape',b.shape,'
    ',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 :','
    ',a[0:1,:])
    # 具有列的步长
    print('Alternate values from first row:','
    ',a[0:1,::2])
    # 
    print('Second column values :','
    ',a[:,1::2])
    print('Arbitrary values :','
    ',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 :','
    ',a[0,0,0])
    print('First array last column :','
    ',a[0,:,1])
    print('First two rows for second and third arrays :','
    ',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 :','
    ',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 :','
    ',a)
    print('Reversed array :','
    ',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 :','
    ',a)
    print('Reversed array vertically :','
    ',np.flip(a,axis=1))
    print('Reversed array horizontally :','
    ',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 :','
    ',a)
    print('Array 2 :','
    ',b)
    print('Vertical stacking :','
    ',np.vstack((a,b)))
    print('Horizontal stacking :','
    ',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 :','
    ',a)
    print('Array 2 :','
    ',b)
    print('Vertical stacking :','
    ',np.vstack((a,b)))
    print('Horizontal stacking :','
    ',np.hstack((a,b)))
    

    组合数组的另一个有趣的方法是使用dstack()方法。它按索引组合数组元素,并沿深度轴堆叠它们:

    a = [[1,2],[3,4]]
    b = [[5,6],[7,8]]
    c = np.dstack((a,b))
    print('Array 1 :','
    ',a)
    print('Array 2 :','
    ',b)
    print('Dstack :','
    ',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 :','
    ',a)
    print('Array 2 :','
    ',b)
    print('Concatenate along rows :','
    ',np.concatenate((a,b),axis=0))
    print('Concatenate along columns :','
    ',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 :','
    ',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在以下情况下兼容:

    1. 两者都有相同的尺寸

    2. 其中一个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 :','
    ',np.sort(a, kind='mergresort',axis=1))
    # 沿行排序
    print('Sort along row :','
    ',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.com/blog/2020/04/the-ultimate-numpy-tutorial-for-data-science-beginners/

    欢迎关注磐创AI博客站:
    http://panchuang.net/

    sklearn机器学习中文官方文档:
    http://sklearn123.com/

    欢迎关注磐创博客资源汇总站:
    http://docs.panchuang.net/

  • 相关阅读:
    Python爬取优质高清壁纸网站:彼岸
    xpath爬取喜马拉雅糗事播报音频地址
    Pyquery爬取豆瓣电影Top250
    pipenv虚拟环境
    pip报No module named 'pip'错怎么处理?
    SVN的使用
    测试报告
    软件测试分类
    测试模型
    软件开发过程模型
  • 原文地址:https://www.cnblogs.com/panchuangai/p/13207672.html
Copyright © 2020-2023  润新知