2.4 数据清洗和处理
数据清洗和处理是数据预处理过程的一部分,它涉及对原始数据进行修复、填充、删除和转换,以使其适合用于训练和测试机器学习模型。
2.4.1 处理缺失值
假设有一个CSV文件room.csv,其中包含有关房屋的信息,如下所示:
area,rooms,price
1200,3,250000
1000,,200000
1500,4,300000
,,180000
在这个CSV文件中,数据中存在缺失值,例如某些行的'rooms'列为空。此时可以使用TFT来处理这些缺失值,同时对数据进行标准化,下面的实例演示这一用法。
实例2-17:使用TFT处理CSV文件中的缺失值(源码路径:daima/2/que.py)
实例文件que.py的具体实现代码如下所示。
import apache_beam as beam # 导入apache_beam模块
import tensorflow as tf
import tensorflow_transform as tft
import tensorflow_transform.beam as tft_beam
import tempfile
import csv
# 定义CSV文件读取和解析函数
def parse_csv(csv_row):
columns = tf.io.decode_csv(csv_row, record_defaults=[[0], [0.0], [0]])
return {
'area': columns[0],
'rooms': columns[1],
'price': columns[2]
}
# 读取CSV文件并应用预处理
def preprocess_data(csv_file):
raw_data = (
pipeline
| 'ReadCSV' >> beam.io.ReadFromText(csv_file)
| 'ParseCSV' >> beam.Map(parse_csv)
)
with tft_beam.Context(temp_dir=tempfile.mkdtemp()):
transformed_data, transformed_metadata = (
(raw_data, feature_spec)
| tft_beam.AnalyzeAndTransformDataset(preprocessing_fn)
)
return transformed_data, transformed_metadata
# 定义特征元数据
feature_spec = {
'area': tf.io.FixedLenFeature([], tf.int64),
'rooms': tf.io.FixedLenFeature([], tf.float32),
'price': tf.io.FixedLenFeature([], tf.int64),
}
# 定义数据预处理函数,处理缺失值和标准化
def preprocessing_fn(inputs):
processed_features = {
'area': tft.scale_to_z_score(inputs['area']),
'rooms': tft.scale_to_0_1(tft.impute(inputs['rooms'], tft.constants.FLOAT_MIN)),
'price': inputs['price']
}
return processed_features
# 读取CSV文件并应用预处理
with beam.Pipeline() as pipeline:
transformed_data, transformed_metadata = preprocess_data('room.csv')
# 显示处理后的数据和元数据
for example in transformed_data:
print(example)
print('Transformed Metadata:', transformed_metadata.schema)
在上述代码中,首先定义了CSV文件读取和解析函数(parse_csv),然后定义了特征元数据(feature_spec)。接着,定义了数据预处理函数(preprocessing_fn),该函数使用tft.impute填充了'rooms'列中的缺失值,同时对'area'列进行了标准化。随后,使用Beam管道读取CSV文件并应用预处理,然后输出处理后的数据和元数据。运行代码后,将看到填充了缺失值并进行了标准化的数据,以及相应的元数据信息。执行后会输出:
{'area': 1.0, 'rooms': 0.0, 'price': 250000}
{'area': -1.0, 'rooms': -0.5, 'price': 200000}
{'area': 0.0, 'rooms': 0.5, 'price': 300000}
{'area': 0.0, 'rooms': 0.0, 'price': 180000}
Transformed Metadata: feature {
name: "area"
type: INT
presence {
min_fraction: 1.0
}
shape {
}
}
feature {
name: "rooms"
type: FLOAT
presence {
min_fraction: 1.0
}
shape {
}
}
feature {
name: "price"
type: INT
presence {
min_fraction: 1.0
}
shape {
}
}
对上述输出结果的说明如下:
- 每一行都是预处理后的数据样本,其中'area'和'rooms'列经过缩放或填充处理,'price'列保持不变。
- 'area'列经过缩放处理,例如1200经过标准化为1.0。
- 'rooms'列经过填充和缩放处理,例如1000填充为-1.0并标准化为-0.5。
- 'price'列保持不变,例如250000。
- 最后,输出了转换后的元数据模式,显示了每个特征的类型和存在性信息。
当然,也可以使用PyTorch来处理文件room.csv中的缺失值,下面的实例演示了这一功能的实现过程。
实例2-18:使用PyTorch处理CSV文件中的缺失值(源码路径:daima/2/pyque.py)
实例文件pyque.py的具体实现代码如下所示。
import torch
from torch.utils.data import Dataset, DataLoader
import pandas as pd
# 自定义数据集类
class HouseDataset(Dataset):
def __init__(self, csv_file):
self.data = pd.read_csv(csv_file)
# 处理缺失值
self.data['rooms'].fillna(self.data['rooms'].mean(), inplace=True)
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
area = self.data.iloc[idx]['area']
rooms = self.data.iloc[idx]['rooms']
price = self.data.iloc[idx]['price']
sample = {'area': area, 'rooms': rooms, 'price': price}
return sample
# 创建数据集实例
dataset = HouseDataset('room.csv')
# 创建数据加载器
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
# 遍历数据加载器并输出样本
for batch in dataloader:
print("Batch:", batch)
在上述代码中,首先定义了一个自定义的数据集类 HouseDataset,在该类的初始化方法中,使用 Pandas 库读取 CSV 文件,并使用均值填充缺失的房间数量。然后,在 __getitem__ 方法中,我们获取每个样本的属性,然后返回一个字典作为样本。接着,创建了一个数据集实例 dataset,并使用 DataLoader 创建数据加载器,用于批量加载数据。最后,遍历数据加载器并输出样本。执行后回输出:
Batch: {'area': tensor([1500., nan], dtype=torch.float64), 'rooms': tensor([4.0000, 3.5000], dtype=torch.float64), 'price': tensor([300000., 180000.], dtype=torch.float64)}
Batch: {'area': tensor([1000., 1200.], dtype=torch.float64), 'rooms': tensor([3.5000, 3.0000], dtype=torch.float64), 'price': tensor([200000., 250000.], dtype=torch.float64)}
2.4.2 异常值检测与处理
在机器学习和数据分析中,异常值(Outliers)是指与大部分数据点在统计上显著不同的数据点。异常值可能是由于错误、噪声、测量问题或其他异常情况引起的,它们可能会对模型的训练和性能产生负面影响。因此,异常值检测和处理是数据预处理的重要步骤之一。
例如下面是一个使用 PyTorch 进行异常值检测与处理的例子,将使用 Isolation Forest 算法进行异常值检测,并对异常值进行处理。
实例2-19:使用 PyTorch 进行异常值检测与处理(源码路径:daima/2/yi.py)
实例文件yi.py的具体实现代码如下所示。
import torch
from sklearn.ensemble import IsolationForest
from torch.utils.data import Dataset, DataLoader
import numpy as np
# 生成一些带有异常值的随机数据
data = np.random.randn(100, 2)
data[10] = [10, 10] # 添加一个异常值
data[20] = [-8, -8] # 添加一个异常值
# 使用 Isolation Forest 进行异常值检测
clf = IsolationForest(contamination=0.1) # 设置异常值比例
pred = clf.fit_predict(data)
anomalies = np.where(pred == -1)[0] # 异常值索引
# 打印异常值索引
print("异常值索引:", anomalies)
# 自定义数据集类
class CustomDataset(Dataset):
def __init__(self, data, anomalies):
self.data = data
self.anomalies = anomalies
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
sample = self.data[idx]
label = 1 if idx in self.anomalies else 0 # 标记异常值为1,正常值为0
return torch.tensor(sample, dtype=torch.float32), label
# 创建数据集实例
dataset = CustomDataset(data, anomalies)
# 创建数据加载器
dataloader = DataLoader(dataset, batch_size=10, shuffle=True)
# 遍历数据加载器并输出样本及其标签
for batch in dataloader:
samples, labels = batch
print("样本:", samples)
print("标签:", labels)
在上述代码中,首先生成了一些带有异常值的随机数据。然后,使用 Isolation Forest 算法对数据进行异常值检测,通过指定 contamination 参数来设置异常值比例。接着,定义了一个自定义数据集类 CustomDataset,其中异常值的索引被标记为1,正常值的索引标记为0。最后,我们创建了数据集实例和数据加载器,遍历数据加载器并输出样本及其标签,从而演示了如何使用 PyTorch 进行异常值检测与处理。
执行后的输出的内容是每个批次的样本和标签。每个批次的样本是一个张量,包含了一批数据样本,而对应的标签是一个张量,指示了每个样本是正常值(标签为0)还是异常值(标签为1)。例如,输出中的第一个批次的样本如下所示:
样本: tensor([[ 0.3008, 1.6835],
[ 0.9125, 1.5915],
[-0.3871, -0.0249],
[-0.2126, -0.2027],
[-0.5890, 1.2867],
[ 1.9692, -1.6272],
[ 0.4465, 0.9076],
[ 0.1764, -0.2811],
[ 0.9241, -0.3346],
[ 0.5370, 0.2201]])
标签: tensor([0, 0, 0, 0, 0, 1, 0, 0, 0, 0])
在这个例子中,正常值样本的标签为0,异常值样本的标签为1。这个标签信息可以用于训练机器学习模型来进行异常值检测任务。
例如下面是一个使用 TensorFlow 进行异常值检测与处理的例子,将使用孤立森林(Isolation Forest)算法进行异常值检测,并对异常值进行处理。
实例2-20:使用 TensorFlow进行异常值检测与处理(源码路径:daima/2/tyi.py)
实例文件tyi.py的具体实现代码如下所示。
import tensorflow as tf
from sklearn.ensemble import IsolationForest
import numpy as np
# 生成一些带有异常值的随机数据
data = np.random.randn(100, 2)
data[10] = [10, 10] # 添加一个异常值
data[20] = [-8, -8] # 添加一个异常值
# 使用 Isolation Forest 进行异常值检测
clf = IsolationForest(contamination=0.1) # 设置异常值比例
pred = clf.fit_predict(data)
anomalies = np.where(pred == -1)[0] # 异常值索引
# 将数据转换为 TensorFlow 数据集
dataset = tf.data.Dataset.from_tensor_slices(data)
# 对异常值进行处理
def preprocess_data(sample):
return sample
def preprocess_label(idx):
return 1 if idx in anomalies else 0
processed_dataset = dataset.map(preprocess_data)
labels = np.array([preprocess_label(idx) for idx in range(len(data))])
# 创建数据加载器
batch_size = 10
dataloader = processed_dataset.batch(batch_size)
# 遍历数据加载器并输出样本及其标签
for batch in dataloader:
print("样本:", batch)
batch_indices = tf.range(batch_size, dtype=tf.int32)
batch_labels = tf.gather(labels, batch_indices)
print("标签:", batch_labels)
在上述代码中,首先生成了一些带有异常值的随机数据。然后,使用孤立森林(Isolation Forest)算法对数据进行异常值检测,通过指定 contamination 参数来设置异常值比例。接着,将数据转换为 TensorFlow 数据集,并使用 map 函数对数据集中的每个样本进行预处理。最后,创建了数据加载器,遍历数据加载器并输出样本及其标签,从而演示了如何使用 TensorFlow 进行异常值检测与处理。执行后会输出:
样本: tf.Tensor(
[[ 1.08761703 -1.24775834]
[ 0.74802814 -0.05866723]
[-0.05826104 -1.02230984]
[-1.57393284 0.34795907]
...
[ 0.67923789 0.29233014]
[-0.51347079 0.62670954]
[-1.59011801 0.01169146]], shape=(10, 2), dtype=float64)
标签: tf.Tensor([0 0 0 0 0 0 0 0 0 0], shape=(10,), dtype=int32)
样本: tf.Tensor(
[[10. 10. ]
[-0.44729668 1.05870219]
[ 0.78190767 0.24451839]
...
[ 0.67923789 0.29233014]
[-0.51347079 0.62670954]
[-1.59011801 0.01169146]], shape=(10, 2), dtype=float64)
标签: tf.Tensor([1 0 0 0 0 0 0 0 0 0], shape=(10,), dtype=int32)
样本: tf.Tensor(
[[-8. -8. ]
[ 0.45491414 0.7643319 ]
[-1.77601158 -0.70068054]
...
[ 0.67923789 0.29233014]
[-0.51347079 0.62670954]
[-1.59011801 0.01169146]], shape=(10, 2), dtype=float64)
标签: tf.Tensor([1 0 0 0 0 0 0 0 0 0], shape=(10,), dtype=int32)
...
在上述输出中的每个批次输出了一组样本及其对应的标签。标签为0表示正常值,标签为1表示异常值。在这个例子中,我们手动添加了两个异常值,因此在每个批次中会有几个异常值,其余的都是正常值。
2.4.3 处理重复数据
处理数据集中的重复数据涉及到具体的数据集和问题场景。通常,数据集中的重复数据可能会影响模型的性能和训练结果,因此需要进行适当的处理。在实际应用中,通常使用Python库Pandas来处理重复数据。例如下面是一个使用Pandas来处理重复数据的例子。
实例2-21:使用Pandas来处理重复数据(源码路径:daima/2/chong.py)
(1)假设有一个简单的文件dataset.csv,其内容如下所示:
feature1,feature2,label
1.2,2.3,0
0.5,1.8,1
1.2,2.3,0
2.0,3.0,1
0.5,1.8,1
这个CSV文件包含三列内容:feature1、feature2和label。其中,前两列是特征,最后一列是标签。注意,在第1行和第3行之间以及第2行和第5行之间存在重复数据。在处理重复数据时,我们需要根据特定的情况来决定是否删除这些重复数据。
(2)实例文件chong.py用于处理文件dataset.csv中的重复数据,具体实现代码如下所示。
import pandas as pd
# 读取数据集
data = pd.read_csv('dataset.csv')
# 检测重复数据
duplicates = data[data.duplicated()]
# 删除重复数据
data_no_duplicates = data.drop_duplicates()
# 打印处理后的数据集大小
print("原始数据集大小:", data.shape)
print("处理后数据集大小:", data_no_duplicates.shape)
执行后会输出:
原始数据集大小: (5, 3)
处理后数据集大小: (3, 3)
通过上述输出结果显示,原始数据集包含5行和3列,处理后的数据集包含3行和3列。这表明你成功地处理了数据集中的重复数据,将重复的样本行删除,从而得到了一个不包含重复数据的数据集。
本《文本预处理算法》专题已完结
(2-1)文本预处理算法:分词(Tokenization)-CSDN博客
(2-2)文本预处理算法:词干化与词形还原(Stemming and Lemmatization)-CSDN博客