关注"AI机器学习与深度学习算法"公众号
前言
众所周知,训练机器学习模型的目标是提高模型的泛化能力,通常使用测试集误差来近似模型在现实世界的泛化误差。为了能用机器学习来解决现实世界的问题,我们通常需要对从现实世界中获取的数据进行预处理操作。本文需要使用两个软件包:
- 数据分析软件包 Pandas。在 Python 中常用的数据分析工具中,通常使用 pandas 软件包。Pandas 软件包可以很方便的从 CSV、JSON、SQL、Microsoft Excel 文件格式中导入数据,并通过 Pandas 软件包中的 API 对导入的数据进行处理。
- 机器学习软件包 sklearn。sklearn 是 Python 第三方提供的非常强力的机器学习库,它包含了从数据预处理到训练模型的各个方面。
本文主要包括以下几个内容:
- 创建一个人工数据集,使用 Pandas 软件包对数据集进行读取;
- 使用三种策略对缺失值进行处理;
- 使用 sklearn 软件包处理文本标签;
- 转换为 PyTorch 和 TensorFlow 使用的张量格式;
读取数据集
首先创建一个人工的数据集,并存储在 csv(逗号分隔值)文件 "./data/iris.csv"。下面我们将数据集按行写入 csv 文件中(从鸢尾花数据集中随机选取 5 个样本,并截取前两个样本特征)。
代码语言:javascript复制import os
# iris.csv文件路径
data_file = os.path.join('.', 'data', 'iris.csv')
# 往iris.csv文件中写入数据
with open(data_file, 'w') as f:
f.write("SepalLength,SepalWidth,Namen") # 列名
f.write("4.9,3.,setosan") # 每行代表一个数据样本
f.write("5.,3.4,setosan")
f.write("NA,2.4,versicolorn")
f.write("7.4,2.8,virginican")
f.write("NA,3.,virginican")
要从创建的 csv 文件中加载原始数据集,我们导入 pandas 包并调用 read_csv 函数。该数据集有五行三列。其中每行描述了花萼长度("SepalLength")、花萼宽度("SepalWidth")和鸢尾花的类别("Name")。
代码语言:javascript复制import pandas as pd
data = pd.read_csv(data_file)
print(data)
SepalLength SepalWidth Name
0 4.9 3.0 setosa
1 5.0 3.4 setosa
2 NaN 2.4 versicolor
3 7.4 2.8 virginica
4 NaN 3.0 virginica
处理缺失值
产生缺失值(NaN)的情况非常常见,而拥有缺失值的特征对大多数机器学习任务都是不利的,因此我们需要对缺失值进行处理。处理缺失值有以下三种策略:
- 策略 1:删除拥有缺失值的样本,即删除拥有缺失值的行;
- 策略 2:删除拥有缺失值的特征,即删除拥有缺失值的列;
- 策略 3:将缺失值设置为某个值(0、平均数或者中位数等),即所谓的插值法;
# 策略 1
data = data.dropna(subset = ['SepalLength']) # 指定SepalLength列
# 策略 2
data = data.drop("SepalLength", axis = 1) # 删除SepalLength列
# 策略 3
data = data.fillna(0) # NaN设置为0
mean = data.mean()
data = data.fillna(mean) # NaN设置为平均数
median = data.median()
data = data.fillna(median) # NaN设置为中位数
处理文本标签
鸢尾花数据集是经典的分类数据集,根据鸢尾花的花萼和花瓣特征分类具体的鸢尾花,Name 列为具体的类别标签。
通过位置索引 iloc,我们将 data 分成 inputs 和 outputs,其中前者为 data 的前两列,而后者为 data 的最后一列。inputs 为数据集的特征,而 outputs 为对应的类别标签。由于 Name 列没有缺失值,因此将 data 分成 inputs 和 outputs 之前对缺失值进行处理,划分和处理缺失值的顺序视具体情况而定。
代码语言:javascript复制# data中的缺失值已替换成中位数
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
print(inputs)
# SepalLength SepalWidth
# 0 4.9 3.0
# 1 5.0 3.4
# 2 5.0 2.4
# 3 7.4 2.8
# 4 5.0 3.0
print(outputs)
# 0 setosa
# 1 setosa
# 2 versicolor
# 3 virginica
# 4 virginica
# Name: Name, dtype: object
机器学习算法更易于和数字打交道,所以我们需要将 outputs 文本标签转换为数字编码。sklearn 提供了方便转换的 LabelEncoder 类。
代码语言:javascript复制from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
outputs_encoded = encoder.fit_transform(outputs)
print(outputs_encoded)
# [0 0 1 2 2]
可以使用 classes_ 属性来查看这个编码器已学习的文本标签与数字编码的映射。
代码语言:javascript复制print(encoder.classes_)
# ['setosa' 'versicolor' 'virginica']
转换为张量的格式
此时的 inputs 和 outputs 中的所有条目都是数值类型,它们可以转换为张量格式。
代码语言:javascript复制print(type(inputs))
# <class 'pandas.core.frame.DataFrame'>
print(type(outputs_encoded))
# <class 'numpy.ndarray'>
在 PyTorch 和 TensorFlow 深度学习框架中,提供了很多 API 能够方便的将 NumPy 中的 ndarray 数组转换为张量格式。此时 inputs 为 DataFrame 类型,我们可以使用 values 属性获取具体的 ndarray 数组。
代码语言:javascript复制print(type(inputs.values))
# <class 'numpy.ndarray'>
- 在 PyTorch 中
import torch
X, y = torch.tensor(inputs.values), torch.tensor(outputs_encoded)
print(X, y)
# tensor([[4.9000, 3.0000],
# [5.0000, 3.4000],
# [5.0000, 2.4000],
# [7.4000, 2.8000],
# [5.0000, 3.0000]], dtype=torch.float64) tensor([0, 0, 1, 2, 2])
- 在 TensorFlow 中
import tensorflow as tf
X, y = tf.constant(inputs.values), tf.constant(outputs_encoded)
print(X, y)
# tf.Tensor(
# [[4.9 3. ]
# [5. 3.4]
# [5. 2.4]
# [7.4 2.8]
# [5. 3. ]], shape=(5, 2), dtype=float64) tf.Tensor# ([0 0 1 2 2], shape=(5,), dtype=int32)
References:
- 《机器学习实战》
- 《动手学深度学习》