• Course Note: d2l-video-04 - 数据操作+数据预处理
  • Jupyter Notebook: chapter_preliminaries/pandas.ipynb

预备知识中 Data Manipulation 和 Data Preprocessing 的部分

介绍

N 纬数组介绍

  • 0-d (标量)

    1.0
    

    一个类别

  • 1-d (向量)

    [1.0, 2.7, 3.4]
    

    一个特征向量

  • 2-d (矩阵)

    [[1.0, 2.7, 3.4],
     [1.0, 2.7, 3.4],
     [1.0, 2.7, 3.4]]
    

    一个样本 - 特征矩阵

  • 3-d RGB 图片(宽 x 高 x 通道)

    [[[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 通道)

    [[[[...
        ...
        ...]]]]
    
  • 5-d 一个视屏批量 (批量大小 x 时间 x 宽 x 高 x 通道)

Data Manipulation 数据操作

张量(tensor)表示一个数值表示的数组, 这个数组可能有多个纬度, 下面介绍一下 pytorch 里面基础的张量运算

  • 创建张量

    import torch
    x = torch.arange(12)
    
    shape = x.shape     # 元素形状
    num = x.numel()     # 元素总数
    X = x.reshape(3, 4) # 改变张量形状
    
  • 生成张量

    torch.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数组生成张量
    
  • 张量运算

    x = 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) 在一起

    X = 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
    

    通过逻辑运算符构建二元张量

    X == Y
    

    张量所有元素求和

    X.sum()
    

    即使形状不同, 仍然可以通过调用 广播机制(broadcasting mechanism) 来执行按元素操作

    # 使用 广播机制(broadcasting mechanism) 将形状不同的元素相加
    a = torch.arange(3).reshape((3, 1))
    b = torch.arange(2).reshape((1, 2))
    
    # 将 a 3x2 复制为 3x2 的矩阵
    # 将 b 1x2 复制为 3x2 的矩阵
    a + b
    
  • 选择元素

    X[-1], X[1:3]  # 使用下标, 切片获取元素
    X[1, 2] = 9    # 使用指定索引修改元素
    X[0:2, :] = 12 # 为多个元素复制 (第一纬度中的 0,1 全部赋值为12)
    
  • 内存相关
    内存重新分配

    before = id(Y)
    Y = Y + X      # 这里加法导致Y内存重新分配
    id(Y) == before
    # False
    

    执行原地操作

    Z = 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)

    A = X.numpy()
    B = torch.tensor(A)
    type(A), type(B)
    #> (numpy.ndarray, torch.Tensor)
    

    将大小为1的张量转换为Python标量

    a = 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)

会得到如下表格(第一列索引不是表格内容)

NumRoomsAlleyPrice
0NaNPave127500
12.0NaN106000
24.0NaN178100
3NaNNaN140000

为了处理缺失的数据, 常使用插值和删除的方法, 这里使用插值

# 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)
NumRoomsAlley_PaveAlley_nan
0NaNTrueFalse
12.0FalseTrue
24.0FalseTrue
3NaNFalseTrue
# 使用平均值填充
inputs = inputs.fillna(inputs.mean())
print(inputs)
NumRoomsAlley_PaveAlley_nan
03.010
12.001
24.001
33.001

最后转换为 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位太慢了