Python+SPSS数学建模数据清洗实战:从问卷数据到分析建模的完整指南

数学建模竞赛中,数据清洗往往是最耗时却最容易被忽视的环节。面对一份包含数百个字段、数千条记录的复杂问卷数据,如何高效地将其转化为可供建模的"干净"数据集?本文将以2023年深圳杯A题居民健康数据为例,手把手教你使用Python和SPSS构建一套可复用的数据清洗流程。

1. 数据清洗前的准备工作

拿到原始数据的第一件事不是立即开始清洗,而是需要做好充分的准备工作。对于深圳杯A题附件2这样的复杂问卷数据(包含200+字段),我们需要先理解数据结构,制定清洗策略。

1.1 数据理解与探索

import pandas as pd
import numpy as np

# 读取原始数据
raw_data = pd.read_excel('慢性病及相关因素流调数据.xlsx', header=None)

# 查看数据概览
print(f"数据集形状: {raw_data.shape}")
print("前5行数据:")
print(raw_data.head(5))

典型输出结果:

数据集形状: (1500, 230)
前5行数据:
        0     1     2     3     4     5   ...   225   226   227   228   229
0     NaN   NaN   NaN   NaN   NaN   NaN  ...   NaN   NaN   NaN   NaN   NaN
1     ID   Q1   Q2   Q3   Q4   Q5  ...  Q228  Q229  Q230  Q231  Q232
2     1   2    1    3    1    2   ...   0     1     0     1     0
3     2   1    2    1    2    1   ...   1     0     1     0     1
4     3   2    1    3    2    1   ...   0     1     0     1     0

关键观察点

  • 数据包含1500行、230列
  • 前两行可能是标题或说明信息
  • 存在NaN值需要处理
  • 第一列似乎是ID号

1.2 制定清洗路线图

针对此类问卷数据,建议按照以下顺序进行清洗:

  1. 元数据处理 :提取或构建有效的数据字典
  2. 结构清洗 :处理表头、删除空行、添加ID等
  3. 缺失值处理 :识别、分析和填补缺失数据
  4. 异常值检测 :查找并处理不合理数值
  5. 数据转换 :创建衍生变量、标准化编码等
  6. 数据导出 :保存为适合建模的格式

2. 结构化清洗:从原始数据到规整表格

2.1 构建规范的数据框架

# 重新读取数据,正确处理表头
data = pd.read_excel('慢性病及相关因素流调数据.xlsx', header=1)

# 删除全空的行
data = data.dropna(how='all')

# 检查并修复ID列
if 'ID' not in data.columns:
    data.insert(0, 'ID', range(1, len(data)+1))
else:
    data['ID'] = data['ID'].fillna(pd.Series(range(1, len(data)+1)))

print(f"清洗后数据形状: {data.shape}")
print("ID列示例:")
print(data['ID'].head())

2.2 问卷数据的特殊处理

问卷数据往往需要额外的清洗步骤:

# 处理多选题的拆分(示例)
mchoice_cols = ['Q15', 'Q27', 'Q48']  # 假设这些是多选题
for col in mchoice_cols:
    if col in data.columns:
        # 拆分多选题选项
        expanded = data[col].str.get_dummies(sep=',')
        expanded.columns = [f"{col}_{c}" for c in expanded.columns]
        data = pd.concat([data, expanded], axis=1)
        data.drop(col, axis=1, inplace=True)

# 处理文本型分类变量
text_cols = data.select_dtypes(include=['object']).columns
for col in text_cols:
    data[col] = data[col].str.strip()  # 去除前后空格
    data[col] = data[col].replace({'': np.nan})  # 空字符串转为NaN

3. 缺失值处理:策略与实战

3.1 系统性缺失模式分析

# 计算各列缺失率
missing_rate = data.isnull().mean().sort_values(ascending=False)

# 可视化缺失模式
import matplotlib.pyplot as plt
plt.figure(figsize=(12,6))
missing_rate[missing_rate > 0].plot(kind='bar')
plt.title('各变量缺失率分布')
plt.ylabel('缺失比例')
plt.show()

常见缺失模式处理策略

缺失类型 判断标准 处理方式 SPSS实现方法
完全随机缺失 缺失与任何变量无关 直接删除或简单填补 删除或均值/中位数填补
随机缺失 缺失与观测变量相关 多重填补或模型预测 MULTIPLE IMPUTATION
非随机缺失 缺失与未观测因素相关 创建缺失指标变量 创建新变量标记缺失

3.2 Python与SPSS协同处理缺失值

Python端处理

# 简单填补示例
data.fillna({
    '年龄': data['年龄'].median(),
    '性别': data['性别'].mode()[0],
    '收入': -1  # 特殊编码表示缺失
}, inplace=True)

# 复杂缺失使用插值
data['体重'] = data.groupby(['性别','年龄'])['体重'].apply(
    lambda x: x.fillna(x.mean()))

SPSS端处理

* 多重填补示例.
MULTIPLE IMPUTATION 
  /IMPUTE METHOD=FCS 
  /IMPUTE VARIABLES=收入 体重 饮食习惯 
  /IMPUTE MAXITER=100 
  /IMPUTE NBITER=10 
  /IMPUTE SEED=12345.

4. 异常值与数据一致性检查

4.1 基于统计的异常值检测

# 数值型变量异常值检测
num_cols = data.select_dtypes(include=['number']).columns

for col in num_cols:
    q1 = data[col].quantile(0.25)
    q3 = data[col].quantile(0.75)
    iqr = q3 - q1
    lower_bound = q1 - 1.5*iqr
    upper_bound = q3 + 1.5*iqr
    
    outliers = data[(data[col] < lower_bound) | (data[col] > upper_bound)]
    if not outliers.empty:
        print(f"{col}发现{len(outliers)}个异常值,范围[{outliers[col].min()}, {outliers[col].max()}]")

4.2 逻辑一致性检查

问卷数据常常需要检查回答的逻辑一致性:

# 示例:吸烟者应该有吸烟量数据
mask = (data['是否吸烟'] == 1) & (data['每日吸烟量'].isna())
print(f"发现{len(data[mask])}条吸烟但无吸烟量记录")

# 示例:BMI计算验证
data['计算BMI'] = data['体重'] / (data['身高']/100)**2
inconsistent_bmi = data[abs(data['BMI'] - data['计算BMI']) > 0.5]
print(f"发现{len(inconsistent_bmi)}条BMI记录不一致")

5. 数据转换与特征工程

5.1 分类变量编码

# 有序分类变量映射
education_map = {
    '小学及以下': 1,
    '初中': 2,
    '高中/中专': 3,
    '大专': 4,
    '本科': 5,
    '研究生及以上': 6
}
data['教育程度编码'] = data['教育程度'].map(education_map)

# 无序分类变量哑变量化
data = pd.get_dummies(data, columns=['职业类型', '居住地区'], prefix_sep=':')

5.2 创建衍生变量

# 健康行为评分
data['健康行为分'] = (
    data['每日蔬菜摄入量'].clip(0, 500)/100 + 
    data['每周运动次数']*0.5 +
    (data['吸烟'] == 0)*1 +
    (data['饮酒'] <= 2)*1
)

# 时段特征提取
data['调查时段'] = pd.to_datetime(data['调查时间']).dt.hour
data['是否晚间'] = (data['调查时段'] >= 18).astype(int)

6. SPSS数据验证与高级处理

6.1 数据质量验证语法

* 检查变量范围.
VALIDATE DATA
  /VARIABLES=年龄 收入 BMI
  /RANGES LOWEST=0 HIGHEST=100 FOR 年龄
  /RANGES LOWEST=0 HIGHEST=50000 FOR 收入
  /RANGES LOWEST=12 HIGHEST=40 FOR BMI.

* 识别重复记录.
MATCH FILES
  /FILE=*
  /BY ID
  /FIRST=first
  /LAST=last.
SELECT IF first.
EXECUTE.

6.2 变量聚类与降维

* 变量聚类减少维度.
VARIABLE CLUSTER
  /VARIABLES=Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10
  /MEASURE=EUCLID
  /METHOD=BINARY
  /CLUSTER=WARD
  /PRINT SCHEDULE
  /PLOT DENDROGRAM.

7. 数据导出与建模准备

7.1 导出清洗后数据

# 保存为CSV
data.to_csv('cleaned_health_data.csv', index=False, encoding='utf-8-sig')

# 保存为SPSS格式
import pyreadstat
pyreadstat.write_sav(data, 'cleaned_health_data.sav')

# 保存为Excel
data.to_excel('cleaned_health_data.xlsx', index=False)

7.2 建模前的最后检查清单

  1. 变量类型检查

    • 分类变量是否正确编码
    • 连续变量是否已标准化
  2. 缺失值确认

    • 是否所有缺失已处理
    • 缺失标记是否一致
  3. 数据分布验证

    • 异常值是否已处理
    • 偏态分布是否已转换
  4. 数据字典更新

    • 所有新变量是否已记录
    • 变量含义是否清晰
# 最终数据质量报告
report = pd.DataFrame({
    '变量名': data.columns,
    '类型': data.dtypes,
    '缺失数': data.isnull().sum(),
    '唯一值数': data.nunique()
})
print(report)

在实际数学建模竞赛中,一套完整、高效的数据清洗流程可以节省大量时间。本文介绍的方法不仅适用于深圳杯A题,也可迁移到其他问卷类数据分析任务中。关键在于建立系统化的清洗思维,而不是零散地解决问题。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐