python numpy库总结

2021/11/18 22:13:41

本文主要是介绍python numpy库总结,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本节导图:https://www.processon.com/view/link/5fcc5e81f346fb3fc8776929

文章目录

  • 1. ndarray对象
    • 1.1 为什么是ndarray
        • list的问题
        • array模块
        • ndarray(N-dimensional array)
    • 1.2 创建ndarray对象
        • 可以通过列表创建数组
        • 可以通过`shape`属性,查看数组的行数和列数
        • 可以使用`reshape()`方法,创建特定shape的新数组
        • 可以通过`dtype`属性,查看数组的元素类型
        • 可以在创建数组时声明dtype
        • 可以使用`astype()`方法进行类型转换
    • 1.3 通过某些函数创建ndarray对象
        • 使用`arange()`创建等差数组
        • 使用`linspace()`创建等差数组
        • 使用`logspace()`创建等比数组
        • 使用`zeros()` `ones()` `full()`初始化特定值
    • 1.4 存取元素
        • 使用索引存取
        • 切片获取的新数组是原始数组的视图,即它与原始数组共享内存
        • 多维数组的存取使用多个值来表示
        • 可以使用数组来存取元素
        • 切片和数组 存取元素对比
    • 1.5 ufunc运算
        • 四则运算
        • 比较运算
        • 布尔运算
    • 1.6 广播
        • 例子1
        • 例子2
  • 2. 庞大的函数库
    • 2.1 随机数函数
    • 2.2 求和、平均值、方差函数
    • 2.3 大小与排序函数
    • 2.4 数组操作函数
    • 2.5 乘积运算函数
  • 3. 小结

1.

1. ndarray对象

1.1 为什么是ndarray

list的问题

Python列表的元素可以是任意对象,列表里保存的是对象的指针。比如存储 [1, 2, 3],需要三个指针和三个整数对象,对于数值运算来讲,这很浪费内存和CPU计算。

array模块

Python也提供了array模块,它可以直接保存数值(而不是对象),但是它不支持多维数组、也缺乏丰富的运算函数。

ndarray(N-dimensional array)

ndarray即n维数组,它弥补了以上不足,它提供了如下对象:

  • ndarray对象:存储特定类型的多维数组
  • ufunc函数:对数组进行处理的函数

ndarray是Numpy的核心对象,Numpy中的所有函数都是围绕ndarray进行处理的。

1.2 创建ndarray对象

我们先将numpy导入

import numpy as np

可以通过列表创建数组

a1 = np.array([1, 2, 3])
a1
array([1, 2, 3])
a2 = np.array([[4, 5, 6], [7, 8, 9]])
a2
array([[4, 5, 6],
       [7, 8, 9]])

可以通过shape属性,查看数组的行数和列数

print(a1.shape)
print(a2.shape)
(3,)
(2, 3)

可以使用reshape()方法,创建特定shape的新数组

a3 = a2.reshape((3, 2))
a3
array([[4, 5],
       [6, 7],
       [8, 9]])

reshape后得到的数组与原数组共享存储,我们可以尝试来修改下

a3[0,0] = 0  # 均发生修改
print(a3)
print(a2)
[[0 5]
 [6 7]
 [8 9]]
[[0 5 6]
 [7 8 9]]

可以通过dtype属性,查看数组的元素类型

    a1.dtype
dtype('int32')

通过整数列表创建的数组,默认的dtype,在64位系统里是int64,在32位系统里是int32

可以在创建数组时声明dtype

    a4 = np.array([1, 2, 3], dtype=np.int32)
    a4
array([1, 2, 3])

可以使用astype()方法进行类型转换

    a4.astype(np.float32)  # 将dtype int32转为float32
array([1., 2., 3.], dtype=float32)

1.3 通过某些函数创建ndarray对象

通过列表创建数组效率显然不高,numpy提供了很多专门用来创建数组的函数。

使用arange()创建等差数组

类似于内置函数range()arange()函数指定开始值、终止值、步长,函数返回一个等差一维数组。

    np.arange(0, 10, 1)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

注意到,这里不包含终止值

可以后接reshape()方法,指定特定shape

    np.arange(0, 10, 1).reshape((5, 2))
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])

使用linspace()创建等差数组

linspace()函数指定开始值、终止值、元素个数返回等差数组。

    np.linspace(1, 10, 10)  # 将1到10 划分10等份
array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.])

注意到,这里包含终止值。可以设置参数endpoint=False,来排除终止值

    np.linspace(1, 10, 10, endpoint=False)
array([1. , 1.9, 2.8, 3.7, 4.6, 5.5, 6.4, 7.3, 8.2, 9.1])

使用logspace()创建等比数组

linspace()函数用法类似,logspace()函数也指定开始值、终止值、元素个数,但它需要额外传入公比参数base,默认为10

    np.logspace(0, 5, 5, base=2, endpoint=False)
array([ 1.,  2.,  4.,  8., 16.])

注意,这里的起始值和终止值其实是公比2的次幂

使用zeros() ones() full()初始化特定值

    np.zeros((2, 3), dtype=np.int32)  # 初始化shape为(2,3)的数组所有元素为int32的0
array([[0, 0, 0],
       [0, 0, 0]])
    np.ones((3, 2), dtype=np.float32)  # 初始化shape为(3,2)的数组所有元素为float32的1
array([[1., 1.],
       [1., 1.],
       [1., 1.]], dtype=float32)
    np.full(4, 10, dtype=np.float64)  # 初始化shape为(4,)的数组所有元素为float64的10
array([10., 10., 10., 10.])

1.4 存取元素

使用索引存取

像存取列表list的方式那样,来存取数组

    a = np.arange(10)  # 定义一个数组
    a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    print(a[5])  # 获取数组第5个元素(从0开始)
5
    print(a[:5])  # 获取数组前5个元素(不包括第5个)
    print(a[2:5])  # 获取数组第2到第5个元素(包括第2个,不包括第5个)
    print(a[:-1])  # 获取数组从头到尾的元素(不包括最后一个),-1表示倒数第1个元素
[0 1 2 3 4]
[2 3 4]
[0 1 2 3 4 5 6 7 8]
    print(a[1:9:2])  # 从1到9,每2步取一个元素
[1 3 5 7]
    a[1] = 11  # 将第1个元素替换
    print(a)
[ 0 11  2  3  4  5  6  7  8  9]
    a[0:2] = 100, 101  # 替换前2个元素
    print(a)
[100 101   2   3   4   5   6   7   8   9]

切片获取的新数组是原始数组的视图,即它与原始数组共享内存

    b = np.arange(5)  # 定义b
    print(b)
    
    c = b[:3]  # 切片获得c
    print(c)
    
    c[0] = 100  # 更改c
    print(c)
    print(b)  # b也发生了修改
[0 1 2 3 4]
[0 1 2]
[100   1   2]
[100   1   2   3   4]

这里与list的切片不同,列表的切片返回的是一个新的列表

    b = list(range(5))  # 定义b
    print(b)
    
    c = b[:3]  # 切片获得c
    print(c)
    
    c[0] = 100  # 更改c
    print(c)
    print(b)  # b并没有被修改
[0, 1, 2, 3, 4]
[0, 1, 2]
[100, 1, 2]
[0, 1, 2, 3, 4]

多维数组的存取使用多个值来表示

    # 定义二维数组a
    a = np.arange(10).reshape((-1, 2))  # -1代表自动计算shape[0],这里是shape为(5,2)
    a
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])
    print(a[1,:])  # 获取第1行
    print(a[:,1])  # 获取第1列
    
    print(a[1:3, 1])  # 第1到3行,第1列
[2 3]
[1 3 5 7 9]
[3 5]

可以使用数组来存取元素

除了使用索引和切片,我们还可以使用list或者数组来存取元素

    a = np.arange(100, 105)  # 定义a
    a
array([100, 101, 102, 103, 104])
    a[[0,2,4]]  # 使用列表,按照列表内声明的索引取元素,返回新数组
array([100, 102, 104])
    a[np.array([0,2,4])]  # 使用数组,按照索引取元素
array([100, 102, 104])
    a[np.array([True, False, False, True, True])]  # 使用bool数组,返回对应位置为True的数组
array([100, 103, 104])

数组获取到的数组,是原始数组的副本

    b = a[np.array([0,2,4])]  # 通过数组获取数组b
    print(b)
    b[0] = 0  # 更改b的元素
    print(b)  # b发生修改
    print(a)  # a未发生修改
[100 102 104]
[  0 102 104]
[100 101 102 103 104]

切片和数组 存取元素对比

  • 数组通过切片得到的数组,是原始数组的视图,共享内存
  • 数组通过(整数或bool)数组得到的数组,是原始数组的副本
  • 出现上述情况的原因,与ndarray对象内存结构的具体实现相关,这里不展开;

1.5 ufunc运算

ufunc是universal function的缩写,它是一种能对数组的每个元素进行运算的函数

四则运算

数组之间的加减乘除等运算,可以通过Python内置的+ - * /等运算符实现,也可以使用add() subtract()等函数实现,两者等价。

完整的运算符参考下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Awk1LOS-1637239987972)(images/数组运算符ufun函数.png)]

    # 定义两个数组
    a = np.arange(10)
    b = np.full(10, -1)
    print(a)
    print(b)
[0 1 2 3 4 5 6 7 8 9]
[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1]
    a + b  # 使用运算符+
array([-1,  0,  1,  2,  3,  4,  5,  6,  7,  8])
    np.multiply(a, b)  # 使用函数乘
array([ 0, -1, -2, -3, -4, -5, -6, -7, -8, -9])

比较运算

类似的,数组之间的比较运算也可以通过运算符> = <等实现,等价于使用equal() less()等函数。它返回一个布尔数组。

完整的运算符参考如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M99MLXoA-1637239987978)(images/比较运算符ufunc函数.png)]

    # 定义两个随机数组
    a = np.random.rand(5)
    b= np.random.rand(5)
    print(a)
    print(b)
[0.45512267 0.54405151 0.24847556 0.90709983 0.21287093]
[0.07250248 0.85389154 0.0598896  0.58928252 0.47854526]
    a > b  # 使用运算符>
array([ True, False,  True,  True, False])
    np.less_equal(a, b)  # 使用函数less_equal
array([False,  True, False, False,  True])

布尔运算

布尔运算在python里面用and or not关键字实现,无法实现运算符重载,所以没有操作符,只能使用函数logical_and() logical_or()等实现。

什么是运算符重载?你可以通过它来定义(或重定义)两个对象的+ - * /等运算。这些运算符的操作本质上是函数调用,你可以在你的类里面实现__add__()内置函数,然后你的类就具有+加法的功能了。这里不展开,感兴趣的同学参考:https://zhuanlan.zhihu.com/p/162931696

    # 定义两个bool数组
    a = np.array([True, False, False])
    b = np.array([True, True, False])
    print(a)
    print(b)
[ True False False]
[ True  True False]
    print(np.logical_and(a, b))  # 逻辑与
    print(np.logical_or(a, b))  # 逻辑或
    print(np.logical_not(a))  # 逻辑非
    print(np.logical_xor(a, b))  # 逻辑异或
[ True False False]
[ True  True False]
[False  True  True]
[False  True False]

1.6 广播

上面所讲的ufunc函数处理的都是shape相同的多个数组,如果要处理的数组shape不同,会进行如下广播处理:

  1. 让所有输入数组都向其中shape最长的数组看齐,shape中不足的部分都在前面加1补齐;
  2. 输出数组的shape是输入数组shape的各个维度上的最大值;
  3. 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为1时,这个数组能够用来计算,否则出错;
  4. 当输入数组的某个维度的长度为1时,沿着此维度运算时都用此维度上的第一组值。

看起来比较抽象,可以通过两个例子来理解这4条规则。

例子1

    arr0 = np.array([  # 2维数组,shape为(2,3)
        [1, 2, 3],
        [4, 5, 6]
    ])
    arr2 = np.array([10, 20, 30])  # 1维数组,shape为(3,)
    print(arr0.shape)
    print(arr2.shape)
(2, 3)
(3,)
    arr_sum = arr0 + arr2  # 广播发生,计算两个数组之和
    print(arr_sum)
    print(arr_sum.shape)  # 输出shape:根据规则1,arr2补齐为(1,3);根据规则2,输出shape为(max(2,1),max(3,3)) = (2,3)
[[11 22 33]
 [14 25 36]]
(2, 3)

我们已经知道输出shape为(2,3),那具体每个元素如何计算呢?

arr0的shape为(2,3)arr2的shape为(1,3)

  • 根据规则3,这两个数组可以用来被计算(维度2相等,维度1虽不等 但arr2为1)
  • 根据规则4,发生了arr2沿着维度1进行广播(arr2的维度1长度为1)

过程参考下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pPB1A1Xr-1637239987979)(images/广播1.png)]

例子2

    arr2 = np.array([  # 2维数组,shape为(1,3)
        [10, 20, 30]
    ])
    arr3 = np.array([  # 2维数组,shape为(3,1)
        [10],
        [20],
        [30]
    ])
    print(arr2.shape)
    print(arr3.shape)
(1, 3)
(3, 1)
    arr_sum = arr2 + arr3  # 广播发生,计算数组之和
    print(arr_sum)
    print(arr_sum.shape)  # 输出shape:规则1满足;根据规则2,输出shape为(max(1,3), max(3,1)) = (3,3)
[[20 30 40]
 [30 40 50]
 [40 50 60]]
(3, 3)

如何计算每个元素?

  • 根据规则3,两个数组可以被用来计算(两个维度都不同,但都有一个维度 某个数组的为1)
  • 根据规则4,arr2沿着第1维广播,arr3沿着第2维广播(arr2的维度1为1,arr3的维度2为1)

过程参考下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uzhPCc7H-1637239987984)(images/广播2.png)]

2. 庞大的函数库

numpy还提供了大量对数组进行处理的函数,充分利用这些函数,能简化程序的逻辑、提高程序运行速度

2.1 随机数函数

numpy.random模块中提供了大量的随机数相关的函数,下面是一些重点函数列表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PeEhFx8i-1637239987986)(images/随机数1.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l9iZDbeZ-1637239987988)(images/随机数2.png)]

看几个例子

print(np.random.rand(2,3))  # 随机生成shape为(2,3)的二维数组,每个元素在0~1之间
print(np.random.randn(2,3))  # 随机生成shape为(2,3)的二维数组,每个元素符合标准正态分布(均值为0,标准差为1)
print(np.random.randint(1,10,size=(2,3)))  # 随机生成shape为(2,3)的二维数组,每个元素在1到10之间,不包含10
[[0.71599632 0.77172853 0.28996579]
 [0.72852298 0.60934017 0.84835497]]
[[-0.42632997  0.85967941 -1.09201344]
 [-0.23171307 -0.17257021  0.90615894]]
[[2 3 6]
 [1 2 3]]
print(np.random.uniform(1,10,(2,3)))  # 随机生成shape为(2,3)的二维数组,每个元素符合1~10的均匀分布
[[3.06191826 6.84866151 4.98272061]
 [7.88468112 9.32084376 6.50330689]]
a = np.arange(10)
np.random.shuffle(a)  # 使用shuffle函数打乱数组a,数组a被改变,无返回
print(a)
[4 3 6 8 7 0 1 5 9 2]
a = np.arange(10)
print(np.random.permutation(a)) # 使用permutation函数打乱数组a,数组a不变,返回打乱后的新数组
print(a)
[1 6 9 4 0 2 3 5 8 7]
[0 1 2 3 4 5 6 7 8 9]
np.random.seed(0)  # 设置随机种子,使得每次运行的随机数都一致(使得随机数可复现)
print(np.random.rand(2,3))
[[0.5488135  0.71518937 0.60276338]
 [0.54488318 0.4236548  0.64589411]]

2.2 求和、平均值、方差函数

本节介绍的函数如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ab0fNMim-1637239987989)(images/求和平均值方差.png)]

看几个例子

a = np.random.randint(0,5,(2,3))
print(a)
[[4 0 0]
 [4 2 1]]
print(np.sum(a, axis=0))  # 沿维度0求和
print(np.sum(a, axis=1)) # 沿维度1求和
print(np.sum(a, axis=0, keepdims=True))  # 保留维度
[8 2 1]
[4 7]
[[8 2 1]]

其它几个函数使用方式类似,这里不再细讲

2.3 大小与排序函数

常见的大小与排序函数,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TC2Tfeik-1637239987991)(images/大小与排序.png)]

这里注意,min()minimum()的区别、max()maximum()的区别

# 定义两个数组
a = np.random.randint(0,5,(2,3))
b = np.random.randint(0,5,(2,3))
print(a)
print(b)
[[0 1 1]
 [0 1 4]]
[[3 0 3]
 [0 2 3]]
print(np.min(a, axis=0))  # 沿着维度0对a取最小值(单个数组)
print(np.minimum(a, b))  # 比较两个数组,取每个位置的最小值
[0 1 1]
[[0 0 1]
 [0 1 3]]

2.4 数组操作函数

常见的数组操作函数如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSS8nOOh-1637239987993)(images/多维数组操作.png)]

我们来看些例子

a = np.full((2,2), 1)  # shape为(2,2),元素为1
b = np.full((2,2), 2)  # shape为(2,2),元素为2
print(a)
print(b)
[[1 1]
 [1 1]]
[[2 2]
 [2 2]]
print(np.concatenate((a,b)))  # 沿着维度0拼接
print(np.concatenate((a,b), axis=1))  # 沿着维度1拼接
[[1 1]
 [1 1]
 [2 2]
 [2 2]]
[[1 1 2 2]
 [1 1 2 2]]
print(np.vstack((a,b)))  # 沿着维度0拼接
print(np.hstack((a,b)))  # 沿着维度1拼接
[[1 1]
 [1 1]
 [2 2]
 [2 2]]
[[1 1 2 2]
 [1 1 2 2]]

2.5 乘积运算函数

常见的乘积运算函数如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BCezh9Jo-1637239987995)(images/各种乘积运算.png)]

我们来看些例子

a = np.full((3,1), 1)  # shape为(3,1),元素为1
b = np.full((1,3), 2)  # shape为(1,3),元素为2
print(a)
print(b)
[[1]
 [1]
 [1]]
[[2 2 2]]
print(np.dot(a,b))  # 矩阵积, shape为(3,3)
[[2 2 2]
 [2 2 2]
 [2 2 2]]
print(np.dot(b,a)) # 矩阵积, shape为(1,1)
[[6]]
a = np.arange(0,5)
b = np.arange(0,-5,-1)
print(a)
print(b)
[0 1 2 3 4]
[ 0 -1 -2 -3 -4]
print(np.inner(a,b))  # 内积,返回标量
-30

如上所述,操作数组的函数非常多,这里只是介绍了5种常用的大类,每个类里面也仅仅举了一小部分的使用例子,对于大家来讲,需要做:

  1. 以上函数的 函数名和功能 多看几遍,知道numpy已经提供了这些功能,以后有相关需求,知道有函数可以用、以及要用哪个函数;
  2. 具体用法细节,就等在实践中慢慢熟悉;

3. 小结

本节主要给大家讲了两个知识点:ndarray对象numpy庞大的函数库

实践中,python相比java、c等语言,确实慢。但是在做多维数组的计算时,如果你能用好numpy的ndarray及其配套的函数,(而不是使用list和for循环),那你的Python程序 运行效率将会很高。



这篇关于python numpy库总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程