NumPy 多维数组入门到精通

一 前言

NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起组合使用, 这种组合广泛用于替代 MatLab,是一个强大的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习;
公众号:知识追寻者

知识追寻者(Inheriting the spirit of open source, Spreading technology knowledge;)

二 NumPy介绍

Numpy是进行科学计算的基础包,其核心功能就是支持对python数组的处理,高效而便捷;其功能包括如下

  1. 具有功能强大N维数组对象
  2. 精密的广播功能函数
  3. 集成 C /C++ 的和 fortran代码工具
  4. 支持线性代数,傅里叶变化和随机函数等

三 NumPy安装

可以直接使用pip安装也可以使用Anaconda发行的Windwos安装

pip安装示例

pip install numpy

Anaconda 安装示例

conda install numpy

四 Ndarray介绍

ndarray 对象是用于创建N维数组的的数据集对象;创建的数组大小固定,与python的列表最大不同就是python列表大小不固定;其核属性如下

  1. dtype 每个ndarray都有一个数据类型,比如全是整型的一维数组
  2. ndim,轴的数量是秩(python中使用 rank称呼)
  3. shape 表示数组维度的大小,一般统称数组的维是轴(axes),轴的数量是秩(rank);比如(n,m)表示具有n行,m列的矩阵;
  4. size,数组元素的总个数,相当于 .shape 中 n*m 的值
  5. itemsize,ndarray 对象中每个元素的大小,以字节为单位
  6. flags,ndarray 对象的内存信息
  7. real,ndarray元素的实部
  8. imag,ndarray 元素的虚部

Ndarray函数如下

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

参数介绍如下:

参数 含义
object 数组
dtype 数据类型
copy 是否启用复制
order 创建数组的方向,C为行方向,F为列方向,A为任意方向
subok 返回一个与基类类型一致的数组
ndmin 指定生成数组的最小维度

五 dtype 概览

数据类型 含义
np.int8 字节(-128到127)
np.int16 整数(-32768至32767)
np.int32 整数(-2147483648至2147483647)
np.int64 整数(-9223372036854775808至9223372036854775807)
np.uint8 无符号整数(0到255)
np.uint16 无符号整数(0到65535)
np.uint32 无符号整数(0到4294967295)
np.uint64 无符号整数(0到18446744073709551615)
np.intp 用于索引的整数,通常与索引相同 ssize_t
np.uintp 整数大到足以容纳指针
np.float32 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
np.float64/float_ 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
np.complex64 复数,表示双 32 位浮点数
np.complex12/complex_ 复数,表示双 64 位浮点数

六 创建数组

6.1 构造函数方式

构造函数方式创建比较*,完全由用户自定义多维数组作为入参;

创建一维数组

# -*- coding: utf-8 -*-

import numpy as np

# 一维数据
za = np.array([0,5,10,15])
# 打印数组
print(za)

输出

[ 0  5 10 15]

创建二维数组

# -*- coding: utf-8 -*-

import numpy as np

# 一维数据
za = np.array([[0,2,4,6],[1,3,5,7]])
# 打印数组
print(za)

输出

[[0 2 4 6]
 [1 3 5 7]]

6.2 随机数方式

创建一个一个2行3列的数组(2*3)

# -*- coding: utf-8 -*-

import numpy as np

# 随机数生成多维数组
nz = np.random.randn(2,3) # 一个2行3列的数组
print(nz)

输出

[[ 1.28315417  0.45088654 -0.85996385]
 [ 0.69196783 -1.18493407 -0.68383036]]

6.3 zeros创建全0数组

创建一个2行5列的全0数组(2*5)

# -*- coding: utf-8 -*-

import numpy as np

# 全0数组
print(np.zeros((2,5),dtype=np.int))

输出

[[0 0 0 0 0]
 [0 0 0 0 0]]

6.4 ones创建全1 数组

创建一个2行5列的全1数组(2*5)

# -*- coding: utf-8 -*-

import numpy as np

# 全1数组
print(np.ones((2,5),dtype=np.int))

输出

[[1 1 1 1 1]
 [1 1 1 1 1]]

6.5 使用empty创建数组

创建一个3个2行4列的数组(3*2*4

# -*- coding: utf-8 -*-

import numpy as np

print(np.empty((3,2,4),dtype=np.float64))

输出

[[[0. 0. 0. 0.]
  [0. 0. 0. 0.]]

 [[0. 0. 0. 0.]
  [0. 0. 0. 0.]]

 [[0. 0. 0. 0.]
  [0. 0. 0. 0.]]]

6.6使用内置板块创建数组

创建一个1*10的数组

# -*- coding: utf-8 -*-

import numpy as np

# 内置数组板块
arr = np.arange(10)
print(arr)

输出

[0 1 2 3 4 5 6 7 8 9]

创建一个一维数组,元素从10-30之间选取,步长为5

arr = np.arange(10,30,5)
print(arr)

输出

[10 15 20 25]

七数组属性

7.1 数组维度

创建一个3*2*3 的数组

# -*- coding: utf-8 -*-

import numpy as np

arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
# 打印数组维度
print(arr.ndim)

输出

[[[ 69   0 110]
  [  0  97   0]]

 [[ 98   0 108]
  [  0 101   0]]

 [[100   0   0]
  [  0  73   0]]]
3

7.2 数组形状

# -*- coding: utf-8 -*-

import numpy as np

arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
#打印数组形状
print(arr.shape)

输出

[[[ 69   0 110]
  [  0  97   0]]

 [[ 98   0 108]
  [  0 101   0]]

 [[100   0   0]
  [  0  73   0]]]
(3, 2, 3)

7.3 数组字节数

itemsize 返回的是每个数组中每个元素的字节大小,指定了int8表示8bit为1个字节;

# -*- coding: utf-8 -*-

import numpy as np

arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
# 打印数组字节数
print(arr.itemsize)

输出

[[[ 69   0 110]
  [  0  97   0]]

 [[ 98   0 108]
  [  0 101   0]]

 [[100   0   0]
  [  0  73   0]]]
1

7.4 打印内存对象

# -*- coding: utf-8 -*-

import numpy as np

arr = np.empty((3,2,3),dtype=np.int8)
# 打印内存对象
print(arr.flags)

输出

  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False

7.5数组数据类型

# -*- coding: utf-8 -*-

import numpy as np

arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
# 打印数组数据类型
print(arr.dtype)

输出

[[[  0   0   0]
  [124   0 106]]

 [[  0 124   1]
  [106   0 107]]

 [[  3 114  62]
  [100   1 -96]]]
int8

八 数组基本操作

8.1 算术运算

数组的算术运算会应运到数组的每个元素;如果是2个矩阵间的运算就会在对应的位置进行符号运算;那么如下操作中都是元素级操作;

【加法】

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr = np.array([0,2,4,6])
# 数组加2
plus = arr+2
print(plus)

输出

[2 4 6 8]

矩阵间

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 + arr1
print(arr)


输出

[ 1  5  9 13]

【减法】

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr = np.array([0,2,4,6])
# 数组减2
sub = arr-2
print(sub)

输出

[-2  0  2  4]

矩阵间

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 - arr1
print(arr)

输出

[1 1 1 1]

【乘法】

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr = np.array([0,2,4,6])
# 数组乘2
sub = arr*2
print(sub)

输出

[ 0  4  8 12]

矩阵间

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 * arr1
print(arr)


输出

[ 0  6 20 42]

【除法】

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr = np.array([0,2,4,6])
# 数组除法
sub = arr/3
print(sub)

输出

[0.         0.66666667 1.33333333 2.        ]

【平方】

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr = np.array([0,2,4,6])
# 数组平方
sub = arr**2
print(sub)

输出

[ 0  4 16 36]

【正弦】

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 * np.sin(arr1)
print(arr)

输出

[ 0.          2.72789228 -3.78401248 -1.95590849]

【平方根】

# -*- coding: utf-8 -*-

import numpy as np

# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 * np.sqrt(arr1)
print(arr)


输出

[ 0.          4.24264069 10.         17.1464282 ]

8.2 矩阵积

矩阵积也就是线性代数的矩阵运算方式,如下方式中是 3*3 的矩阵运算方式

A*B <=> np.dot(A,B)

# -*- coding: utf-8 -*-

import numpy as np

arr1 = np.array([
    [1,1,1],
    [2,2,2],
    [3,3,3]
])
arr2 = np.array([
    [1,2,3],
    [4,5,6],
    [7,8,9]
])
arr =  np.dot(arr1,arr2)
print(arr)


输出

[[12 15 18]
 [24 30 36]
 [36 45 54]]

B*A <=> np.dot(B,A)

# -*- coding: utf-8 -*-

import numpy as np

arr1 = np.array([
    [1,1,1],
    [2,2,2],
    [3,3,3]
])
arr2 = np.array([
    [1,2,3],
    [4,5,6],
    [7,8,9]
])
arr =  np.dot(arr2,arr1)
print(arr)

输出

[[14 14 14]
 [32 32 32]
 [50 50 50]]

8.3 自增自减操作

自增,自减也是针对元素级操作

【自减】

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([1,1,1])
arr -= 1
print(arr)

输出

[0 0 0]

【自增】

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([1,1,1])
arr += 1
print(arr)

输出

[2 2 2]

8.4 通用函数

NumPy 提供了很多通用函数,知识追寻者在这边示例只是部分,读者使用到时应该查阅官方文档;

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([1,1,1])
# 求和
sum = np.sum(arr)
print(sum)
# 指数e
exp = np.exp(arr)
print(exp)
# 平方根
sqr = np.sqrt(arr)
print(sqr)
# 加
add = np.add(arr,np.array([2,2,2]))
print(add)

输出

3
[2.71828183 2.71828183 2.71828183]
[1. 1. 1.]
[3 3 3]

8.5 布尔操作

直接使用关系运算符操作,应用于元素级别

# -*- coding: utf-8 -*-

import numpy as np


arr = np.array([
        [1,2,3,4,5],
        [2,3,4,5,6],
        [3,4,5,6,7]
               ])

print(arr>5)

输出

[[False False False False False]
 [False False False False  True]
 [False False False  True  True]]

九 索引切片

数组的索引也是和字符串类似,比如[1,1,1]这个数组的正向索引就是0,1,2;负向索引就是-3,-2,-1;

9.1一维数组切片

取索引1到3(不包括3)

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([1,2,3,4,5])
print(arr[1:3])

输出

[2 3]

取 索引1到数组末尾

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([1,2,3,4,5])
print(arr[1:])

输出

[2 3 4 5]

取索引-3到-1

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([1,2,3,4,5])
print(arr[-3:-1])

输出

[3 4]

9.2二维索引切片

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([
        [1,2,3,4,5],
        [2,3,4,5,6],
        [3,4,5,6,7]
               ])
# 获取第一行
print(arr[0])
# 获取第一行第三列
print(arr[0,2])
# 获取1-2行
print(arr[0:2])
# 获取1-2行 每行的前2个元素
print(arr[0:2,0:2])

输出

[1 2 3 4 5]
3
[[1 2 3 4 5]
 [2 3 4 5 6]]
[[1 2]
 [2 3]]

十数组迭代

10.1 一维数组迭代

一维数组迭代直接使用for循环

# -*- coding: utf-8 -*-

import numpy as np

arr = np.arange(10,dtype=np.int8)
for i in arr:
    print(i)

输出

0
1
2
3
4
5
6
7
8
9

10.2 二维数组迭代

二维数组迭代,内嵌一个for循环

# -*- coding: utf-8 -*-

import numpy as np

arr = np.empty((2,3),dtype=np.int8)
print(arr)
for row in arr:
    for column in row:
        print(column)

输出

[[0 0 5]
 [0 0 0]]
0
0
5
0
0
0

10.3 使用函数迭代

# -*- coding: utf-8 -*-

import numpy as np


arr = np.array([
        [1,2,3,4,5],
        [2,3,4,5,6],
        [3,4,5,6,7]
               ])
# 0 轴 代表行索引
max = np.apply_along_axis(np.max,axis=0,arr=arr)
# 1 轴代表列索引
min = np.apply_along_axis(np.min,axis=1,arr=arr)
print(max)
print(min)

输出

[3 4 5 6 7]
[1 2 3]

十一 形状操作

11.1 形状调整

重新调整大小的规则是shape各个属性的积一致;比如 2*2*3 = 3*6

# -*- coding: utf-8 -*-

import numpy as np

arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
# 调整形状大小
re = arr.reshape(3,6)
print(re)

输出

[[[ 69   0 110]
  [  0  97   0]]

 [[ 98   0 108]
  [  0 101   0]]

 [[100   0   0]
  [  0  73   0]]]
[[ 69   0 110   0  97   0]
 [ 98   0 108   0 101   0]
 [100   0   0   0  73   0]]

注 使用resize 会改变数组本身

11.2 形状可逆

将一个 3*4的矩阵改变为2*6, 使用ravel()函数后会为一维数组

# -*- coding: utf-8 -*-

import numpy as np

arr = np.random.random((3,4))
# 改变形状
res = arr.reshape(2,6)
# 可逆
vel = res.ravel()
print(vel)

输出

[0.31196361 0.21399829 0.7420462  0.07945804 0.44684642 0.15533381
 0.39328725 0.33091821 0.36530517 0.99345252 0.44964442 0.23923565]

11.3 行列交换

将矩阵的行转与列互换

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])
print(arr.transpose())

输出

[[2. 4. 8.]
 [8. 5. 9.]
 [0. 1. 3.]
 [6. 1. 6.]]

十二叠加操作

12.1hstack

将第二个数组作为列叠加至第一个数组

# -*- coding: utf-8 -*-

import numpy as np

arr1 = np.ones((3,3))
arr2 = np.zeros((3,3))
# 将arr2作为列叠加至arr1
print(np.hstack((arr1,arr2)))

输出

[[1. 1. 1. 0. 0. 0.]
 [1. 1. 1. 0. 0. 0.]
 [1. 1. 1. 0. 0. 0.]]

12.2 vstack

将第二个数组作为行叠加至第一个数组

# -*- coding: utf-8 -*-

import numpy as np

arr1 = np.ones((3,3))
arr2 = np.zeros((3,3))
# 将arr2作为行叠加至arr1
print(np.vstack((arr1,arr2)))

输出

[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]

12.3 column_stack

将一维数组作为列形成新的二维数组(1D变2D)

# -*- coding: utf-8 -*-

import numpy as np

arr1 = np.ones((1,3))
arr2 = np.zeros((1,3))
print(np.column_stack((arr1,arr2)))

输出

[[1. 1. 1. 0. 0. 0.]]

12.4 row_stack

将一维数组作为行形成新的二维数组(1D变2D)

# -*- coding: utf-8 -*-

import numpy as np

arr1 = np.ones((1,3))
arr2 = np.zeros((1,3))
print(np.row_stack((arr1,arr2)))

输出

[[1. 1. 1.]
 [0. 0. 0.]]

十三 数组切分

13.1 水平切分

将一个4*4 的矩阵按照宽度切分为两个 4*2

# -*- coding: utf-8 -*-

import numpy as np

arr = np.ones((4,4))
[A,B]= np.hsplit(arr,2)
print(A)
print(B)

输出

[[1. 1.]
 [1. 1.]
 [1. 1.]
 [1. 1.]]
[[1. 1.]
 [1. 1.]
 [1. 1.]
 [1. 1.]]

13.2 垂直切分

将一个4*4 的矩阵按照高度切分为两个 2*4

# -*- coding: utf-8 -*-

import numpy as np

arr = np.ones((4,4))
[A,B]= np.vsplit(arr,2)
print(A)
print(B)

输出

[[1. 1. 1. 1.]
 [1. 1. 1. 1.]]
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]]

13.3 指定切分

指定切分是指按照轴切分矩阵为多个小矩阵;如下示例中按照行索引轴切分,分别切分为三个部分;[1,3]会被切分为[:1],[1:3],[3:]

# -*- coding: utf-8 -*-

import numpy as np

arr = np.ones((4,4))
[A,B,C]= np.split(arr,[1,3],axis=0)
print(A)
print(B)
print(C)

输出

[[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]]
[[1. 1. 1. 1.]]

十四 副本与视图

视图是指对数据的引用,在操作视图的同时也会改变元数据,如上操作的切片都是视图操作,会对原数据产生影响;副本 是指对数据完整的拷贝,副本拥有独立的内存空间,故对副本进行修改不会改变原来的数据;

14.1 视图

如下示例中改变视图数组第一个元素,原数组的第一个元素也会被改变;

# -*- coding: utf-8 -*-

import numpy as np

arr = np.arange(10)
print(arr)
vw = arr.view()
vw[0]= 100
print(arr)

输出

[0 1 2 3 4 5 6 7 8 9]
[100   1   2   3   4   5   6   7   8   9]

14.2 副本

如下示例中改变副本数组第一个元素,原数组的第一个元素不会被改变;

# -*- coding: utf-8 -*-

import numpy as np

arr = np.arange(10)
print(arr)
vw = arr.copy()
vw[0]= 100
print(arr)

输出

[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]

十五 广播规则

在不同形状的数组进行运算时需要遵守广播规则;通常情况下都是shape形同,那么对应位置的元数进行算术操作即可;

  1. 当输入的数组具有不同数量的的维度时,会将1 预先填充至位置,直到数组的形状形同;
  2. 如果元素缺失,则会用已有的元素进行替换填充;

如下示例中 数组B 是 1 * 3 经过规则一后面两行会变为全是1 ,此时应该是 3 * 3; 经过规则二后 会变为元素都是全是2 的3 * 3矩阵;

# -*- coding: utf-8 -*-

import numpy as np

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

B = np.array([2,2,2])

print(arr * B)

输出

[[ 2  4  6]
 [ 8 10 12]
 [14 16 18]]

十六 数组的读取和保存

16.1 二进制形式保存数组

保存单个数组时可以调用save方法,自动添加后缀.npy

# -*- coding: utf-8 -*-

import numpy as np

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

np.save('dirs/numpy_z',arr)

保存多个数组时调用savez方法,自动添加后缀.npz

# -*- coding: utf-8 -*-

import numpy as np

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

np.savez('dirs/numpy_zz',arr,arr2)

16.2 文件中读取数组

读取【.npy】

arr = np.load('dirs/numpy_z.npy')
print(arr)

输出

[[1 2 3]
 [4 5 6]
 [7 8 9]]

读取【.npz】

# -*- coding: utf-8 -*-

import numpy as np

arr = np.load('dirs/numpy_zz.npz')
print(arr.files)
print(arr['arr_0'])

输出

['arr_0', 'arr_1']
[[1 2 3]
 [4 5 6]
 [7 8 9]]

16.3 保存和读取txt文本数组

# -*- coding: utf-8 -*-

import numpy as np

arr = np.array([[1,2,3],
               [4,5,6],
               [7,8,9]])
# 保存为txt,十进制形式,分格符为逗号
np.savetxt('dirs/numpy_z.txt',arr,fmt="%d", delimiter=",")
# 读取文件以整数形式,分格符为逗号
val = np.loadtxt('dirs/numpy_z.txt',dtype=int, delimiter=',')
print(val)

输出

[[1 2 3]
 [4 5 6]
 [7 8 9]]

还支持 csv格式读者可以参考官方文档进行学习;

十七 参考文档

https://numpy.org/doc/1.13/user/index.html

上一篇:pr中打开Audition编辑剪辑?


下一篇:真香!CODING DevOps “极速构建计划”,再也不用担心构建慢了!