从零开始实现数据预处理流程

2021-06-15 17:03:06 浏览数 (1)

关注"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、平均数或者中位数等),即所谓的插值法;
代码语言:javascript复制
# 策略 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 中
代码语言:javascript复制
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 中
代码语言:javascript复制
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:

  1. 《机器学习实战》
  2. 《动手学深度学习》

0 人点赞