003:NumPy的应⽤-1

        Numpy 是⼀个开源的 Python 科学计算库, ⽤于快速处理任意维度的数组 Numpy ⽀持常⻅的数组和矩阵操 ,对于同样的数值计算任务,使⽤ NumPy 不仅代码要简洁的多,⽽且 NumPy 的性能远远优于原⽣ Python ,基本是⼀个到两个数量级的差距,⽽且数据量越⼤,NumPy 的优势就越明显。
        NumPy 最为核⼼的数据类型是 ndarray ,使⽤ ndarray 可以处理⼀维、⼆维和多维数组,该对象相当于是⼀个快速⽽灵活的⼤数据容器。NumPy 底层代码使⽤ C 语⾔编写,解决了 GIL 的限制, ndarray 在存取数据的时候,数据与数据的地址都是连续的,这确保了可以进⾏⾼效率的批量操作,远远优于 Python 中的 list ;另⼀⽅⾯ ndarray 对象提供了更多的⽅法来处理数据,尤其是和统计相关的⽅法,这些⽅法也是 Python 原⽣的 list 没有的。
        准备⼯作
1. 启动 Notebook
jupyter notebook
        提示:在启动 Notebook 之前,建议先安装好数据分析相关依赖项,包括之前提到的三⼤神器以及相关依赖项,包括: numpy pandas matplotlib openpyxl 等。如果使⽤ Anaconda ,则⽆需单独安装。
2. 导⼊
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
        说明:如果已经启动了 Notebook 但尚未安装相关依赖库,例如尚未安装 numpy ,可以在 Notebook的单元格中输⼊ !pip install numpy 并运⾏该单元格来安装 NumPy ,也可以⼀次性安装多个三⽅库,需要在单元格中输⼊ %pip install numpy pandas matplotlib 。注意上⾯的代码,我们不仅导⼊了NumPy ,还将 pandas matplotlib 库⼀并导⼊了。
        创建数组对象
        创建 ndarray 对象有很多种⽅法,下⾯就如何创建⼀维数组、⼆维数组和多维数组进⾏说明。
        ⼀维数组
⽅法⼀:使⽤ array 函数,通过 list 创建数组对象
代码:
array1 = np.array([1, 2, 3, 4, 5])
array1
输出:
array([1, 2, 3, 4, 5])
⽅法⼆:使⽤ arange 函数,指定取值范围创建数组对象
代码:
array2 = np.arange(0, 20, 2)
array2
输出:
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
⽅法三:使⽤ linspace 函数,⽤指定范围均匀间隔的数字创建数组对象
代码:
array3 = np.linspace(-5, 5, 101)
array3
输出:
array([-5. , -4.9, -4.8, -4.7, -4.6, -4.5, -4.4, -4.3, -4.2, -4.1, -4. ,
 -3.9, -3.8, -3.7, -3.6, -3.5, -3.4, -3.3, -3.2, -3.1, -3. , -2.9,
 -2.8, -2.7, -2.6, -2.5, -2.4, -2.3, -2.2, -2.1, -2. , -1.9, -1.8,
 -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1. , -0.9, -0.8, -0.7,
 -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0. , 0.1, 0.2, 0.3, 0.4,
 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2, 1.3, 1.4, 1.5,
 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6,
 2.7, 2.8, 2.9, 3. , 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7,
 3.8, 3.9, 4. , 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8,
 4.9, 5. ])
⽅法四:使⽤ numpy.random 模块的函数⽣成随机数创建数组对象
产⽣ 10 个范围的随机⼩数,代码:
array4 = np.random.rand(10)
array4
输出:
array([0.45556132, 0.67871326, 0.4552213 , 0.96671509, 0.44086463,
 0.72650875, 0.79877188, 0.12153022, 0.24762739, 0.6669852 ])
产⽣ 10 个[1,100)范围的随机整数,代码:
array5 = np.random.randint(1, 100, 10)
array5
输出:
array([29, 97, 87, 47, 39, 19, 71, 32, 79, 34])

array6 = np.random.normal(50, 10, 20)
array6

 输出:

array([55.04155586, 46.43510797, 20.28371158, 62.67884053, 61.23185964,
 38.22682148, 53.17126151, 43.54741592, 36.11268017, 40.94086676,
 63.27911699, 46.92688903, 37.1593374 , 67.06525656, 67.47269463,
 23.37925889, 31.45312239, 48.34532466, 55.09180924, 47.95702787])
说明 :创建⼀维数组还有很多其他的⽅式,⽐如通过读取字符串、读取⽂件、解析正则表达式等⽅式,这⾥我们暂不讨论这些⽅式,有兴趣的读者可以⾃⾏研究。
⼆维数组
⽅法⼀:使⽤ array 函数,通过嵌套的 list 创建数组对象
代码:
array7 = np.array([[1, 2, 3], [4, 5, 6]])
array7
输出:
array([[1, 2, 3],
 [4, 5, 6]])
⽅法⼆:使⽤ zeros ones full 函数指定数组的形状创建数组对象
使⽤ zeros 函数,代码:
array8 = np.zeros((3, 4))
array8
输出:
array([[0., 0., 0., 0.],
 [0., 0., 0., 0.],
 [0., 0., 0., 0.]])
使⽤ ones 函数,代码:
array9 = np.ones((3, 4))
array9
输出:
array([[1., 1., 1., 1.],
 [1., 1., 1., 1.],
 [1., 1., 1., 1.]])
使⽤ full 函数,代码:
array10 = np.full((3, 4), 10)
array10
输出:
array([[10, 10, 10, 10],
 [10, 10, 10, 10],
 [10, 10, 10, 10]])
⽅法三:使⽤ eye 函数创建单位矩阵
代码:
array11 = np.eye(4)
array11
输出:
array([[1., 0., 0., 0.],
 [0., 1., 0., 0.],
 [0., 0., 1., 0.],
 [0., 0., 0., 1.]])
⽅法四:通过 reshape 将⼀维数组变成⼆维数组
代码:
array12 = np.array([1, 2, 3, 4, 5, 6]).reshape(2, 3)
array12
输出:
array([[1, 2, 3],
 [4, 5, 6]])
提示 reshape ndarray 对象的⼀个⽅法,使⽤ reshape ⽅法时需要确保调形后的数组元素个数与调形前数组元素个数保持⼀致,否则将会产⽣异常。
⽅法五:通过 numpy.random 模块的函数⽣成随机数创建数组对象
产⽣[0,1)范围的随机⼩数构成的3 4 列的⼆维数组,代码:
array13 = np.random.rand(3, 4)
array13
输出:
array([[0.54017809, 0.46797771, 0.78291445, 0.79501326],
 [0.93973783, 0.21434806, 0.03592874, 0.88838892],
 [0.84130479, 0.3566601 , 0.99935473, 0.26353598]])

array14 = np.random.randint(1, 100, (3, 4))
array14

 输出:

array([[83, 30, 64, 53],
 [39, 92, 53, 43],
 [43, 48, 91, 72]])
多维数组
使⽤随机的⽅式创建多维数组
代码:
array15 = np.random.randint(1, 100, (3, 4, 5))
array15
输出:
array([[[94, 26, 49, 24, 43],
 [27, 27, 33, 98, 33],
 [13, 73, 6, 1, 77],
 [54, 32, 51, 86, 59]],
 [62, 75, 62, 29, 87],
 [90, 26, 6, 79, 41],
 [31, 15, 32, 56, 64],
 [37, 84, 61, 71, 71]],
 [[45, 24, 78, 77, 41],
 [75, 37, 4, 74, 93],
 [ 1, 36, 36, 60, 43],
 [23, 84, 44, 89, 79]]])
将⼀维⼆维的数组调形为多维数组
⼀维数组调形为多维数组,代码:
array16 = np.arange(1, 25).reshape((2, 3, 4))
array16
输出:
array([[[ 1, 2, 3, 4],
 [ 5, 6, 7, 8],
 [ 9, 10, 11, 12]],
 [[13, 14, 15, 16],
 [17, 18, 19, 20],
 [21, 22, 23, 24]]])
⼆维数组调形为多维数组,代码:
array17 = np.random.randint(1, 100, (4, 6)).reshape((4, 3, 2))
array17
输出:
array([[[60, 59],
 [31, 80],
 [54, 91]],
 [[67, 4],
 [ 4, 59],
 [47, 49]],
 [[16, 4],
 [ 5, 71],
 [80, 53]],
 [[38, 49],
  [70, 5],
 [76, 80]]])
读取图⽚获得对应的三维数组
代码:
array18 = plt.imread('guido.jpg')
array18
输出:
array([[[ 36, 33, 28],
 [ 36, 33, 28],
 [ 36, 33, 28],
 ...,
 [ 32, 31, 29],
 [ 32, 31, 27],
 [ 31, 32, 26]],
 [[ 37, 34, 29],
 [ 38, 35, 30],
 [ 38, 35, 30],
 ...,
 [ 31, 30, 28],
 [ 31, 30, 26],
 [ 30, 31, 25]],
 [[ 38, 35, 30],
 [ 38, 35, 30],
 [ 38, 35, 30],
 ...,
 [ 30, 29, 27],
 [ 30, 29, 25],
 [ 29, 30, 25]],
 ...,
 [[239, 178, 123],
 [237, 176, 121],
 [235, 174, 119],
 ...,
 [ 78, 68, 56],
 [ 75, 67, 54],
 [ 73, 65, 52]],
 [[238, 177, 120],
 [236, 175, 118],
 [234, 173, 116],
...,
 [ 82, 70, 58],
 [ 78, 68, 56],
 [ 75, 66, 51]],
 [[238, 176, 119],
 [236, 175, 118],
 [234, 173, 116],
 ...,
 [ 84, 70, 61],
 [ 81, 69, 57],
 [ 79, 67, 53]]], dtype=uint8)
说明 :上⾯的代码读取了当前路径下名为 guido.jpg 的图⽚⽂件,计算机系统中的图⽚通常由若⼲⾏若⼲列的像素点构成,⽽每个像素点⼜是由红绿蓝三原⾊构成的,所以能够⽤三维数组来表示读取图⽚⽤到了 matplotlib 库的 imread 函数。
数组对象的属性
1. size 属性:数组元素个数
代码:
array19 = np.arange(1, 100, 2)
array20 = np.random.rand(3, 4)
print(array19.size, array20.size)
输出:
50 12
2. shape 属性:数组的形状
代码:
print(array19.shape, array20.shape)
输出:
(50,) (3, 4)
3. dtype 属性:数组元素的数据类型
代码:
print(array19.dtype, array20.dtype)
输出:
int64 float64
ndarray 对象元素的数据类型可以参考如下所示的表格。

 

4. ndim 属性:数组的维度
代码:
print(array19.ndim, array20.ndim)
输出:
1 2
5. itemsize 属性:数组单个元素占⽤内存空间的字节数
代码:
array21 = np.arange(1, 100, 2, dtype=np.int8)
print(array19.itemsize, array20.itemsize, array21.itemsize)
输出:
8 8 1
说明 :在使⽤ arange 创建数组对象时,通过 dtype 参数指定元素的数据类型。可以看出, np.int8 代 表的是8 位有符号整数,只占⽤ 1 个字节的内存空间,取值范围是 。
6. nbytes 属性:数组所有元素占⽤内存空间的字节数
代码:
print(array19.nbytes, array20.nbytes, array21.nbytes)
输出:
400 96 50
7. flat 属性:数组(⼀维化之后)元素的迭代器
代码:
from typing import Iterable
print(isinstance(array20.flat, np.ndarray), isinstance(array20.flat, Iterable))
输出:
False True
8. base 属性:数组的基对象(如果数组共享了其他数组的内存空间)
代码:
array22 = array19[:]
print(array22.base is array19, array22.base is array21)
输出:
True False
说明 :上⾯的代码⽤到了数组的切⽚操作,它类似于 Python list 类型的切⽚,但在细节上⼜不完全相同,下⾯会专⻔讲解这个知识点。通过上⾯的代码可以发现, ndarray 切⽚后得到的新的数组对象跟原来的数组对象共享了内存中的数据,因此 array22 base 属性就是 array19 对应的数组对象。
数组的索引和切⽚
Python 中的列表类似, NumPy ndarray 对象可以进⾏索引和切⽚操作,通过索引可以获取或修改数组中的元素,通过切⽚可以取出数组的⼀部分。
1. 索引运算(普通索引)
⼀维数组,代码:
array23 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
print(array23[0], array23[array23.size - 1])
print(array23[-array23.size], array23[-1])
输出:
1 9
1 9
⼆维数组,代码:
array24 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(array24[2])
print(array24[0][0], array24[-1][-1])
print(array24[1][1], array24[1, 1])
输出:
[7 8 9]
1 9
5 5
[[ 1 2 3]
 [ 4 10 6]
 [ 7 8 9]]
代码:
array24[1][1] = 10
print(array24)
array24[1] = [10, 11, 12]
print(array24)
输出:
[[ 1 2 3]
 [ 4 10 6]
 [ 7 8 9]]
[[ 1 2 3]
 [10 11 12]
 [ 7 8 9]]
2. 切⽚运算(切⽚索引)
切⽚是形如 [ 开始索引 : 结束索引 : 步⻓ ] 的语法,通过指定 开始索引 (默认值⽆穷⼩)、 结束索引 (默认值⽆穷⼤)和步⻓ (默认值 1 ),从数组中取出指定部分的元素并构成新的数组。因为开始索引、结束索引和步⻓都有默认值,所以它们都可以省略,如果不指定步⻓,第⼆个冒号也可以省略。⼀维数组的切⽚运算跟 Python中的 list 类型的切⽚⾮常类似,此处不再赘述,⼆维数组的切⽚可以参考下⾯的代码,相信⾮常容易理解。
代码:
print(array24[:2, 1:])
输出:
[[2 3]
 [5 6]]
代码:
print(array24[2])
print(array24[2, :])
输出:
[7 8 9]
[7 8 9]
代码:
print(array24[2:, :])
输出:
[[7 8 9]]
代码:
print(array24[:, :2])
输出:
[[1 2]
 [4 5]
 [7 8]]
代码:
print(array24[1, :2])
print(array24[1:2, :2])
输出:
[4 5]
[[4 5]]
代码:
print(array24[::2, ::2])
输出:
[[1 3]
 [7 9]]
代码:
print(array24[::-2, ::-2])
输出:
[[9 7]
 [3 1]]
关于数组的索引和切⽚运算,⼤家可以通过下⾯的两张图来增强印象,这两张图来⾃ 《利⽤ Python 进⾏数据分析》 ⼀书,它是 pandas 库的作者 Wes McKinney 撰写的 Python 数据分析领域的经典教科书,有兴趣的读者可以购买和阅读原书。

 

3. 花式索引( fancy index
花式索引( Fancy indexing )是指利⽤整数数组进⾏索引,这⾥所说的整数数组可以是 NumPy ndarray , 也可以是 Python list tuple 等可迭代类型,可以使⽤正向或负向索引。
⼀维数组的花式索引,代码:
array25 = np.array([50, 30, 15, 20, 40])
array25[[0, 1, -1]]
输出:
array([50, 30, 40])
⼆维数组的花式索引,代码:
array26 = np.array([[30, 20, 10], [40, 60, 50], [10, 90, 80]])
# 取⼆维数组的第1⾏和第3⾏
array26[[0, 2]]
输出:
array([[30, 20, 10],
 [10, 90, 80]])
代码:
# 取⼆维数组第1⾏第2列,第3⾏第3列的两个元素
array26[[0, 2], [1, 2]]
输出:
array([20, 80])
代码:
# 取⼆维数组第1⾏第2列,第3⾏第2列的两个元素
array26[[0, 2], 1]
输出:
array([20, 90])
4. 布尔索引
布尔索引就是通过布尔类型的数组对数组元素进⾏索引,布尔类型的数组可以⼿动构造,也可以通过关系运算来产⽣布尔类型的数组。
代码:
array27 = np.arange(1, 10)
array27[[True, False, True, True, False, False, False, False, True]]
输出:
array([1, 3, 4, 9])
代码:
array27 >= 5 
输出:
array([False, False, False, False, True, True, True, True, True])
代码:
# ~运算符可以实现逻辑变反,看看运⾏结果跟上⾯有什么不同
~(array27 >= 5)
输出:
array([ True, True, True, True, False, False, False, False, False])
代码:
array27[array27 >= 5]
输出:
array([5, 6, 7, 8, 9])
提示 :切⽚操作虽然创建了新的数组对象,但是新数组和原数组共享了数组中的数据,简单的说,如果通过新数组对象或原数组对象修改数组中的数据,其实修改的是同⼀块数据。花式索引和布尔索引也会创建新的数组对象,⽽且新数组复制了原数组的元素,新数组和原数组并不是共享数据的关系,这⼀点通过前⾯讲的,数组的 base 属性也可以了解到,在使⽤的时候要引起注意。
案例:通过数组切⽚处理图像
学习基础知识总是⽐较枯燥且没有成就感的,所以我们还是来个案例为⼤家演示下上⾯学习的数组索引和切⽚操作到底有什么⽤。前⾯我们说到过,可以⽤三维数组来表示图像,那么通过图像对应的三维数组进⾏操作,就可以实现对图像的处理,如下所示。 读⼊图⽚创建三维数组对象。
guido_image = plt.imread('guido.jpg')
plt.imshow(guido_image)
对数组的 0 轴进⾏反向切⽚,实现图像的垂直翻转。
plt.imshow(guido_image[::-1])

对数组的1轴进⾏反向切⽚,实现图像的⽔平翻转。

plt.imshow(guido_image[:,::-1]) 

 

数组对象的⽅法
统计⽅法
统计⽅法主要包括: sum() mean() std() var() min() max() argmin() argmax() cumsum() 等,分别⽤于对数组中的元素求和、求平均、求标准差、求⽅差、找最⼤、找最⼩、求累积和等,请参考下⾯的代码。

 

array28 = np.array([1, 2, 3, 4, 5, 5, 4, 3, 2, 1])
print(array28.sum())
print(array28.mean())
print(array28.max())
print(array28.min())
print(array28.std())
print(array28.var())
print(array28.cumsum())
输出:
30
3.0
5
1
1.4142135623730951
2.0
[ 1 3 6 10 15 20 24 27 29 30]
其他⽅法
1. all() / any() ⽅法:判断数组是否所有元素都是 True / 判断数组是否有为 True 的元素。
2. astype() ⽅法:拷⻉数组,并将数组中的元素转换为指定的类型。
3. dump() ⽅法:保存数组到⽂件中,可以通过 NumPy 中的 load() 函数从保存的⽂件中加载数据创建数组。
代码:
array31.dump('array31-data')
array32 = np.load('array31-data', allow_pickle=True)
array32
输出:
array([[1, 2],
 [3, 4],
 [5, 6]])
4. fill() ⽅法:向数组中填充指定的元素。
5. flatten() ⽅法:将多维数组扁平化为⼀维数组。
代码:
array32.flatten()
输出:
array([1, 2, 3, 4, 5, 6])
6. nonzero() ⽅法:返回⾮ 0 元素的索引。
7. round() ⽅法:对数组中的元素做四舍五⼊操作。
8. sort() ⽅法:对数组进⾏就地排序。
代码:
array33 = np.array([35, 96, 12, 78, 66, 54, 40, 82])
array33.sort()
array33
输出:
array([12, 35, 40, 54, 66, 78, 82, 96])
9. swapaxes() transpose() ⽅法:交换数组指定的轴。
代码:
# 指定需要交换的两个轴,顺序⽆所谓
array32.swapaxes(0, 1)
输出:
array([[1, 3, 5],
 [2, 4, 6]])
代码:
# 对于⼆维数组,transpose相当于实现了矩阵的转置
array32.transpose()
输出:
array([[1, 3, 5],
 [2, 4, 6]])
10. tolist() ⽅法:将数组转成 Python 中的 list
  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值