持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
在这篇文章中我们主要讲解一下 数据的操作 以及 数据预处理
数据操作
为了完成各种操作,我们需要某种方法来存储和操作数据。一般来说,需要做两件重要的事情:
(1)获取数据;
(2)在将数据读入计算机后对其进行处理。
张量创建
在这一小节,我们介绍下 维数组,也称为 张量(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分成inputs和outputs,其中前者为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
转换为张量
现在inputs和outputs中的所有条目都是数值类型,我们可以将其转换为张量格式。
import torch
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y
总结
数据预处理的方式还有很多,读者可以查询下其余资料了解其他的数据预处理技术。下篇我们主要讲解一下线性代数的运算知识,可以关注我,带你了解更多知识。