4. 数据质量评估与清洗入门

在科研数据分析中,拿到一份原始数据后直接开始画图或建模,是新手最常见的失误。真实数据往往来自问卷录入、仪器导出、多表合并或人工抄录,其中混杂着缺失、异常、重复和格式不一致等问题。如果不先做质量评估与清洗,后续的统计结果和可视化图表都可能建立在错误的基础上。本节围绕四类典型数据问题展开:缺失值、异常值、重复记录和格式错误,并给出可操作的识别方法与初步清洗流程。

先做质量评估,再动手清洗

质量评估的目标是“先看清问题,再决定怎么处理”。建议在清洗前先建立一份数据质量概览,记录每个字段的类型、缺失比例、取值范围、唯一值数量以及疑似异常的数量。这份概览既是清洗决策的依据,也是最终质量报告的核心内容。下面这张图展示了一个典型的数据质量评估与清洗工作流,从原始数据进入,经过四类问题识别,再分流到对应的处理策略,最后汇总为质量报告。

数据质量评估与清洗工作流 原始数据 CSV / Excel / 数据库 质量概览 字段类型·缺失率·唯一值 问题识别 缺失值 · 异常值 重复记录 · 格式错误 缺失值处理 删除 / 均值·中位数填补 异常值处理 IQR / Z 分数 / 截尾 重复记录处理 按主键 / 全字段去重 格式错误处理 类型转换 / 单位统一 清洗后数据 保留处理日志与依据 质量报告 问题数量·处理方式·影响 评估结果反馈,迭代清洗规则 判断原则:先量化问题规模,再选择处理策略;任何删除或填补都应记录依据,避免“清洗后无法复现”。 示例参数:缺失率 > 50% 的字段考虑剔除;异常值用 IQR 法,超出 Q1−1.5×IQR 或 Q3+1.5×IQR 视为疑似异常。

缺失值:先判断机制,再选择策略

缺失值不是简单地“补上”或“删掉”。首先要看缺失的比例和分布。若某字段缺失率很低(例如低于 5%),且缺失是随机发生的,删除对应行通常影响不大;若缺失率很高(例如超过 50%),该字段本身可能信息量不足,应考虑剔除或重新采集。更关键的是判断缺失机制:完全随机缺失、随机缺失还是非随机缺失。例如问卷中“收入”字段的缺失往往与受访者意愿相关,属于非随机缺失,直接删除会引入偏差。

常用处理方式有三类。第一是删除:整行删除适用于缺失比例小且随机的情况,整列删除适用于字段整体失效。第二是填补:数值型字段可用均值、中位数或分组中位数填补,类别型字段可用众数或单独标记为“未知”。第三是保留缺失标记:在建模时把“是否缺失”作为一个指示变量,保留缺失本身携带的信息。无论采用哪种方式,都要在数据中新增一列处理标记,记录该行或该字段经过了什么处理。

异常值:用统计规则圈定疑似对象

异常值是指明显偏离整体分布的观测。识别异常值最常用的两种规则是 IQR 法和 Z 分数法。IQR 法先计算第一四分位数 Q1 和第三四分位数 Q3,得到四分位距 IQR = Q3 − Q1,再把小于 Q1 − 1.5×IQR 或大于 Q3 + 1.5×IQR 的值标记为疑似异常。Z 分数法则计算每个值与均值的偏差除以标准差,通常把 |Z| > 3 视为疑似异常。两种方法都只是“圈定候选”,不能自动判定为错误。

例如某实验记录了 20 次反应时间(单位:毫秒),大部分在 300~500 之间,但出现了一个 3200 的数值。它可能是仪器误触发,也可能是真实的极端反应。处理前应回到原始记录核对,确认是录入错误则修正,确认是真实观测则保留并在分析中说明。对确认的异常值,可选择删除、截尾(把极端值替换为边界值)或使用稳健统计方法(如中位数代替均值)。

重复记录与格式错误:规则化处理

重复记录常见于多表合并、多次录入或导出时重复追加。识别时先明确“什么算重复”:是按唯一主键(如样本编号)判断,还是按全部字段完全一致判断。前者用于发现同一对象被录入多次,后者用于发现完全冗余的行。处理时保留一条、删除其余,并记录删除数量。若同一主键下字段值不一致,则不能简单去重,而需要人工核对哪条记录为准。

格式错误包括类型不一致、单位不统一、日期格式混乱、前后空格和全半角混用等。例如“年龄”字段中混入了“25岁”“二十五”“ 25 ”等多种写法,直接转换为数值会失败。处理思路是先统一格式再转换类型:去除首尾空格、统一单位、把中文数字或带单位文本解析为数值、把日期统一为 ISO 格式(YYYY-MM-DD)。转换后要检查失败记录的数量和原因,不能静默丢弃。

用工具完成初步清洗并生成质量报告

在 Python 中,pandas 是完成上述工作的常用工具。下面是一段示例代码,演示如何读取数据、统计缺失、标记异常、去除重复并输出质量摘要。示例中的字段名和阈值仅作教学示意,实际使用时需按数据情况调整。

import pandas as pd

df = pd.read_csv("raw_data.csv")

# 1. 质量概览:缺失率与唯一值
overview = pd.DataFrame({
    "缺失数": df.isna().sum(),
    "缺失率": (df.isna().mean() * 100).round(1),
    "唯一值数": df.nunique()
})

# 2. 异常值标记(以“反应时间”字段为例,IQR 法)
q1, q3 = df["反应时间"].quantile([0.25, 0.75])
iqr = q3 - q1
low, high = q1 - 1.5 * iqr, q3 + 1.5 * iqr
df["反应时间_异常"] = ~df["反应时间"].between(low, high)

# 3. 去除完全重复行,保留首次出现
before = len(df)
df = df.drop_duplicates(keep="first")
dup_removed = before - len(df)

# 4. 格式统一:去空格并转为数值
df["年龄"] = pd.to_numeric(
    df["年龄"].astype(str).str.strip().str.replace("岁", "", regex=False),
    errors="coerce"
)

# 5. 输出质量摘要
print(overview)
print(f"删除重复行:{dup_removed}")
print(f"年龄转换失败:{df['年龄'].isna().sum()}")

运行后应重点观察三类输出:各字段缺失率是否集中在少数列、异常标记数量是否合理(过多说明阈值过严或数据分布偏态严重)、格式转换失败数是否可解释。质量报告不必复杂,至少应包含数据总行数、各字段缺失率、异常值数量与判定规则、重复记录删除数、格式转换失败数及处理方式。报告的作用是让读者和合作者知道数据经过了哪些处理,保证分析过程可追溯、可复现。

清洗的核心原则是“可追溯”:每一次删除、填补和转换都要有记录。建议保留原始数据副本,清洗操作写成脚本而不是手工修改,这样换一批数据时可以重复执行同一套规则。
不要为了“让数据好看”而随意删除异常值或填补缺失。异常值可能是真实发现,缺失本身也可能携带信息。任何处理都应在报告中说明依据,避免清洗变成对结果的操纵。