机器学习:数据清洗与预处理 | Python
个人主页-爱因斯晨
文章专栏-Python学习
文章目录
-
- 个人主页-爱因斯晨
- 文章专栏-Python学习
- 前言
- 了解数据清洗
- 数据清洗的步骤
-
- 1. 环境准备与库导入
- 2. 数据加载
- 3. 数据初探与理解
- 4. 缺失值处理
- 5. 重复值处理
- 6. 异常值处理
- 7. 数据类型转换
- 8. 数据标准化 / 归一化(预处理)
- 实例实践
- 总结
前言
我们不论在学习机器学习还是数据分析中,都会涉及很多数据。但原数据不可避免有很多杂志,为了确保结果的准确性,我们需要首先进行数据清洗和预处理。
了解数据清洗
数据清洗就像是一场数据的“大扫除”。它是从原始数据中找出并修正那些错误、不完整、重复或不一致的数据。通过数据清洗,能显著提升数据质量,为后续数据分析、挖掘和建模等工作提供准确、可靠、干净的数据基础,从而让基于数据得出的结论更具可信度和价值。
数据清洗的步骤
1. 环境准备与库导入
import pandas as pd # 数据处理核心库import numpy as np # 数值计算库import matplotlib.pyplot as plt # 基础可视化库import seaborn as sns # 高级可视化库# 设置显示参数,确保中文正常显示plt.rcParams[\"font.family\"] = [\"SimHei\", \"WenQuanYi Micro Hei\", \"Heiti TC\"]pd.set_option(\'display.max_columns\', None) # 显示所有列pd.set_option(\'display.width\', 1000) # 显示宽度
函数 / 参数解释:
import pandas as pd
:导入 pandas 库并简写为 pd。pandas 是数据处理的核心工具,提供了DataFrame
数据结构和丰富的数据操作方法。plt.rcParams
:设置 matplotlib 的全局参数,这里用于配置中文字体,避免图表中中文显示为乱码。pd.set_option
:配置 pandas 的显示选项,确保查看数据时不会截断列或内容。
2. 数据加载
# 从CSV文件加载数据df = pd.read_csv(\'data.csv\')# 从Excel文件加载数据(支持多工作表)excel_file = pd.ExcelFile(\'data.xlsx\')df = excel_file.parse(\'Sheet1\') # 读取名为Sheet1的工作表# 查看数据规模print(f\"数据集规模:{df.shape[0]}行,{df.shape[1]}列\")
函数解释:
pd.read_csv()
:读取 CSV 文件并返回DataFrame
对象。- 常用参数:
sep
(分隔符,默认逗号)、header
(表头行索引,默认 0)、na_values
(指定缺失值标识)、usecols
(指定读取的列) - 示例:
pd.read_csv(\'data.csv\', sep=\';\', na_values=[\'NA\', \'missing\'])
- 常用参数:
pd.ExcelFile()
与parse()
:pd.ExcelFile()
:创建 Excel 文件对象,用于高效读取包含多个工作表的 Excel 文件parse()
:从 ExcelFile 对象中读取指定工作表,参数sheet_name
指定工作表名称或索引
3. 数据初探与理解
# 查看数据基本信息print(\"数据基本信息:\")df.info()# 查看前5行数据print(\"\\n数据前5行:\")print(df.head())# 查看数值型列的统计描述print(\"\\n数值型列统计描述:\")print(df.describe())# 查看类别型列的取值分布print(\"\\n类别型列取值分布:\")for col in df.select_dtypes(include=[\'object\', \'category\']).columns: print(f\"\\n{col}列分布:\") print(df[col].value_counts())
函数解释:
info()
:查看DataFrame
的基本信息,包括索引类型、列信息、数据类型、非空值数量和内存占用。head(n)
:返回前 n 行数据(默认 n=5),用于快速预览数据内容。对应的tail(n)
返回后 n 行。describe()
:生成数值型列的统计摘要,包括计数、均值、标准差、最值和四分位数。select_dtypes(include=[])
:筛选指定数据类型的列,include=[\'object\', \'category\']
用于筛选类别型列。value_counts()
:计算类别型列中每个取值的出现次数,用于了解数据分布。
4. 缺失值处理
# 1. 检测缺失值missing_count = df.isnull().sum() # 计算每列缺失值数量missing_ratio = missing_count / len(df) # 计算缺失比例missing_df = pd.DataFrame({ \'缺失值数量\': missing_count, \'缺失比例\': missing_ratio})print(\"缺失值统计:\")print(missing_df[missing_df[\'缺失值数量\'] > 0]) # 只显示有缺失值的列# 2. 处理缺失值# 方法1:删除缺失值(适用于缺失比例极低的情况)df_drop = df.dropna(axis=0) # 按行删除,axis=1按列删除# 方法2:填充缺失值# 数值型列用均值/中位数填充df[\'数值列1\'] = df[\'数值列1\'].fillna(df[\'数值列1\'].mean()) # 均值填充df[\'数值列2\'] = df[\'数值列2\'].fillna(df[\'数值列2\'].median()) # 中位数填充# 类别型列用众数填充df[\'类别列1\'] = df[\'类别列1\'].fillna(df[\'类别列1\'].mode()[0]) # 众数填充# 方法3:用前后值填充(适用于时间序列)df[\'时间序列列\'] = df[\'时间序列列\'].fillna(method=\'ffill\') # 向前填充# df[\'时间序列列\'] = df[\'时间序列列\'].fillna(method=\'bfill\') # 向后填充
函数解释:
isnull()
:返回布尔型DataFrame
,标记每个元素是否为缺失值(NaN)。sum()
:对isnull()
的结果求和,得到每列缺失值数量。dropna(axis=0)
:删除包含缺失值的行(axis=0)或列(axis=1)。- 常用参数:
how=\'any\'
(默认,任何缺失值即删除)、how=\'all\'
(所有值都缺失才删除)
- 常用参数:
fillna()
:填充缺失值,支持固定值、统计量(均值 / 中位数 / 众数)和前后值填充。
5. 重复值处理
# 1. 检测重复行duplicate_rows = df.duplicated() # 返回布尔型Series,标记是否为重复行print(f\"重复行数量:{duplicate_rows.sum()}\")# 2. 查看重复行内容if duplicate_rows.sum() > 0: print(\"重复行内容:\") print(df[duplicate_rows])# 3. 删除重复行df_clean = df.drop_duplicates(keep=\'first\') # 保留第一次出现的行# df_clean = df.drop_duplicates(keep=\'last\') # 保留最后一次出现的行# df_clean = df.drop_duplicates(keep=False) # 删除所有重复行print(f\"删除重复行后:{df_clean.shape[0]}行\")
函数解释:
- duplicated():检测重复行,返回布尔型 Series。
- 参数
subset=[\'col1\', \'col2\']
:指定用于判断重复的列 - 默认保留第一次出现的行,标记后续重复行为 True
- 参数
- drop_duplicates():删除重复行,参数keep控制保留策略:
keep=\'first\'
:保留第一次出现的行(默认)keep=\'last\'
:保留最后一次出现的行keep=False
:删除所有重复行
6. 异常值处理
# 1. 绘制箱线图可视化异常值plt.figure(figsize=(12, 6))sns.boxplot(data=df.select_dtypes(include=np.number)) # 只对数值列绘图plt.title(\'数值列箱线图(用于检测异常值)\')plt.tight_layout()plt.show()# 2. 使用IQR方法检测异常值def detect_outliers(df, col): \"\"\"检测指定列的异常值\"\"\" Q1 = df[col].quantile(0.25) # 下四分位数 Q3 = df[col].quantile(0.75) # 上四分位数 IQR = Q3 - Q1 # 四分位距 lower_bound = Q1 - 1.5 * IQR # 下界 upper_bound = Q3 + 1.5 * IQR # 上界 outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)] return outliers, lower_bound, upper_bound# 处理每个数值列的异常值for col in df.select_dtypes(include=np.number).columns: outliers, lower, upper = detect_outliers(df, col) if not outliers.empty: print(f\"{col}列异常值数量:{len(outliers)}\") # 方法1:删除异常值 # df = df.drop(outliers.index) # 方法2:截断异常值(替换为边界值) df.loc[df[col] < lower, col] = lower df.loc[df[col] > upper, col] = upper
函数解释:
sns.boxplot()
:绘制箱线图,直观展示数据分布和异常值。箱线图中,超出上下须线(Q1-1.5IQR 和 Q3+1.5IQR)的点被视为异常值。quantile(q)
:计算分位数,q=0.25 表示下四分位数(Q1),q=0.75 表示上四分位数(Q3)。- 异常值处理策略:删除(适用于错误数据)、截断(替换为边界值)、转换(如对数转换)。
7. 数据类型转换
# 查看当前数据类型print(\"原始数据类型:\")print(df.dtypes)# 1. 转换为数值类型(处理字符串格式的数值)df[\'数值列\'] = pd.to_numeric(df[\'数值列\'], errors=\'coerce\') # 无法转换的值变为NaN# 2. 转换为日期类型df[\'日期列\'] = pd.to_datetime(df[\'日期列\'], format=\'%Y-%m-%d\') # 指定格式加速转换# 3. 转换为类别类型(适用于取值有限的字符串列)df[\'类别列\'] = df[\'类别列\'].astype(\'category\')# 查看转换后的数据类型print(\"\\n转换后数据类型:\")print(df.dtypes)
函数解释:
dtypes
:查看各列的数据类型。pd.to_numeric()
:将列转换为数值类型,errors=\'coerce\'
参数将无法转换的值设为 NaN。pd.to_datetime()
:将列转换为日期时间类型,format
参数指定日期格式。astype(\'category\')
:将字符串列转换为类别类型,减少内存占用并提高效率。
8. 数据标准化 / 归一化(预处理)
# 1. 标准化(Z-score标准化,使均值为0,标准差为1)from sklearn.preprocessing import StandardScalerscaler = StandardScaler()numeric_cols = df.select_dtypes(include=np.number).columnsdf[numeric_cols] = scaler.fit_transform(df[numeric_cols])# 2. 归一化(Min-Max归一化,将值缩放到[0,1]范围)from sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler()df[numeric_cols] = scaler.fit_transform(df[numeric_cols])# 查看处理后的统计描述print(\"标准化/归一化后统计描述:\")print(df[numeric_cols].describe())
函数解释:
StandardScaler()
:Z-score 标准化,公式为:(x’ = (x - \\mu) / \\sigma),其中(\\mu)是均值,(\\sigma)是标准差。适用于数据近似正态分布的情况。MinMaxScaler()
:Min-Max 归一化,将值缩放到 [0,1] 范围,公式为:(x’ = (x - \\min) / (\\max - \\min))。适用于需要将数据限制在特定范围的场景。
实例实践
以鸢尾花数据集为例
原数据集:在资源绑定中
#导入库import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as sns#设置显示选项pd.set_option(\'display.max_columns\', None)pd.set_option(\'display.max_rows\', None)# 使用原始字符串处理文件路径excel_file = r\'C:\\Users\\einsc\\PycharmProjects\\PythonProject\\.venv\\share\\yuan\\iris_dataset.xlsx\'#获取表名sheet_names = pd.ExcelFile(excel_file).sheet_namesprint(sheet_names)#读取数据df = pd.ExcelFile(excel_file).parse(\'Sheet1\')print(\"数据基本信息\")df.info()rows, columns = df.shapeprint(f\"数据的行数: {rows}\")print(f\"数据的列数: {columns}\")print(\"数据的前几行\")print(df.head())# 处理缺失值print(\"缺失值统计:\")print(df.isnull().sum())# 若存在缺失值,这里选择用列均值填充数值型列,用众数填充类别型列for col in df.columns: if df[col].dtype == \'object\': df[col] = df[col].fillna(df[col].mode()[0]) else: df[col] = df[col].fillna(df[col].mean())# 处理重复值print(\"重复值数量:\", df.duplicated().sum())# 删除重复值df = df.drop_duplicates()# 处理异常值(使用 IQR 方法)numerical_columns = df.select_dtypes(include=[np.number]).columnsfor col in numerical_columns: Q1 = df[col].quantile(0.25) Q3 = df[col].quantile(0.75) IQR = Q3 - Q1 lower_bound = Q1 - 1.5 * IQR upper_bound = Q3 + 1.5 * IQR df = df[(df[col] >= lower_bound) & (df[col] <= upper_bound)]# 重置索引df = df.reset_index(drop=True)print(\"清洗后数据基本信息\")df.info()print(\"清洗后数据行数: \", df.shape[0])print(\"清洗后数据列数: \", df.shape[1])# 定义保存路径output_file = r\'C:\\Users\\einsc\\PycharmProjects\\PythonProject\\.venv\\share\\yuan\\iris_dataset_cleaned.xlsx\'# 将清洗后的数据保存到新的 Excel 文件df.to_excel(output_file, index=False, sheet_name=\'CleanedData\')print(f\"清洗后的数据已保存到 {output_file}\")print(\"数据的前几行\")
处理结果:
总结
本文聚焦机器学习中的数据清洗与预处理。先阐述其重要性,如同为数据“大扫除”,能提升数据质量、保障结论可靠。接着分八个步骤详细讲解,从环境准备与库导入,到数据加载、初探,再到缺失值、重复值、异常值处理,以及数据类型转换和标准化/归一化,每个步骤都有代码示例和函数解释。最后以鸢尾花数据集为例实践,经各环节处理后保存清洗数据。整体内容系统全面,理论与实践结合,助读者掌握数据清洗与预处理的关键要点和操作。