数据操作
N维数组是机器学习和神经网络的主要数据结构:
- 0-d(标量):[1.0]
- 1-d(向量):[1.0, 2.7, 3.4]
- 2-d(矩阵):[[1.0, 2.7, 3.4], [5.0, 0.2, 4.6]]
- 3-d、4-d、5-d等
创建数组需要的参数包括:
- 形状:例如3 * 4矩阵
- 每个元素的数据类型:例如32位浮点数
- 每个元素的值:例如全部设置为0,或全部设置为随机数
访问元素的方式:
- 单个元素访问:如[1, 2],即访问第1行第2列的元素
- 一行访问:如[1, :],即访问第1行上的所有元素
- 一列访问:如[:, 1],即访问第1列上的所有元素
- 连续子区域访问:如[1:3, 1:],即访问位于第1行到第2行(冒号规定区间为左闭右开)、且位于第1列之后的所有元素
- 非连续子区域访问:如[::3, ::2],即位于从第0行开始每三行(第0、3、6…行)上、且位于从第0列开始每两列(第0、2、4…列)上的所有元素
后续要学习的是在Python中的数据操作实现与数据预处理实现。
数据操作实现
Pytorch中的数据操作相关方法:
arrange()
函数可以根据指定范围及步长,生成一个包含等间隔数值的一维张量
1 2 3
| import torch x = torch.arange(12) print(x)
|
- 通过
numel()
函数可以返回张量中元素的总数量(即"number of elements")
- 通过
reshape()
函数可以不改变元素数量和元素值,而改变一个张量的形状
1 2 3 4 5
| x = x.reshape(3, 4) print(x)
|
- 通过
zeros()
与ones()
函数可以生成全0、全1的张量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| print(torch.zeros(2, 3, 4))
print(torch.ones(2, 3, 4))
|
- 通过
tensor()
方法与提供包含数值的Python列表或嵌套列表,可以为生成张量的每个元素赋予确定值
1 2 3 4
| print(torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]))
|
- 常见的算术预运算(+、-、*、/、**(求幂))均可被升级为按元素运算
1 2 3 4 5 6 7 8
| x = torch.tensor([1.0, 2, 4, 8]) y = torch.tensor([2, 2, 2, 2]) print(x + y, x - y, x * y, x / y, x ** y)
|
- 可以使用
cat()
将多个张量进行联结,并用dim
参数指定联结方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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]])
print(torch.cat((X, Y), dim=0))
print(torch.cat((X, Y), dim=1))
|
- 使用
sum()
可以对张量中的所有元素进行求和,生成一个只有一个元素的张量(标量)
- 在pytorch中,对于同维数但不同形状的张量,可以通过调用广播机制执行按元素操作。原理为将两个张量扩展至相同大小,扩展后新生成的元素使用原有元素进行复制
1 2 3 4 5 6
| a = torch.arange(3).reshape((3, 1)) b = torch.arange(2).reshape((1, 2)) print (a + b)
|
- 可以使用
[-1]
选择最后一个元素,可以使用[1:3]
选择第二、第三个元素(左闭右开,如上文)
1 2 3 4 5
| print(X[-1])
print(X[1:3])
|
- 为多个元素赋相同的值,只需要索引全部这些元素并赋值即可
1 2 3 4 5
| X[0:2, :] = 9 print(X)
|
- 运行一些操作会导致为新结果分配新内存位置,举例如下
1 2 3
| before = id(Y) Y = Y + X print(id(Y) == before)
|
- 如果想要操作后不改变内存位置(执行原地操作),需要提前设置一个空张量当作内存区域
1 2 3 4
| Z = torch.zeros_like(Y) print('id(Z):', id(Z)) Z[:] = X + Y print('id(Z):', id(Z))
|
- 也可以通过
X[:] = X + Y
或X += Y
的方式实现原地操作,减小内存开销
1 2 3
| before = id(X) X += Y print(id(X) == before)
|
Pytorch张量可以使用numpy()
与tensor()
和Numpy张量进行相互转化
1 2 3
| A = X.numpy() B = torch.tensor(A) print(type(A), type(B))
|
大小为1的张量可以使用不同手段转化为Python标量
1 2
| a = torch.tensor([3.5]) print(a, a.item(), float(a), int(a))
|
数据预处理实现
数据预处理用于读取原始数据,使之能够被后续处理。在本例中,首先创建一个人工数据集,并使用一个csv(每一行是一个数据,不同域由逗号分隔)文件进行储存:
1 2 3 4 5 6 7 8 9 10
| 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')
|
可以使用Pandas库,使用其read_csv()
方法,由创建的csv文件中读取数据集:
1 2 3 4 5 6 7 8 9 10 11
| 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 """
|
为了处理丢失的数据(NaN),可以采取插值或删除(删除整行或整列)的方法。此处采取插值法。对于属性值为数的行,可以采用均值差值:
1 2 3 4 5 6 7 8 9 10 11 12
| inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs.iloc[:, 0] = inputs.iloc[:, 0].fillna(inputs.iloc[:, 0].mean())
print(inputs) """ 输出: NumRooms Alley 0 3.0 Pave 1 2.0 NaN 2 4.0 NaN 3 3.0 NaN """
|
对于属性值为类别值或离散值(如Alley列中的值为字符串),可以使用Pandas的get_dummies
方法,将每个离散值视为一个新属性,并用True、False(0、1)表示该行数据是否拥有该属性:
1 2 3 4 5 6 7 8 9 10
| inputs = pd.get_dummies(inputs, dummy_na=True, dtype=int)
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 """
|
至此inputs与outputs中包含所有内容均为数值类型,可以使用torch.tensor()
转化为张量格式:
1 2 3 4 5 6 7 8 9 10
| import torch X, y = torch.tensor(inputs.values), torch.tensor(outputs.values) print(X, y) """ 输出(python默认浮点数为float64): tensor([[3., 1., 0.], [2., 0., 1.], [4., 0., 1.], [3., 0., 1.]], dtype=torch.float64) tensor([127500, 106000, 178100, 140000]) """
|