一文带你了解深度学习的前置预备知识(中)

1,820 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

在这篇文章中我们主要讲解一下 数据的操作 以及 数据预处理

数据操作

为了完成各种操作,我们需要某种方法来存储和操作数据。一般来说,需要做两件重要的事情: (1)获取数据;
(2)在将数据读入计算机后对其进行处理。

张量创建

在这一小节,我们介绍下 nn维数组,也称为 张量(tensor)。现有的比较流行的深度学习框架(PyTorch 和TensorFlow中为Tensor),这些框架中的张量类可以更好的使用GPU进行加速计算,而且支持自动微分。

张量表示由一个数值组成的数组,这个数组可能有多个维度。

  • 具有一个轴的张量对应数学上的向量(vector);
  • 具有两个轴的张量对应数学上的矩阵(matrix);
  • 具有两个轴以上的张量没有特殊的数学名称。

1. 张量的创建

张量中的每个值都称为 张量的元素(element)。

(1)行向量

使用arange创建一个行向量x,这个行向量包含从0开始的前12个整数,它们被默认创建为浮点数。

import torch   # 使用PyTorch框架,注意导入名称写 torch 而不是pytorch

x = torch.arange(12)
x           # tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])

(2)矩阵

除了向量,我们也可以 使用全0、全1、其他常量或者从特定分布中随机采样的数字 来初始化一个矩阵。例如我们创建一个形状为(2,3,4)的张量,其中所有元素都设置为0。

torch.zeros((2, 3, 4))

# 运行结果
tensor([[[0., 0., 0., 0.], 
         [0., 0., 0., 0.], 
         [0., 0., 0., 0.]], 
         
        [[0., 0., 0., 0.], 
         [0., 0., 0., 0.], 
         [0., 0., 0., 0.]]])

那么同样我们只要使用 torch.ones((2,3,4))就可以创建一个全为1的2维3行4列的矩阵。

2. 张量的访问以及修改

  • 通过张量的shape属性来访问张量的 形状(沿每个轴的长度)
x.shape     # 运行结果为 torch.Size([12])
  • 使用reshape函数改变一个张量的形状而不改变元素数量和元素值
# 把张量`x`从形状为(12,)的行向量转换为形状为(3,4)的矩阵。
X = x.reshape(3, 4)
print(X)        

# 运行结果
tensor([[ 0, 1, 2, 3], 
        [ 4, 5, 6, 7], 
        [ 8, 9, 10, 11]])
        

对于已经指定了行和列的张量,我们也可以在改变的位置放置'-1' ,令张量自动计算维度。使用x.reshape(-1,4)x.reshape(3,-1)来取代x.reshape(3,4)

  • 通过检查张量的大小(size)可以得到张量中元素的总数。
print(x.numel)   # 12
print(X.numel)   # 12

注意:
转换后的张量虽然被当做一个 3行4列 的矩阵使用,但这个矩阵里面的值与转换前的张量是相同的。这里要重点记忆一下,虽然张量的形状发生了改变,但其元素值并没有变。
改变张量的形状,并不会改变张量的大小。

张量运算

1. 按元素计算
对于任意具有相同形状的张量,常见的标准算术运算符(+-*/**)都可以被升级为按元素运算。我们可以在同一形状的任意两个张量上调用按元素操作。

x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y   # **运算符是求幂运算

# 运算结果
tensor([ 3., 4., 6., 10.]),
tensor([-1., 0., 2., 6.]), 
tensor([ 2., 4., 8., 16.]),
tensor([0.5000, 1.0000, 2.0000, 4.0000]),
tensor([ 1., 4., 16., 64.]))

2. 线性代数运算(向量点积、矩阵乘法)
对于这部分知识呢,我们在 下一篇文章中 详细阐述。

3. 张量连结
将多个张量 连结(concatenate)在一起,把它们端对端地叠成一个更大的张量。 我们只需要提供张量列表,并给出沿哪个轴连结。

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)   # 沿行(轴 0) 的长度连结  , 3+3 6行
torch.cat((X, Y), dim=1)   # 沿列(轴 1)的长度连结 , 4+4 8列

# 运行结果
(tensor([[ 0., 1., 2., 3.], 
         [ 4., 5., 6., 7.], 
         [ 8., 9., 10., 11.], 
         [ 2., 1., 4., 3.], 
         [ 1., 2., 3., 4.], 
         [ 4., 3., 2., 1.]]), 
 tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.], 
         [ 4., 5., 6., 7., 1., 2., 3., 4.], 
         [ 8., 9., 10., 11., 4., 3., 2., 1.]]))

广播机制

在上面的部分中,我们看到了如何在相同形状的两个张量上执行按元素操作。但是在某些情况下,即使形状不同,我们仍然可以通过调用广播机制(broadcasting mechanism)来执行按元素操作

工作方式如下:首先,通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状。其次,对生成的数组执行按元素操作。大多数情况下,沿着数组中长度为1(列)的轴进行广播,如下例子:

a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b
    # 运行结果
    (tensor([[0], 
            [1], 
            [2]]), 
     tensor([[0, 1]]))
 
 # 广播机制  
 a + b   # 矩阵a复制列,矩阵b复制行,然后再按元素相加。
 
     tensor([[0, 1], 
             [1, 2], 
             [2, 3]])

数据预处理

我们前面介绍了处理存储在张量中数据的各种技术,但是为了能用深度学习来解决现实世界的问题,我们经常是从预处理原始数据开始,而不是从那些准备好的张量格式数据开始。在Python中常用的数据分析工具中,通常使用pandas软件包,它可以很好的与张量兼容。因此,本部分我们主要介绍使用pandas预处理原始数据并将原始数据转换为张量格式的步骤。

读取数据集

我们首先创建一个人工数据集,并存储在csv(逗号分隔值)文件

import os

os.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'student.csv')
with open(data_file, 'w') as f:
    f.write('Age,Marry,Income\n')  # 列名
    f.write('20,0,10000\n')  # 每行表示一个数据样本
    f.write('18,0,8000\n')
    f.write('NA,1,6000\n')
    f.write('NA,1,6000\n')

处理缺失值

“NaN”项代表缺失值。**为了处理缺失的数据,典型的方法包括插值删除。其中插值用替代值代替缺失值,而删除则忽略缺失值。

这里我们使用插值。通过位置索引iloc,将data分成inputsoutputs,其中前者为data的前两列,后者为data的最后一列。对于inputs中缺少的数值,我们用同一列的均值替换“NaN”项。

inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean())
print(inputs)

# 运行结果
   Age   Marry 
 0 20.0   0 
 1 18.0   0
 2 19.0   1 
 3 19.0   1

转换为张量

现在inputsoutputs中的所有条目都是数值类型,我们可以将其转换为张量格式。

import torch

X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y

总结

数据预处理的方式还有很多,读者可以查询下其余资料了解其他的数据预处理技术。下篇我们主要讲解一下线性代数的运算知识,可以关注我,带你了解更多知识。