机器学习-数据预处理(附完整代码)

数据的预处理(清洗、集成、变换、规约)

​ 在进行数据挖掘中,原始海量的数据中存在着大量不完整(有缺失值)、不一致、有异常的数据,严重影响到数据挖掘建模的执行效率,甚至可能导致挖掘结果的偏差,所以对首先对数据进行清洗就显得尤为重要,在数据清洗完成后,后续伴随着数据集成、转换、规约等一系列的处理,该过程就是数据预处理。数据预处理一方面是要提高数据的质量,另一方面是要让数据更好地适应特定的挖掘技术或工具。统计发现,在数据挖掘的过程中,数据预处理工作量占到了整个过程的60%。

数据预处理的主要内容包括数据清洗、数据集成、数据变换和数据规约.

1、数据清洗(Data Cleaning)

在这里插入图片描述
目标:修复数据中的噪声、缺失、不一致等问题。

1.1 、具体内容:

1.1.1、缺失值处理

  • 方法:删除缺失记录、均值/中位数填充、插值法、模型预测填充。
  • 示例:年龄字段缺失时,用数据集的平均年龄填充。

1.1.2、异常值处理

  • 方法:Z-score法(标准化)、IQR(四分位距法)、描述性分析、散点图、箱形图、直方图查找异常并处理。
  • 示例:检测到某商品价格超过正常范围的3倍标准差,判定为异常并剔除。

1.1.3、噪声数据

  • 方法:分箱、回归、孤点分析。
  • 示例:

1.1.4、重复值处理

  • 方法:删除完全重复的行。
  • 示例:电商订单数据中同一订单被重复记录两次,删除冗余行。

示例代码:

import pandas as pd  
import numpy as np  
  
# 我们创建模拟数据,包含重复的行(基于'name'和'city'列)  
data = {  
    'name': ['郭靖', '黄蓉', '李飞', '周伯通', '杨过', '小龙女', '金轮法王', '周伯通','郭靖','黄药师'],  
    'age': [56, np.nan, 35, 40, 45, 30, 40, 45, 56, 76],  
    'sex': ['男', '女', '女', '男', '男', '女', '男', '男','男',np.nan],
    'salary': [20000, 60000, np.nan, 75000, 80000, 60000, 120000, 80000, 20000, 50000],  
    'department': ['人力资源部', 'IT部', '销售部', '市场部', '工会', 'IT部', '金融事业部', '市场部', '人力资源部', '无业游民'],  
    'city': ['广州市', '深圳市', '北京市', '南京市', '杭州市', '合肥市', '贵阳市', '南京市', '广州市', '东莞市']  
}  
  
df = pd.DataFrame(data)  
# 查看原始数据  
print("原始数据:")  
print(df)  
  
# 处理缺失值  
# 使用均值填充'age'列的缺失值,使用中位数填充'salary'列的缺失值  
df['age'].fillna(df['age'].mean(), inplace=True)  
df['salary'].fillna(df['salary'].median(), inplace=True)  
# 删除'sex'列缺失值'黄药师'
df = df.dropna(subset=['sex'])
 
# 处理异常值  
# 假设'salary'列中的值应该在30000到80000之间,我们将其超出这个范围的值视为异常值  
# 并用该列的中位数来替换这些异常值  
df['salary'] = df['salary'].apply(lambda x: x if 30000 <= x <= 80000 else df['salary'].median()) 
  
# 处理重复值  
# 针对'name'和'city'列上重复的行删除(郭靖&周伯通),只保留第一次出现的行  
df.drop_duplicates(subset=['name', 'city'], keep='first', inplace=True)  
  
# 查看清洗后的数据  
print("\n清洗后的数据:")  
print(df)

输出结果:

原始数据:
   name   age  sex    salary department city
0    郭靖  56.020000.0      人力资源部  广州市
1    黄蓉   NaN    女   60000.0        IT部  深圳市
2    李飞  35.0    女       NaN        销售部  北京市
3   周伯通  40.075000.0        市场部  南京市
4    杨过  45.080000.0         工会  杭州市
5   小龙女  30.060000.0        IT部  合肥市
6  金轮法王  40.0120000.0      金融事业部  贵阳市
7   周伯通  45.080000.0        市场部  南京市
8    郭靖  56.020000.0      人力资源部  广州市
9   黄药师  76.0  NaN   50000.0       无业游民  东莞市

清洗后的数据:
   name   age sex   salary department city
0    郭靖  56.060000.0      人力资源部  广州市
1    黄蓉  47.060000.0        IT部  深圳市
2    李飞  35.060000.0        销售部  北京市
3   周伯通  40.075000.0        市场部  南京市
4    杨过  45.080000.0         工会  杭州市
5   小龙女  30.060000.0        IT部  合肥市
6  金轮法王  40.060000.0      金融事业部  贵阳市

2、数据集成(Data Integration)

目标:涉及整合多源数据,解决冗余和实体识别冲突。

2.1、具体内容:

2.1.1、实体识别

  • 方法:统一字段命名(如 CustomerID 和 Cust_ID 合并为同一字段)。
  • 示例:合并销售表(含 ProductID)和库存表(含 ProdID),需统一字段名。

2.1.2、冗余数据处理

  • 方法:分析相关性,删除冗余列(如同时存在 身高(cm) 和 身高(m))。
  • 示例:合并两个客户表时,发现 年龄 和 出生年份 存在冗余,删除其一。

3、数据变换(Data Transformation)

目标:将数据转换为适合数据挖掘分析的格式,有规范化、离散化、特征构造等。

3.1、具体内容:

3.1.1、规范化(Normalization)

数值标准化和归一化是特征工程中常用的方法,用于将数值型特征的取值范围归一到一个共同的尺度或范围内,以便更好地处理和分析数据。

3.1.1.1、Z-score 标准化

该方法将每个特征值减去该特征的均值,并除以标准差,得到标准化后的特征值。这种方法使得每个特征的均值为 0,标准差为 1,具体计算公式如下:
其中,x 是原始特征值, μ 是特征的均值, σ 是特征的标准差, z 是标准化后的特征值
z = x − μ σ z = \frac{x- μ } {σ} z=σxμ
Z-score 标准化的优点是对数据的分布具有平移和缩放不变性,即标准化后的数据不受数据整体偏移和缩放的影响

import pandas as pd
from sklearn.preprocessing import StandardScaler

# 原始数据
data = {
    'salary': [20000, 60000, 70000, 75000, 80000, 60000, 120000, 80000, 20000, 50000]
}

# 创建DataFrame
df = pd.DataFrame(data)

# 使用StandardScaler进行Z-score标准化
scaler = StandardScaler()
scaled_salary = scaler.fit_transform(df[['salary']])  # 注意输入需为二维数组

# 将结果添加到DataFrame
df['salary_zscore'] = scaled_salary.round(3)  # 保留3位小数

# 输出对比
print("处理前数据(原始薪资):")
print(df[['salary']].T)  # 转置显示更紧凑

print("\n处理后数据(Z-score标准化):")
print(df[['salary_zscore']].T)

# 验证参数
print(f"\n验证参数 → 均值: {scaler.mean_[0]:.1f}, 标准差: {scaler.scale_[0]:.1f}")
处理前数据(原始薪资):
      0      1      2      3      4      5      6      7      8      9
salary  20000  60000  70000  75000  80000  60000  120000  80000  20000  50000

处理后数据(Z-score标准化):
             0      1      2      3      4      5      6      7      8      9
salary_zscore -1.432 -0.278  0.028  0.206  0.384 -0.278  1.971  0.384 -1.432 -0.554

验证参数 → 均值: 63500.0, 标准差: 30368.6
3.1.1.2、Min-Max归一化(Normalization)

该方法将每个特征值映射到一个指定的范围内,通常是[0,1]或[-1,1]。具体计算公式如下:
x ′ = x − m i n ( x ) m a x ( x ) − m i n ( x ) x′ = \frac{x- min(x) } {max(x)-min(x)} x=max(x)min(x)xmin(x)
其中, x′ 是归一化后的特征值, x 是原始特征值, min(x) 和 max(x) 分别是特征的最小值和最大值。
Min-Max 归一化的优点是简单易懂,并且可以将数据限制在特定的范围内。它对于一些需要将数据映射到特定范围的算法或可视化方法(如神经网络)会非常合适。

from sklearn.preprocessing import MinMaxScaler
import numpy as np

# 原始数据
data = {
    'salary': [20000, 60000, 70000, 75000, 80000, 60000, 120000, 80000, 20000, 50000]
}

# 将数据转换为二维数组格式
salaries = np.array(data['salary']).reshape(-1, 1)

# 初始化MinMaxScaler并归一化处理
scaler = MinMaxScaler(feature_range=(0, 1))
normalized_salaries = scaler.fit_transform(salaries)

# 输出结果
print("处理前数据:", data['salary'])
print("处理后数据:", normalized_salaries.flatten().tolist()) # 使用flatten()方法将二维数组转换为一维数组以便打印
处理前数据: [20000, 60000, 70000, 75000, 80000, 60000, 120000, 80000, 20000, 50000]
处理后数据: [0.0, 0.4, 0.5, 0.55, 0.6, 0.4, 1.0, 0.6, 0.0, 0.3]
3.1.1.3、独热编码(One-Hot)编码

独热编码(One-Hot)编码,又称为一位有效编码,是一种将分类变量转换为二进制向量的表示方法。这种方法主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由其独立的寄存器位表示,并且在任意时候只有一位有效。
One-Hot编码过程如下:

  • 首先,将分类值映射到整数值。例如,如果有三个工作类型,可以将它们映射为0、1和2。
  • 然后,每个整数值被表示为二进制向量。对于上述的例子,三个工作类型可以表示为(1,0,0)、(0,1,0)和(0,0,1)。

One-Hot 编码适用于需要将分类变量转换为数值型变量的场景,例如在文本分类、推荐系统以及图像识别中,将文本中的词汇、用户的兴趣爱好以及图像的标签转换为向量表示。此外,在使用逻辑回归、决策树等机器学习算法时,One-Hot 编码可以应用于将离散特征的取值扩展到欧式空间,离散特征的某个取值就对应欧式空间的某个点,从而让特征之间的距离计算更加合理。

3.1.1.4、TF-IDF编码

TF-IDF(Term Frequency - Inverse Document Frequency)编码是一种常用的文本特征表示方法,用于衡量一个词在文档集合中的重要程度。

  • 词频(TF):表示某个词在所在文档中出现的频率。一般来说,一个词在文档中出现的次数越多,它就越重要。但是,为了避免长文档中的词被过度重视,通常会对词频进行标准化处理。即词频 = 某个词在文档中出现的次数 / 文档的总词数。
  • 逆文档频率(IDF):表示一个词在所有文档中的重要性。一个词如果在很多文档中都出现,那么它的IDF值就会较低;相反,如果一个词只在很少的文档中出现,那么它的IDF值就会较高。逆文档频率计算公式:IDF = log(总文档数 / 包含该词的文档数 + 1)。这里的加1是为了避免分母为零的情况。

示例1:Z-score数值标准化/归一化

3.1.2、离散化

有时候需要对数据进行离散化操作,比如决策树、朴素贝叶斯等算法,不能直接处理连续型变量。再比如有些属性,希望处理数据成离散化区间。例如在处理年龄属性时,没有必要单独处理每一个年龄值,划分为几个区间会更便捷:“<30”、“30-60”和“>60”。通过离散化处理后,可以简化模型的复杂性,提高模型的计算效率,常用的离散化包括:

  • 二值化:将连续数据转换为二值数据,其中每个数据点与某个阈值进行比较,大于阈值的设置为一个固定值(例如1),小于阈值的设置为另一个固定值(例如0)。二值化后的值的设置取决于具体场景。
  • 等宽法:将连续变量的值域划分为具有相同宽度的区间。区间的个数可以由数据本身的特点决定,或者由用户指定。该方法类似于制作频率分布表。
  • 等频法:将相同数量的记录放进每个区间。这意味着每个区间包含相同数量的数据点。该方法可以确保每个区间中的数据点数量相等,但可能导致某些区间包含许多数据,而其他区间的数据极少。
  • 频率区间法:根据数据的频率分布进行排序,然后按照等频率或指定频率进行离散化。该方法将数据变换成均匀分布,但会改变原有数据的分布状态。
  • 聚类法:例如使用K均值算法将样本集分为多个离散化的簇。这种方法基于数据的自然聚类或分组进行离散化。
  • 卡方过滤:通过基于卡方的离散化方法,找出数据的最佳临近区间并合并,形成较大的区间。该方法旨在减少区间的数量,同时保持数据的重要特征。

示例1:一个简单的按年龄分段的离散化例子

import pandas as pd  
  
# 创建一个包含年龄数据的数据框  
data = {  
    'age': [25, 30, 15, 45, 60, 75, 90, 12, 18, 50]  
}  
df = pd.DataFrame(data)  
  
# 定义年龄区间的边界  
bins = [0, 12, 18, 60, float('inf')]  
labels = ['儿童', '青少年', '成年人', '老年人']  
  
# 使用pandas的cut函数进行离散化  
df['age_category'] = pd.cut(df['age'], bins=bins, labels=labels, include_lowest=True)  

# 打印离散化后的数据框  
print(df)

示例1输出:

   age age_category
0   25          成年人
1   30          成年人
2   15          青少年
3   45          成年人
4   60          成年人
5   75          老年人
6   90          老年人
7   12           儿童
8   18          青少年
9   50          成年人

示例1:等频法将学生成绩数据离散化

import pandas as pd

# 示例数据:某班级学生的考试成绩
data = { 'score': [85, 90, 78, 92, 88, 76, 95, 89, 77, 82] }

df = pd.DataFrame(data)  
# 将数据转换为pandas series
scores_series = pd.Series(df['score'])
# 设置离散化区间数
num_bins = 3

# 使用等频法离散化数据,得到数据在每个区间的索引0-2
discretized_scores = pd.qcut(scores_series, q=num_bins, labels=False)

# 查看离散化后的数据
print("离散化后的数据:")
df['score_discret'] = pd.qcut(scores_series, q=num_bins, labels=False)
print(df)

# 查看离散化区间边界
bins = pd.qcut(scores_series, q=num_bins, retbins=True, labels=False)[1]
print("\n离散化区间边界:")
print(bins)

# 输出每个区间的范围及数据点数量
for i in range(num_bins):
    mask = (discretized_scores == i)
    bin_data = scores_series[mask]
    print(f"区间 {i + 1}: {bins[i]} - {bins[i + 1]}, 数据点数量: {len(bin_data)}")

示例2输出:

离散化后的数据:
   score  score_discret
0     85              1
1     90              2
2     78              0
3     92              2
4     88              1
5     76              0
6     95              2
7     89              1
8     77              0
9     82              0

离散化区间边界:
[76. 82. 89. 95.]
区间 1: 76.0 - 82.0, 数据点数量: 4
区间 2: 82.0 - 89.0, 数据点数量: 3
区间 3: 89.0 - 95.0, 数据点数量: 3

3.1.3、特征构造

  • 方法:生成新特征(如从日期中提取星期几)。
  • 示例:将 购买日期 转换为 季节 或 是否为周末。

4、数据规约(Data Reduction)

目标:减少数据规模但保持完整性,同时保留关键信息。

4.1、具体内容:

4.1.1、属性(维)规约

  • 方法:主成分分析(PCA)、删除低方差特征、逐步回归。
  • 示例:用sklearn库中的鸢尾花数据集来做降维分析,数据集共有数据150组,每组包括花萼长(sepal lenth)、花萼宽(sepal width)、花瓣长(petal length)、花瓣宽(petal width)4个输入特征,同时给出了这一组特征对应的鸢尾花类别,类别包括Setosa Iris(狗尾花鸢尾),Versicolour Iris(杂色鸢尾),Virgincica Iris(弗吉尼亚鸢尾)三种类别,分别用0,1,2表示。

我们先用聚类方法处理数据集,然后用数据集的前两个特征输出聚类结果。下图中可以看出三种鸢尾花的聚类结果。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.cluster import KMeans

# 加载鸢尾花数据集
iris = datasets.load_iris()
X = iris.data  # 特征数据(4列)
y = iris.target  # 真实类别标签(0,1,2)
feature_names = iris.feature_names[:2]  # 前两个特征名(花萼长和花萼宽)
# 仅使用前两个特征(花萼长、花萼宽)
X_first_two = X[:, :2]
# 使用 K-means 聚类(假设分3类,与真实类别一致)
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(X_first_two)
cluster_labels = kmeans.predict(X_first_two)
plt.figure(figsize=(12, 5))

# 子图1:真实类别分布
plt.subplot(1, 2, 1)
plt.scatter(X_first_two[:, 0], X_first_two[:, 1], c=y, cmap="viridis", edgecolor="k")
plt.xlabel(feature_names[0])
plt.ylabel(feature_names[1])
plt.title("True Labels (0=Setosa, 1=Versicolour, 2=Virginica)")
plt.show()

在这里插入图片描述
示例:下面我们用PCA降维方法将鸢尾花数据集的四个特征降维到二维,然后再用聚类方法输出聚类结果。

import numpy as np
from sklearn import datasets
from sklearn.decomposition import PCA

# 加载鸢尾花数据集
iris = datasets.load_iris()
# 获取特征矩阵和目标向量
X = iris.data
y = iris.target

# 创建 PCA 实例,保留2个主成分
pca = PCA(n_components=2)
pca.fit(X)

# 投影数据到低维空间
X2 = pca.fit_transform(X)

from sklearn.cluster import AgglomerativeClustering
import matplotlib.pyplot as plt

# 定义层次聚类模型,距离计算使用欧式距离,簇间隔采用ward连接算法
clustering = AgglomerativeClustering(n_clusters=3, affinity='euclidean', linkage='ward')
# 拟合数据并预测聚类标签
labels = clustering.fit_predict(X2)

# 可视化聚类结果
plt.scatter(X2[:, 0], X2[:, 1], c=labels, cmap='viridis')
plt.xlabel('PCA X1')
plt.ylabel('PCA X2')
plt.title('Iris dataset clustering')
plt.show()

示例输出:
在这里插入图片描述

4.1.2、数值(数量)规约

  • 方法:聚类抽样、分层抽样、直方图分箱。
  • 示例:从 100 万条数据中随机抽取 10% 进行分析。

4.1.3、数据压缩

使用压缩算法减少数据存储空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琉璃梦境

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值