- Course Note: d2l-video-04 - 数据操作+数据预处理
- Jupyter Notebook: chapter_preliminaries/pandas.ipynb
预备知识中 Data Manipulation 和 Data Preprocessing 的部分
介绍
N 纬数组介绍
0-d (标量)
PLAINTEXT1.0
一个类别
1-d (向量)
PLAINTEXT[1.0, 2.7, 3.4]
一个特征向量
2-d (矩阵)
PLAINTEXT[[1.0, 2.7, 3.4], [1.0, 2.7, 3.4], [1.0, 2.7, 3.4]]
一个样本 - 特征矩阵
3-d RGB 图片(宽 x 高 x 通道)
PLAINTEXT[[[1.0, 2.7, 3.4], [1.0, 2.7, 3.4], [1.0, 2.7, 3.4]], [[1.0, 2.7, 3.4], [1.0, 2.7, 3.4], [1.0, 2.7, 3.4]]]
4-d 一个 RGB 图片批量 (批量大小 x 宽 x 高 x 通道)
PLAINTEXT[[[[... ... ...]]]]
5-d 一个视屏批量 (批量大小 x 时间 x 宽 x 高 x 通道)
Data Manipulation 数据操作
张量(tensor)表示一个数值表示的数组, 这个数组可能有多个纬度, 下面介绍一下 pytorch 里面基础的张量运算
创建张量
PYTHONimport torch x = torch.arange(12) shape = x.shape # 元素形状 num = x.numel() # 元素总数 X = x.reshape(3, 4) # 改变张量形状
生成张量
PYTHONtorch.zeros((2, 3, 4)) # 形状为 2x3x4 的全0张量 torch.ones((2, 3, 4)) # 形状为 2x3x4 的全1张量 torch.randn(3, 4) # 形状为 3 x 4 的随机张量 torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) # 通过py数组生成张量
张量运算
PYTHONx = torch.tensor([1.0, 2, 4, 8]) # .0 表示为浮点数, 会转换为浮点数张量, 而不是整数 y = torch.tensor([2, 2, 2, 2]) x + y, x - y, x * y, x / y, x ** y # 对应位置的元素进行标准运算
按照行 或 列 连结(concatenate) 在一起
PYTHONX = torch.arange(12, dtype=torch.float32).reshape((3,4)) # shape: 3x4 Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) # shape: 3x4 torch.cat((X, Y), dim=0) # 第0纬(外层)连结: 变成6x8 torch.cat((X, Y), dim=1) # 第1纬(内存)连结: 变成3x8
通过逻辑运算符构建二元张量
PYTHONX == Y
张量所有元素求和
PYTHONX.sum()
即使形状不同, 仍然可以通过调用 广播机制(broadcasting mechanism) 来执行按元素操作
PYTHON# 使用 广播机制(broadcasting mechanism) 将形状不同的元素相加 a = torch.arange(3).reshape((3, 1)) b = torch.arange(2).reshape((1, 2)) # 将 a 3x2 复制为 3x2 的矩阵 # 将 b 1x2 复制为 3x2 的矩阵 a + b
选择元素
PYTHONX[-1], X[1:3] # 使用下标, 切片获取元素 X[1, 2] = 9 # 使用指定索引修改元素 X[0:2, :] = 12 # 为多个元素复制 (第一纬度中的 0,1 全部赋值为12)
内存相关
内存重新分配PYTHONbefore = id(Y) Y = Y + X # 这里加法导致Y内存重新分配 id(Y) == before # False
执行原地操作
PYTHONZ = torch.zeros_like(Y) print('id(Z):', id(Z)) # 使用X[:] = X + Y或X += Y来减少操作的内存开销 Z[:] = X + Y print('id(Z):', id(Z)) # 与上 print 输出相同 before = id(X) X += Y id(X) == before # True
类型转换
转换为NumPy张量 (ndarray)PYTHONA = X.numpy() B = torch.tensor(A) type(A), type(B) #> (numpy.ndarray, torch.Tensor)
将大小为1的张量转换为Python标量
PYTHONa = torch.tensor([3.5]) a, a.item(), float(a), int(a) #> (tensor([3.5000]), 3.5, 3.5, 3)
Data Preprocessing 数据预处理
csv 全称 Comma-Seperated Values 即逗号分开的值, 是一种文本文件格式, 用来存储表格数据, 数据项之间通常用逗号分隔, 行与行之间用换行符分隔. 实际上, 可以使用其他符号, 例如;来做分隔符
下面通过一个读取csv文件的例子, 说明如何将csv中的数据读入 pytorch
首先构造一个csv文件
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)
会得到如下表格(第一列索引不是表格内容)
NumRooms | Alley | Price | |
---|---|---|---|
0 | NaN | Pave | 127500 |
1 | 2.0 | NaN | 106000 |
2 | 4.0 | NaN | 178100 |
3 | NaN | NaN | 140000 |
为了处理缺失的数据, 常使用插值和删除的方法, 这里使用插值
# inputs: 所有行, 前两列数据, 房间数量和小巷
# outputs: 所有行, 最后一列数据, 价格
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
# 使用 pd.get_dummies() 将 Alley 分成两类, dummy_na 表示是否为缺失值(NaN)创建一个新的独热编码列
# 当 dummy_na=True 时, 如果原始数据中有缺失值(NaN), 函数会创建一个新的列, 列名为原列名_nan, 并用True来标记所有原始值为NaN的行
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)
NumRooms | Alley_Pave | Alley_nan | |
---|---|---|---|
0 | NaN | True | False |
1 | 2.0 | False | True |
2 | 4.0 | False | True |
3 | NaN | False | True |
# 使用平均值填充
inputs = inputs.fillna(inputs.mean())
print(inputs)
NumRooms | Alley_Pave | Alley_nan | |
---|---|---|---|
0 | 3.0 | 1 | 0 |
1 | 2.0 | 0 | 1 |
2 | 4.0 | 0 | 1 |
3 | 3.0 | 0 | 1 |
最后转换为 torch 张量
import torch
X = torch.tensor(inputs.to_numpy(dtype=float))
y = torch.tensor(outputs.to_numpy(dtype=float))
X, y
输出
(tensor([[3., 1., 0.],
[2., 0., 1.],
[4., 0., 1.],
[3., 0., 1.]], dtype=torch.float64),
tensor([127500., 106000., 178100., 140000.], dtype=torch.float64))
深度学习更多使用 float32 类型运算, 64位太慢了