课程主页:https://courses.d2l.ai/zh-v2
教材:https://zh-v2.d2l.ai/
课程论坛讨论:https://discuss.d2l.ai/c/16
Pytorch论坛:https://discuss.pytorch.org/
温故而知新!!!
转载链接:数据预处理
读取数据集
创建一个人工数据集,并存储在CSV(逗号分隔值)文件 ../data/house_tiny.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', encoding = 'utf8') 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文件中加载原始数据集,需导入pandas
包并调用read_csv
函数。读取数据集成功后,可知数据集有四行三列,每行描述了房间数量(”NumRooms“)、巷子类型(“Alley”)和房屋价格(“Price”)
# 如果没有安装pandas,只需取消对以下行的注释来安装pandas
# pip install pandas
import pandas as pd
data = pd.read_csv(data_file)
print(data)
一、处理缺失值
"NAN"
项代表缺失值。两种典型的处理确实的数据的方法为:插值法+删除法。其中,插值法用一个替代值弥补缺失值,删除法则直接忽略缺失值。
1、插值法
通过位置索引iloc
,将data分成inputs
和outputs
,inputs
为data的前两列,outputs
为data的最后一列。对于inputs
中缺少的数值,用同一列的均值替换"NAN"
项。
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean())
print(inputs)
对于inputs
中的类别值或离散值,将“NA”
视为一个类别。由于”箱子类型“(Alley)列只接收两种类型的类别值“Pave”
和"NA"
,pandas
可以自动将此列转换为两列”Alley_Pave“
和"Alley_nan"
。
inputs = pd.get_dummies(inputs, dummy_na = False)
print(inputs)
2、删除法
a) 按行删除
方案一:删除缺失值最多的行。即删除第0行和第3行。
NaNum = data.isna().sum(axis = 1)
res = [i for i, v in enumerate(NaNum) if v == max(NaNum)]
data.drop(res)
代码解读:
1) data.isna()
将数据转换为bool矩阵,存在数据缺失则值为True。由下图可知,NA被视为一种类型,没有算作数据缺失。因此该数据集仅有两个地方有数据缺失,即NumRooms列下的两个True值对应的地方。
2) NaNum = data.isna().sum(axis = 1)
计算每行缺失数据的个数
3) res = [i for i, v in enumerate(NaNum) if v == max(NaNum)]
计算缺失值最多的行的索引。如本数据集中第0行和第3行缺失个数最多。
4) data.drop(res)
删除对应的行
方案二:当某个特定属性缺失时,删除该行。
如若NumRooms属性缺失(即第0列数据有缺失),则删除该行,代码如下:
NaNum = data.iloc[:, 0].isna()
res = [i for i, v in enumerate(NaNum) if v == True]
data.drop(res)
方案三:只要存在数据缺失,便删除该行。
NaNum = data.isna().sum(axis = 1)
res = [i for i, v in enumerate(NaNum) if v > 0]
data.drop(res)
b) 按列删除
方案一:删除缺失值最多的列。即删除第0列。
col = data.columns[data.isna().sum(axis = 0).argmax()]
NewData = data.drop(col, axis = 1)
print(NewData)
代码解读:
1) data.isna()
将数据转换为bool矩阵,存在数据缺失则值为True。由下图可知,NA被视为一种类型,没有算作数据缺失。因此该数据集仅有两个地方有数据缺失,即NumRooms列下的两个True值对应的地方。
2) data.isna().sum(axis = 0)
统计每列缺失数据的个数。
3) argmax()
得到最大数值的索引值,如NumRooms的索引值为0,因此结果为0。
4) data.columns[index]
获取对应的列名(属性名)
5) data.drop(ColName, axis = 0)
删除对应的列。注意该命令不会改变原始的数据集,如下图data的值并没有改变。
方案二:只要存在数据缺失,便删除该属性(该列)。即删除第0列
NaNum = data.isna().sum(axis = 0)
res = [i for i,v in enumerate(NaNum) if v > 0]
col = data.columns[res]
data.drop(col, axis = 1)
二、转换为张量格式
目前,inputs
和outputs
中的所有条目都是数值类型,它们可以转换为张量格式,如将经过插值法处理后的数据集转换为张量格式。
import torch
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y
三、提问记录
问题一: reshape()
和view()
函数的区别
解答:参考文章PyTorch:view() 与 reshape() 区别详解。个人总结为reshape()
包含了view()
的功能,且鲁棒性更强一些。两种使用场景如下:
1) 满足连续性条件的tensor,reshape()
和view()
的功能一样,都是一个浅拷贝,数据存储的物理地址没变,只是改变了数据的索引方式
2)不满足连续性条件的tensor,reshape() = contiguous() + view()
,是一个深拷贝,新开辟一个物理空间,将数据复制一份到该空间,再对该副本的索引方式进行改变。因此该情况下直接使用view()
函数将会报错,需先调用contiguous()
将tensor变为连续的,再使用view()
。