-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstep1_preprocessing.py
More file actions
381 lines (295 loc) · 12.2 KB
/
Copy pathstep1_preprocessing.py
File metadata and controls
381 lines (295 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# -*- coding: utf-8 -*-
"""
水质安全预测项目 - 步骤1: 数据预处理
目的: 学习如何处理真实数据集中的常见问题,为机器学习做准备
"""
import pandas as pd
import numpy as np
import torch
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
import warnings
warnings.filterwarnings('ignore')
# 设置中文字体显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def load_and_explore_data(file_path):
"""
加载数据并进行初步探索
这是任何机器学习项目的第一步 - 了解你的数据
"""
print("=" * 50)
print("步骤1: 数据加载与探索")
print("=" * 50)
# 1. 加载数据
try:
data = pd.read_csv(file_path)
print(f"✓ 数据加载成功!")
print(f"数据集形状: {data.shape}")
print(f"包含 {data.shape[0]} 个水质样本, {data.shape[1]} 个特征")
except Exception as e:
print(f"✗ 数据加载失败: {e}")
return None
# 2. 查看数据结构
print(f"\n数据集列名:")
for i, col in enumerate(data.columns):
print(f" {i + 1}. {col}")
# 3. 查看前几行数据
print(f"\n数据前5行预览:")
print(data.head())
# 4. 基本统计信息
print(f"\n数据类型信息:")
print(data.dtypes)
print(f"\n基本统计信息:")
print(data.describe())
return data
def check_data_quality(data):
"""
检查数据质量问题
学习识别真实数据中的常见问题:缺失值、异常值等
"""
print("\n" + "=" * 50)
print("步骤1.2: 数据质量检查")
print("=" * 50)
# 1. 缺失值检查
print("缺失值统计:")
missing_data = data.isnull().sum()
missing_percent = (missing_data / len(data)) * 100
missing_summary = pd.DataFrame({
'缺失数量': missing_data,
'缺失比例(%)': missing_percent
})
print(missing_summary[missing_summary['缺失数量'] > 0])
# 2. 目标变量分布检查
if 'Potability' in data.columns:
print(f"\n目标变量 (Potability) 分布:")
potability_counts = data['Potability'].value_counts()
print(
f"可饮用 (1): {potability_counts.get(1, 0)} 个样本 ({potability_counts.get(1, 0) / len(data) * 100:.1f}%)")
print(
f"不可饮用 (0): {potability_counts.get(0, 0)} 个样本 ({potability_counts.get(0, 0) / len(data) * 100:.1f}%)")
# 检查类别平衡性
balance_ratio = min(potability_counts) / max(potability_counts)
if balance_ratio < 0.8:
print(f"⚠️ 警告: 数据不平衡 (比例: {balance_ratio:.2f})")
else:
print(f"✓ 数据相对平衡 (比例: {balance_ratio:.2f})")
# 3. 异常值检查 (使用IQR方法)
print(f"\n异常值检查 (使用四分位距方法):")
numeric_columns = data.select_dtypes(include=[np.number]).columns
numeric_columns = [col for col in numeric_columns if col != 'Potability']
outlier_summary = []
for col in numeric_columns:
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)][col]
outlier_count = len(outliers)
outlier_percent = (outlier_count / len(data)) * 100
outlier_summary.append({
'特征': col,
'异常值数量': outlier_count,
'异常值比例(%)': outlier_percent
})
outlier_df = pd.DataFrame(outlier_summary)
print(outlier_df)
return data
def handle_missing_values(data):
"""
处理缺失值
学习不同的缺失值处理策略及其适用场景
"""
print("\n" + "=" * 50)
print("步骤1.3: 缺失值处理")
print("=" * 50)
# 记录原始数据大小
original_size = len(data)
print(f"原始数据集大小: {original_size}")
# 统计每行的缺失值数量
missing_per_row = data.isnull().sum(axis=1)
print(f"完全无缺失值的行数: {sum(missing_per_row == 0)}")
print(f"有1个缺失值的行数: {sum(missing_per_row == 1)}")
print(f"有2个以上缺失值的行数: {sum(missing_per_row >= 2)}")
# 处理策略: 删除有缺失值的行
# 注: 这里选择删除是因为项目重点是学习机器学习流程,而非复杂的缺失值处理
print(f"\n选择处理策略: 删除包含缺失值的行")
print(f"原因: 保持数据完整性,专注于学习机器学习核心流程")
# 删除缺失值
data_clean = data.dropna()
cleaned_size = len(data_clean)
removed_count = original_size - cleaned_size
removed_percent = (removed_count / original_size) * 100
print(f"清理后数据集大小: {cleaned_size}")
print(f"移除样本数: {removed_count} ({removed_percent:.1f}%)")
# 验证清理效果
print(f"\n验证: 清理后的缺失值统计")
print(data_clean.isnull().sum().sum() == 0 and "✓ 成功移除所有缺失值" or "✗ 仍有缺失值")
return data_clean
def handle_outliers(data):
"""
处理异常值
学习异常值检测和处理方法
"""
print("\n" + "=" * 50)
print("步骤1.4: 异常值处理")
print("=" * 50)
# 获取数值型特征 (排除目标变量)
numeric_features = [col for col in data.select_dtypes(include=[np.number]).columns
if col != 'Potability']
print(f"处理 {len(numeric_features)} 个数值特征的异常值")
# 记录处理前后的数据
data_processed = data.copy()
outlier_counts = {}
# 对每个数值特征进行异常值处理
for col in numeric_features:
print(f"\n处理特征: {col}")
# 计算四分位距
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
# 识别异常值
outlier_mask = (data[col] < lower_bound) | (data[col] > upper_bound)
outlier_count = outlier_mask.sum()
outlier_counts[col] = outlier_count
print(f" 异常值边界: [{lower_bound:.3f}, {upper_bound:.3f}]")
print(f" 检测到异常值: {outlier_count} 个")
# 处理策略: 使用边界值截断 (Winsorization)
# 这比删除异常值更温和,保留了更多数据用于学习
data_processed.loc[data_processed[col] < lower_bound, col] = lower_bound
data_processed.loc[data_processed[col] > upper_bound, col] = upper_bound
print(f" 处理方法: 截断到边界值")
total_outliers_handled = sum(outlier_counts.values())
print(f"\n总计处理异常值: {total_outliers_handled} 个")
print(f"异常值处理策略: 截断法 (保留数据,提高模型稳定性)")
return data_processed
def normalize_features(data):
"""
特征标准化/归一化
学习为什么需要标准化以及如何实现
"""
print("\n" + "=" * 50)
print("步骤1.5: 特征标准化")
print("=" * 50)
# 分离特征和目标变量
feature_columns = [col for col in data.columns if col != 'Potability']
X = data[feature_columns].values
y = data['Potability'].values
print(f"需要标准化的特征数量: {len(feature_columns)}")
print(f"特征名称: {feature_columns}")
# 显示标准化前的数据范围
print(f"\n标准化前各特征的数据范围:")
for i, col in enumerate(feature_columns):
col_data = X[:, i]
print(
f" {col}: [{col_data.min():.3f}, {col_data.max():.3f}] (均值: {col_data.mean():.3f}, 标准差: {col_data.std():.3f})")
# 使用StandardScaler进行标准化
print(f"\n应用标准化 (Z-score normalization): (x - mean) / std")
scaler = StandardScaler()
X_normalized = scaler.fit_transform(X)
# 验证标准化效果
print(f"\n标准化后各特征的统计信息:")
for i, col in enumerate(feature_columns):
col_data = X_normalized[:, i]
print(f" {col}: 均值={col_data.mean():.6f}, 标准差={col_data.std():.6f}")
print(f"\n✓ 标准化完成!")
print(f"为什么需要标准化:")
print(f" 1. 不同特征的量级差异很大 (pH: 6-8, Conductivity: 0-800)")
print(f" 2. 标准化确保所有特征对模型训练有相等的影响")
print(f" 3. 提高梯度下降等优化算法的收敛速度")
return X_normalized, y, scaler
def convert_to_pytorch_tensors(X, y):
"""
转换为PyTorch张量
学习如何将数据转换为深度学习框架可用的格式
"""
print("\n" + "=" * 50)
print("步骤1.6: 转换为PyTorch张量")
print("=" * 50)
print(f"原始数据类型: X={type(X)}, y={type(y)}")
print(f"原始数据形状: X={X.shape}, y={y.shape}")
# 转换为PyTorch张量
X_tensor = torch.FloatTensor(X)
y_tensor = torch.LongTensor(y) # 分类任务使用LongTensor
print(f"\n转换后张量信息:")
print(f" 特征张量 (X): {X_tensor.shape}, 数据类型: {X_tensor.dtype}")
print(f" 标签张量 (y): {y_tensor.shape}, 数据类型: {y_tensor.dtype}")
# 检查张量的基本统计信息
print(f"\n张量统计验证:")
print(f" X_tensor - 最小值: {X_tensor.min():.3f}, 最大值: {X_tensor.max():.3f}")
print(f" y_tensor - 唯一值: {torch.unique(y_tensor).tolist()}")
print(f"\n✓ 数据预处理完成!")
print(f"数据现在可以用于PyTorch模型训练")
return X_tensor, y_tensor
def save_preprocessed_data(X_tensor, y_tensor, scaler, output_dir="preprocessed_data"):
"""
保存预处理后的数据
便于后续步骤直接加载使用
"""
import os
print("\n" + "=" * 50)
print("步骤1.7: 保存预处理结果")
print("=" * 50)
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 保存张量数据
torch.save(X_tensor, f"{output_dir}/X_tensor.pt")
torch.save(y_tensor, f"{output_dir}/y_tensor.pt")
# 保存标准化器 (用于新数据的预处理)
import joblib
joblib.dump(scaler, f"{output_dir}/scaler.pkl")
print(f"✓ 数据已保存到 {output_dir}/ 目录:")
print(f" - X_tensor.pt: 预处理后的特征数据")
print(f" - y_tensor.pt: 目标标签数据")
print(f" - scaler.pkl: 标准化器 (用于新数据预处理)")
def main():
"""
主函数 - 执行完整的数据预处理流程
这是机器学习项目的第一个关键步骤
"""
print("🎯 水质安全预测项目 - 数据预处理")
print("📚 学习目标: 掌握机器学习数据预处理的完整流程")
print("包括: 数据加载、质量检查、缺失值处理、异常值处理、特征标准化、数据转换")
# 数据文件路径 (请修改为您的数据文件路径)
file_path = "water_potability.csv"
try:
# 步骤1: 数据加载与探索
data = load_and_explore_data(file_path)
if data is None:
return
# 步骤2: 数据质量检查
data = check_data_quality(data)
# 步骤3: 缺失值处理
data_clean = handle_missing_values(data)
# 步骤4: 异常值处理
data_processed = handle_outliers(data_clean)
# 步骤5: 特征标准化
X_normalized, y, scaler = normalize_features(data_processed)
# 步骤6: 转换为PyTorch张量
X_tensor, y_tensor = convert_to_pytorch_tensors(X_normalized, y)
# 步骤7: 保存预处理结果
save_preprocessed_data(X_tensor, y_tensor, scaler)
print("\n" + "🎉" * 20)
print("数据预处理完成!")
print("下一步: 进行步骤2 - 构建监督分类任务")
print("🎉" * 20)
except Exception as e:
print(f"❌ 预处理过程中发生错误: {e}")
print("请检查数据文件路径和格式")
if __name__ == "__main__":
main()
"""
📝 学习总结:
通过这个步骤,你学会了:
1. 如何系统地探索和理解数据集
2. 识别和处理真实数据中的质量问题
3. 应用不同的数据清理策略
4. 为机器学习准备干净、标准化的数据
5. 使用PyTorch处理数据的基本方法
这些技能在任何机器学习项目中都是必需的!
"""