(一)数据操作的理论
我们在机器学习中所用到的最多的数据结构是数组。所以我们先对数组进行操作。
(1)N维数组
- 0维:一个点
- 一维:一行数字
- 二维:矩阵,可以是一个样本的特征矩阵
- 三维:一张彩色图片
- 四维:一个批量的图片(一堆图片),也就是常说的一个batch。
- 五维:一个视频,在四维的基础上
加上时间维度。
(2)创建数组
创建数组时,我们需要给三个信息:
- 形状:3x3的矩阵
- 数据类型:浮点数
- 每个元素的值:是单位阵还是随机
(3)访问数组
[1, 2]: 一行二列
[1, :]: 第一行所有
[:, 1]: 第一列所有
[1:3, 1:]: 行的区间是[1, 3), 列的区间是[1, :]
[::3,::2]: 行的区间是隔三行取一行,列的区间是隔两行取一行。
有时候还可以使用-1来选中最后一行或者列。
(二)数据操作的理实操
在torch里面,用张量来表示数组。
张良表示一个数值组成的数组,这个数组可能有多个维度。
(1)一些API
首先,我们可以使用 arange
创建一个行向量 x
。这个行向量包含以0开始的前12个整数,它们默认创建为整数。也可指定创建类型为浮点数。张量中的每个值都称为张量的 元素(element)。例如,张量 x
中有 12 个元素。除非额外指定,新的张量将存储在内存中,并采用基于CPU的计算。
可以使用reshape
来改变一个张量的形状。但是如果你输入的参数不对的话,就会报错。
全零矩阵zeros
.
全一矩阵ones
.
随机数randn
或者直接用数组创建张量。
对说有的元素求和
(2)运算符
也可以做指数运算
使用cat
对张量进行堆叠dim=0,按行堆叠,dim=1按列堆叠。
可以使用逻辑运算符生成二元张量
(3)广播机制
它通过复制的手段,将两个本来不能够运算的矩阵,弄得形状一样,就能够运算了。
(4)索引和切片
这些操作都较为简单。
(5)内存节省
我们在以往的编程过程中,总以为x = x+y这里的x的内存地址和原来的是一样的。然而在torch中会重新分配一个内存。也就是原来的x仍然存在内存中。这样对神经网络的驯良往往是不利的。所以要避免这样的使用。
有两种解决方案:
- x += y
-
x[:] = x+y
(6)numpy、tensor、python标量之间的转换
(三)数据预处理
创建一个人工数据集,并存储为csv(逗号分隔值)文件
import os
import torch
# 在上一级目录中创建文件夹 data
os.makedirs(os.path.join('..','data'),exist_ok=True)
# 进入data文件夹,并创建houses_tiny.csv
data_file = os.path.join("..","data",'houses_tiny.csv')
print(data_file)
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')
读取csv文件
import pandas as pd
data = pd.read_csv(data_file)
print(data)
这中间时候这种NaN这样的数据,我们如何去处理这样的数据,这就叫做数据预处理,而且对后面训练模型也是极为重要的。
我们常用的方法就是,如果一行中有NaN这样的数据,就将这一行直接丢掉。
当然我们可以插值。
inputs, outputs = data.iloc[:,0:2], data.iloc[:,2]
inputs = inputs.fillna(inputs.mean()) # 以下两种写法一致
inputs['NumRooms'] = inputs['NumRooms'].fillna(inputs['NumRooms'].mean()) # 使用一列的平均值进行填充
print(inputs.mean())
print(inputs)
print(outputs)
那对于不是数值的值我们如何处理呢?我们可以将NaN也可以看作是一个类别。
首先先看一下get_dummies这个函数的文档说明,我们可以将其当作是快速one-hot的方法。
>>> s = pd.Series(list('abca'))
>>> pd.get_dummies(s)
a b c
0 1 0 0
1 0 1 0
2 0 0 1
3 1 0 0
>>> s1 = ['a', 'b', np.nan]
>>> pd.get_dummies(s1)
a b
0 1 0
1 0 1
2 0 0
>>> pd.get_dummies(s1, dummy_na=True)
a b NaN
0 1 0 0
1 0 1 0
2 0 0 1
>>> df = pd.DataFrame({'A': ['a', 'b', 'a'], 'B': ['b', 'a', 'c'],
... 'C': [1, 2, 3]})
>>> pd.get_dummies(df, prefix=['col1', 'col2'])
C col1_a col1_b col2_a col2_b col2_c
0 1 1 0 0 1 0
1 2 0 1 1 0 0
2 3 1 0 0 0 1
>>> pd.get_dummies(pd.Series(list('abcaa')))
a b c
0 1 0 0
1 0 1 0
2 0 0 1
3 1 0 0
4 1 0 0
>>> pd.get_dummies(pd.Series(list('abcaa')), drop_first=True)
b c
0 0 0
1 1 0
2 0 1
3 0 0
4 0 0
>>> pd.get_dummies(pd.Series(list('abc')), dtype=float)
a b c
0 1.0 0.0 0.0
1 0.0 1.0 0.0
2 0.0 0.0 1.0
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)
现在inputs和outputs的数据处理都完成了,就可以将其转换成张量的形式了。并且里面的值都是64位的浮点数。
x, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
print(x,y)
注意:reshape()返回值是不会重新分配内存空间的,他返回的是原来的tensor的地址
a = torch.tensor([1,2,3,4])
b = a.reshape((2,2))
print(b)
b[:] = 5
print(a,b)
# 解决方法
a = torch.tensor([1,2,3,4])
b = a.clone().reshape((2,2))
print(b)
b[:] = 5
print(a,b)
tensor([[1, 2],
[3, 4]])
tensor([5, 5, 5, 5]) tensor([[5, 5],
[5, 5]])
tensor([[1, 2],
[3, 4]])
tensor([1, 2, 3, 4]) tensor([[5, 5],
[5, 5]])