【Numpy】12 数据类型和基本操作
2023.1.3 一口气学完Numpy
12.1 为什么用numpy
- 矩阵运算的时候,速度快。深度学习的核心基础是矩阵运算。
Numpy 是上个时代的产物,它基本上所有的优化都是基于 CPU 的优化,而现在的深度学习,大多都要利用到 GPU 甚至是 TPU 的计算单元。 所以有很多操作,Numpy 是不擅长的。但是像 Tensorflow,Pytorch 这种深度学习库,在很大程度上都是借鉴了 Numpy 而开发的。
- 自己开发不依赖于 Tensorflow 和 Pytorch 的深度学习的项目,建议从 Numpy 入手。(比如遗传算法)
Tensorflow
和Pytorch
能实现的项目,就尽量用它们开发,Numpy 在深度学习上的功能,和 GPU 的加速上,都不占优势。
12.2 Ndarray 对象
NumPy 最重要的一个特点是其 N 维数组对象 ndarray
- ndarray 对象是用于存放同类型元素的多维数组
- ndarray 中的每个元素在内存中都有相同存储大小的区域。
12.2.1 对象的常规操作
12.2.1.1 查看数组类型type()
import numpy as np
a = np.array([[1,2,3],[5,12,4]])
print (a)
[[ 1 2 3]
[ 5 12 4]]
type(a)
numpy.ndarray
12.2.2.2 数组形状ndarray.shape
a.shape
(2, 3)
12.2.2.3 重新定义形状reshape
data = np.arange(6)
print(data)
data = np.arange(6).reshape([2, 3])
data
[0 1 2 3 4 5]
array([[0, 1, 2],
[3, 4, 5]])
12.2.2.4 维数ndarray.ndim
a = np.arange(24)
print (a.ndim) # a 现只有一个维度
# 现在调整其大小
b = a.reshape(2,4,3) # b 现在拥有三个维度
print (b.ndim)
1
3
12.2.2.5 元素类型
print(b,b.dtype)
[[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[[12 13 14]
[15 16 17]
[18 19 20]
[21 22 23]]] int32
12.2.2 创建数组
12.2.2.1 空数组np.empty
np.empty(形状,数据类型)
数组元素为随机值,因为它们未初始化
import numpy as np
x = np.empty([3,2], dtype = int)
print (x)
[[ 112 4522068]
[ -952915696 414]
[ 0 -2147483648]]
12.2.2.2 零值填充numpy.zeros()
默认是浮点型float64
,也可以指定类型
x = np.zeros((2,2))
print(x)
print(x.dtype)
[[0. 0.]
[0. 0.]]
float64
# 设置类型为整数
y = np.zeros((5), dtype = int)
print(y)
[0 0 0 0 0]
- 类似的还有全
1
创建:numpy.ones(形状)
- 类似的还有对角矩阵创建:
numpy.eye(形状)
x = np.eye(2,2)
print(x)
[[1. 0.]
[0. 1.]]
# 也可以不是正的
x = np.eye(2,3)
print(x)
[[1. 0. 0.]
[0. 1. 0.]]
12.2.2.3 np.arange()
而创建有些规律的数据也是 Numpy 的拿手好戏。首先我要说一个最常见的,arange
功能,这就有点像 Python 里的 range
功能,用来得到一个序列,我举个例子
print("python range:", list(range(5)))
print("numpy arange:", np.arange(5))
python range: [0, 1, 2, 3, 4]
numpy arange: [0 1 2 3 4]
# (start, end, step)
print("python range:", list(range(3, 10, 2)))
print("numpy arange:", np.arange(3, 10, 2))
python range: [3, 5, 7, 9]
numpy arange: [3 5 7 9]
12.2.2.4 np.linspace()
直译是线性空间。也就是从开始 start
到结束end
,均匀分布 num
个数据点,并返回
# (start, end, num)
print("linspace:", np.linspace(-1, 1, 5))
linspace: [-1. -0.5 0. 0.5 1. ]
12.2.3 从已有的数组创建数组
12.2.3.1 将列表转换为 ndarray
import numpy as np
x = [1,2,3]
a = np.asarray(x, dtype = float)
print (type(x),type(a))
<class 'list'> <class 'numpy.ndarray'>
用np.asarray(x)
:x可以是列表、元组等转换为ndarray
格式
### 12.2.3.2 np.zeros_like(), np.ones_like(), np.full_like()
- 已经有一份数据,我们想创建一个和它类型一样,大小一样的另一份数据, 可以设置类型,用已知数据的类型
data = np.array([
[1,2,3],
[4,5,6]
], dtype=np.int64)
ones = np.ones(data.shape, dtype=data.dtype)
ones
array([[1, 1, 1],
[1, 1, 1]], dtype=int64)
- 也我们可以调用
np.xxx_like
这种形式的功能
ones_like = np.ones_like(data)
ones_like
array([[1, 1, 1],
[1, 1, 1]], dtype=int64)
np.full_like(和谁一样, 填充的数据)
print(np.zeros_like(data))
print(np.full_like(data, 6))
[[0 0 0]
[0 0 0]]
[[6 6 6]
[6 6 6]]
12.2.4 随机数和随机操作
12.2.4.1 np.random.rand(), np.random.random()
np.random.rand()
是一种最方便去生成带 shape 的 [0, 1) 之间取值的 Array。实现同一个目的的还有这样一种写法,功能上没差别,但是就是看你个人习惯了,np.random.random()
用它就是直接传一个 shape 进去。
# 随机生成 [0, 1) 之间的数
dim1, dim2 = 3, 2
print(np.random.rand(dim1, dim2)) # 你还能继续添加 dim3 或更多
[[0.49989771 0.48202423]
[0.0920152 0.80241831]
[0.01686598 0.36143663]]
#print(np.random.random([dim1, dim2]))相当于
print(np.random.random([3, 2]))
[[0.78749328 0.9306585 ]
[0.43213537 0.89557413]
[0.20278646 0.75437857]]
### 12.2.4.2 np.random.randn(), np.random.randint()
- np.random.randn():按照标准正态分布去生成
- np.random.randint():随机整数,开始结尾 几个数
print(np.random.randn(dim1, dim2))
[[ 0.22624066 -0.7838529 ]
[-0.43663436 -0.82459037]
[ 1.2300422 -0.73857468]]
print(np.random.randint(low=-3, high=6, size=10))
[ 2 -2 1 5 4 -2 4 5 0 1]
12.2.4.3 随机从一组数选择np.random.choice()
replace=False
有没有放回抽取 还是很重要的
data = np.array([2,1,3,4,6])
print("选一个:", np.random.choice(data))
print("选多个:", np.random.choice(data, size=3))
print("不重复地选多个(不放回):", np.random.choice(data, size=3, replace=False))
print("带权重地选择:", np.random.choice(data, size=10, p=[0,0,0,0.2,0.8]))
选一个: 6
选多个: [4 6 6]
不重复地选多个(不放回): [4 6 2]
带权重地选择: [4 6 6 6 6 6 6 6 6 6]
`np.random.choice(data)`:是从数据data中随机抽;`size`:选几个数;`replace=False`:不重样;`p`:抽的gailv;
12.2.4.4 将数据随机打乱np.random.shuffle()、np.random.permutation()
保持原型状
print(data)
[2 1 3 4 6]
np.random.shuffle(data)
print("shuffled:", data)
shuffled: [2 6 1 3 4]
np.random.shuffle()
是对原有数据进行打乱。所以要保留原来数据,一般要np.copy(data)
备份一下np.random.permutation()
,是打乱后行程新的数据
#np.random.shuffle(data)
data_copy = np.copy(data)
np.random.shuffle(data)
print("源数据:", data_copy)
print("shuffled:", data)
源数据: [2 6 1 3 4]
shuffled: [2 6 3 1 4]
#np.random.permutation(data)
print("直接出乱序序列:", np.random.permutation(10))
data = np.arange(12).reshape([6,2])
print("多维数据在第一维度上乱序:", np.random.permutation(data))
直接出乱序序列: [6 1 5 2 7 4 9 3 0 8]
多维数据在第一维度上乱序: [[ 8 9]
[ 6 7]
[10 11]
[ 2 3]
[ 0 1]
[ 4 5]]
12.2.4.5 随机分布 np.random.normal(), np.random.uniform()
# (均值,方差,size)
print("正态分布:", np.random.normal(1, 0.2, 10))
# (最低,最高,size)
print("均匀分布:", np.random.uniform(-1, 1, 10))
正态分布: [0.98271868 1.10408556 1.19706026 0.85296396 0.86414722 0.71507546
0.92360382 0.87213024 1.01227216 1.02784269]
均匀分布: [ 0.44634207 0.49971606 -0.7768119 -0.59691976 -0.04761686 -0.53302451
0.32256355 0.41130953 -0.04766905 0.97091207]
12.2.4.6 随机种子seed
随机种子一样的 运行多少次,随机出来的数都一样。要对比两种随机初始化模型的优劣,或者在强化学习中要固定随机环境的随机序列可以用到
# seed(1) 代表的就是 1 号随机序列
np.random.seed(1)
print(np.random.randint(2, 10, size=3))
print(np.random.randint(2, 10, size=3))
[7 5 6]
[2 9 3]
# seed(1) 代表的就是 1 号随机序列
#再运行一次
np.random.seed(1)
print(np.random.randint(2, 10, size=3))
print(np.random.randint(2, 10, size=3))
[7 5 6]
[2 9 3]
np.random.seed(2)
print(np.random.randint(2, 10, size=3))
np.random.seed(2)
print(np.random.randint(2, 10, size=3))
[2 9 7]
[2 9 7]
12.3 访问对象
12.3.1 直接访问
12.3.2.1 一维
a = np.array([1, 2, 3])
print("a[0]:", a[0])
print("a[1]:", a[1])
a[0]: 1
a[1]: 2
【也可以同时访问多个】:访问的组成一个列表,所以多用一个[]
print(a)
print("a[[0,1]]是访问0号和1号:", a[[0,1]])
print("a[[1,1,0]]是访问1号、1号和0号:", a[[1,1,0]])
[1 2 3]
a[[0,1]]是访问0号和1号: [1 2]
a[[1,1,0]]是访问1号、1号和0号: [2 2 1]
12.3.2.2 二维或者多维数据
- ①缺项的,都是从高维算的。这个
1
就是高维方向的1
,也就是第1
列
b = np.array([
[1,2,3,4],
[5,6,7,8],
[9,10,11,12]
])
# 选第 2 行所有数
print("b[1]:", b[1])
b[1]: [5 6 7 8]
- ②直接访问某个值
# 选第 2 行,第 1 列的数
print("b[1,0]:", b[1,0])
b[1,0]: 5
- ③访问多个值
# 这个看着有点纠结,如果对应到数据,
# 第一个拿的是数据位是 [1,2]
# 第二个拿的是 [0,3]
print("b[[1,0],[2,3]]:\n",
b[[1,0],
[2,3]])
b[[1,0],[2,3]]:
[7 4]
12.3.2 切片访问
和python一样
b = np.array([
[1,2,3,4],
[5,6,7,8],
[9,10,11,12]
])
print("b[:2]:\n", b[:2])
print("b[:2, :3]:\n", b[:2, :3])
print("b[1:3, -2:]:\n", b[1:3, -2:])
b[:2]:
[[1 2 3 4]
[5 6 7 8]]
b[:2, :3]:
[[1 2 3]
[5 6 7]]
b[1:3, -2:]:
[[ 7 8]
[11 12]]
12.3.3 条件筛选
a = np.array([
[1,2,3,4],
[5,6,7,8],
[9,10,11,12]
])
print(a[a>7])
[ 8 9 10 11 12]
那么只要我们得到一个 True/False 数据,我都能做筛选
condition = (a > 7) & (a != 10)
print(a[condition])
[ 8 9 11 12]
condition = a > 7
print(np.where(condition, -1, a))
[[ 1 2 3 4]
[ 5 6 7 -1]
[-1 -1 -1 -1]]
找到哪里满足条件是Ture
的用-1
代替,其他还是a
里面的数字
condition = a > 7
print(np.where(condition, -1, 2))
[[ 2 2 2 2]
[ 2 2 2 -1]
[-1 -1 -1 -1]]
False
的用2
代替