Chapter 2 预备知识
2.1 数据操作
2.1.1 创建向量或矩阵
import torch
x = torch.arange(12 , dtype=torch.float32) # arange 创建一个行向量 x,包含以0开始的前12个数,指定创建类型为浮点数
x.shape #访问张量(沿每个轴的长度)的形状
X = x.reshape(3, 4) #把张量x从形状为(12,)的行向量转换为形状为(3,4)的矩阵,张量的大小不会改变
x.reshape(-1,4) #通过-1来调用自动计算维度的功能
x.reshape(3,-1)
torch.zeros((2, 3, 4)) #创建零矩阵
torch.ones((2, 3, 4)) #1矩阵
torch.randn(3, 4) #创建一个形状为(3,4)的张量。 其中的每个元素都从均值为0、标准差为1的标准高斯分布(正态分布)中随机采样。
torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) #嵌套列表形式
2.1.2 运算
- **按元素运算:**两向量的对应元素做四则运算或求幂等运算。
- 透过逻辑运算符构造二元张量,例如X == Y.
- 连结
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
#dim=0表示按第一个维度(即行)连结,dim=1表示按第二个维度(即列)连结。
2.1.3 广播机制
工作方式如下:
- 通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状;
- 对生成的数组执行按元素操作。
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a + b #矩阵a将复制列, 矩阵b将复制行,然后再按元素相加
2.1.4 索引和切片
第一个元素的索引是0,最后一个元素索引是-1
X[-1], X[1:3] #用[-1]选择最后一个元素,可以用[1:3]选择第二个和第三个元素
X[1, 2] = 9 #通过指定索引来将元素写入矩阵
X[0:2, :] = 12 #[0:2, :]访问第1行和第2行,其中“:”代表沿轴1(列)的所有元素
2.1.5 节省内存
利用Y = X + Y会分配新内存,这是不必要的,不可取的。因此采用 Y[:] = 或 **Y += X **的形式来减少操作的内存开销。
2.1.6 转换为其他Python对象
A = X.numpy() #将Pytorch定义的张量tensor转换为NumPy张量(ndarray)
B = torch.tensor(A) #将ndarray转换为tensor
a = torch.tensor([3.5])
a, a.item(), float(a), int(a) #将大小为1的张量转换为Python标量的四种方法
2.2 数据预处理
使用pandas处理原始数据
2.2.1 读取数据集
os.path.join:根据不同操作系统的路径分隔符,将多个路径拼接成一个完整的路径。
with open(data_file, ‘w’) as f:打开一个文件,如果文件不存在则创建一个新文件,如果文件已经存在则清空文件内容,并将文件对象赋值给变量 f
,并将这个文件对象作为一个上下文管理器,在代码块执行完毕后自动关闭文件。
read_csv:是pandas库中的一个函数,用于读取CSV文件并将其转换为DataFrame对象。它可以自动推断数据类型、处理缺失值、处理日期时间等。它还支持许多可选参数,例如指定分隔符、编码、列名等。
import os
os.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Price\n') # 列名
f.write('NA,Pave,127500\n') # 每行表示一个数据样本
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')
import pandas as pd
data = pd.read_csv(data_file)
print(data) # 或者直接运行 data
上图为’print(data) '的输出结果,下图为’data’的输出结果
2.2.2 处理缺失值
“NaN”:代表缺失值。
处理缺失的数据的典型方法:
- 插值法:用一个替代值弥补缺失值;
- 删除法:直接忽略缺失值。
get_dummies:它可以将分类变量的每个取值(category)转换为一个新的列(column),并将相应的值设置为1或0,表示该行是否包含该取值。
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2] # iloc:位置索引
inputs = inputs.fillna(inputs.mean()) # 用同一列的均值替换“NaN”项
print(inputs)
2.2.3 转换为张量格式
import torch
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
2.2.4 练习:删除缺失值最多的列
import os
os.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Price\n') # 列名
f.write('NA,Pave,127500\n') # 每行表示一个数据样本
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')
import pandas as pd
data = pd.read_csv(data_file)
# 检查每一列中缺失值的数量
missing_values = data.isna().sum()
# 找到缺失值最多的列的索引
max_missing_col = missing_values.idxmax()
# 删除缺失值最多的列
data.drop(max_missing_col, axis=1, inplace=True)
#其中,`axis=1` 表示删除列,`inplace=True` 表示在原始数据上进行修改。
data
2.3 线性代数
2.3.1 & 2.3.2 & 2.3.3 标量&向量&矩阵
- 标量:只有一个元素的张量
- 向量:标量值(被称为元素/成分)组成的列表;(数学)具有一个轴的张量。
- 维度:向量的长度。 ⚠️张量的纬度表示张量具有的轴数
- 单个向量的默认方向是列向量
x = torch.arange(5)
len(x)
x.shape
- 矩阵:就是数学里的矩阵,有对称矩阵、正定矩阵、方阵等
- 转置:‘A.T’
- 一般将每个数据样本作为矩阵中的行向量,即列为属性
2.3.4 & 2.3.5 张量&张量算法的基本性质
张量:描述具有任意数量轴的n维数组的通用方法。(上述三种类型是张量的特例)
哈达玛积:即俩矩阵的按元素乘法
A * B
2.3.6 降维
- 降维有两种方式:
- 求和:‘A.sum()’
默认情况下,调用求和函数会沿所有的轴降低张量的维度,使它变为一个标量。 还可以指定张量沿哪一个轴来通过求和降低维度。
以矩阵为例,为了通过求和所有行的元素来降维(轴0),可以在调用函数时指定axis=0。 由于输入矩阵沿0轴降维以生成输出向量,因此输入轴0的维数在输出形状中消失。
A_sum_axis0 = A.sum(axis=0) # 求和所有行的元素
A_sum_axis0, A_sum_axis0.shape
- 求平均值:‘A.mean()’
同样,计算平均值的函数也可以沿指定轴降低张量的维度。
A.mean(axis=1), A.sum(axis=1) / A.shape[1]
- 非降维求和
sum_A = A.sum(axis=1, keepdims=True)
sum_A
A.cumsum(axis=0)
2.3.7 & 2.3.8 & 2.3.9 点积&矩阵-向量积&矩阵-矩阵乘法
这些就是数学中的概念,没啥区别
- 点积:两个向量之间的乘法<_x _, y>,相同位置的按元素乘积的和
torch.dot(x,y) # x,y为两个维度相同的向量
- 矩阵-向量积:矩阵与向量间的乘积
torch.mv(A,x) # 矩阵的列维数必须与向量的维数相同
- 矩阵-矩阵乘法:两个矩阵之间的乘法(数学),需要区别哈达玛积(按元素)
torch.mm(A,B)
2.3.10 范数
-
非正式地说,向量的范数是表示一个向量的分量有多大。
-
向量范数需满足三条性质:
-
缩放性质: f ( α x ) ] = ∣ α ∣ f ( x ) f(\alpha\mathbf{x})]=|\alpha|f(\mathbf{x}) f(αx)]=∣α∣f(x)
-
三角不等式: f ( x + y ) ] ≤ f ( x ) + f ( y ) f(\mathbf x+\mathbf y)]\le f(\mathbf x)+f(\mathbf y) f(x+y)]≤f(x)+f(y)
-
非负性: f ( x ) ≥ 0 f(\mathbf{x})\geq 0 f(x)≥0
-
-
向量的 L 2 L_2 L2范数: ∥ x ∥ 2 = ∑ i = 1 n x i 2 \|\mathbf{x}\|_2=\sqrt{\sum_{i=1}^n x_i^2} ∥x∥2=∑i=1nxi2;
-
向量的 L 1 L_1 L1范数: ∥ x ∥ 1 = ∑ i = 1 n ∣ x i ∣ ; \|\mathbf{x}\|_1=\sum_{i=1}^n|x_i|; ∥x∥1=∑i=1n∣xi∣;
-
矩阵的弗罗贝尼乌斯范数: ∥ X ∥ F = ∑ i = 1 m ∑ j = 1 n x i j 2 . \|\mathbf{X}\|_F=\sqrt{\sum_{i=1}^m\sum_{j=1}^n x_{ij}^2}. ∥X∥F=∑i=1m∑j=1nxij2.
u = torch.tensor([3.0, -4.0])
torch.norm(u) # L2范数
torch.abs(u).sum() # L1范数
torch.norm(torch.ones((4, 9))) #弗罗贝尼乌斯范数
- 范数其实对应的就是优化问题中的目标,如:最大化分配给观测数据的概率; 最小化预测和真实观测之间的距离… …
2.3.11 练习
-
对于任意形状的张量X,len(X)是否总是对应于X特定轴的长度?这个轴是什么?
总是对应轴0的长度 -
运行A/A.sum(axis=1),看看会发生什么。请分析一下原因?
报错:RuntimeError: The size of tensor a (3) must match the size of tensor b (2) at non-singleton dimension 1 原因:A.sum(axis=1)的结果是[3,12],不能通过广播机制也不能与A相除。若求和所有行元素,得到的是[3,5,7],可以通过广播机制变成2x3的矩阵,再进行按元素除法。 -
考虑一个具有形状(2,3,4)的张量,在轴0、1、2上的求和输出是什么形状?
分别是:(3,4),(2,4),(2,3)。对哪一轴求和,哪一轴的维数消失。