数据预处理是数据科学项目中至关重要的环节,直接影响分析结果的准确性和模型性能。本章将介绍数据预处理的核心技术,包括缺失值和异常值处理、特征缩放与编码,以及探索性数据分析方法。
import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
# 创建包含缺失值和异常值的示例数据
print("=== 缺失值与异常值处理 ===")
data = {
'年龄': [25, 30, np.nan, 35, 28, 150, 32, np.nan], # 150是异常值
'收入': [50000, 60000, 55000, np.nan, 52000, 1000000, np.nan, 58000], # 1000000是异常值
'城市': ['北京', '上海', np.nan, '广州', '深圳', '北京', '上海', '杭州']
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
# 检查缺失值
print("\n缺失值统计:")
print(df.isnull().sum())
# 处理缺失值 - 数值列用均值填充
print("\n处理缺失值...")
df_cleaned = df.copy()
df_cleaned['年龄'].fillna(df_cleaned['年龄'].mean(), inplace=True)
df_cleaned['收入'].fillna(df_cleaned['收入'].mean(), inplace=True)
df_cleaned['城市'].fillna('未知', inplace=True)
# 检测和处理异常值
print("\n检测异常值...")
def detect_outliers(data):
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = data[(data < lower_bound) | (data > upper_bound)]
return outliers
print("年龄异常值:", detect_outliers(df_cleaned['年龄']).tolist())
print("收入异常值:", detect_outliers(df_cleaned['收入']).tolist())
# 处理异常值 - 使用中位数替换
print("\n处理异常值...")
age_median = df_cleaned['年龄'].median()
income_median = df_cleaned['收入'].median()
df_cleaned.loc[df_cleaned['年龄'] > 100, '年龄'] = age_median
df_cleaned.loc[df_cleaned['收入'] > 200000, '收入'] = income_median
print("处理后的数据:")
print(df_cleaned)
from sklearn.preprocessing import StandardScaler, MinMaxScaler, LabelEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer
print("=== 特征缩放与编码 ===")
# 创建示例数据
data = {
'年龄': [25, 30, 35, 28, 32],
'收入': [50000, 60000, 55000, 52000, 58000],
'城市': ['北京', '上海', '广州', '深圳', '北京'],
'学历': ['本科', '硕士', '博士', '本科', '硕士']
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
# 特征缩放 - 标准化
print("\n=== 特征标准化 ===")
scaler = StandardScaler()
scaled_data = scaler.fit_transform(df[['年龄', '收入']])
df_scaled = pd.DataFrame(scaled_data, columns=['年龄_标准化', '收入_标准化'])
print(df_scaled)
# 特征缩放 - 归一化
print("\n=== 特征归一化 ===")
minmax_scaler = MinMaxScaler()
normalized_data = minmax_scaler.fit_transform(df[['年龄', '收入']])
df_normalized = pd.DataFrame(normalized_data, columns=['年龄_归一化', '收入_归一化'])
print(df_normalized)
# 标签编码
print("\n=== 标签编码 ===")
label_encoder = LabelEncoder()
df['城市_编码'] = label_encoder.fit_transform(df['城市'])
df['学历_编码'] = label_encoder.fit_transform(df['学历'])
print("标签编码后的数据:")
print(df[['城市', '城市_编码', '学历', '学历_编码']])
# 独热编码
print("\n=== 独热编码 ===")
onehot_encoder = OneHotEncoder(sparse_output=False)
onehot_data = onehot_encoder.fit_transform(df[['城市']])
onehot_columns = onehot_encoder.get_feature_names_out(['城市'])
df_onehot = pd.DataFrame(onehot_data, columns=onehot_columns)
print("独热编码后的数据:")
print(df_onehot)
# 组合所有处理后的特征
print("\n=== 最终处理后的数据集 ===")
df_final = pd.concat([df_scaled, df_normalized, df[['城市_编码', '学历_编码']], df_onehot], axis=1)
print(df_final)
import matplotlib.pyplot as plt
import seaborn as sns
print("=== 探索性数据分析 ===")
# 创建示例数据集
np.random.seed(42)
n_samples = 200
data = {
'年龄': np.random.normal(35, 10, n_samples),
'收入': np.random.normal(50000, 15000, n_samples),
'消费分数': np.random.normal(70, 15, n_samples),
'城市': np.random.choice(['北京', '上海', '广州', '深圳'], n_samples),
'性别': np.random.choice(['男', '女'], n_samples)
}
df = pd.DataFrame(data)
print("数据集基本信息:")
print(df.info())
print("\n数据集描述性统计:")
print(df.describe())
# 数据分布可视化
print("\n=== 数据分布分析 ===")
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 年龄分布
axes[0, 0].hist(df['年龄'], bins=20, color='skyblue', alpha=0.7)
axes[0, 0].set_title('年龄分布')
axes[0, 0].set_xlabel('年龄')
axes[0, 0].set_ylabel('频数')
// 收入分布
axes[0, 1].hist(df['收入'], bins=20, color='lightcoral', alpha=0.7)
axes[0, 1].set_title('收入分布')
axes[0, 1].set_xlabel('收入')
axes[0, 1].set_ylabel('频数')
// 消费分数箱线图
axes[1, 0].boxplot(df['消费分数'])
axes[1, 0].set_title('消费分数箱线图')
axes[1, 0].set_ylabel('消费分数')
// 城市分布
city_counts = df['城市'].value_counts()
axes[1, 1].bar(city_counts.index, city_counts.values, color=['skyblue', 'lightcoral', 'lightgreen', 'gold'])
axes[1, 1].set_title('城市分布')
axes[1, 1].set_xlabel('城市')
axes[1, 1].set_ylabel('人数')
plt.tight_layout()
plt.show()
// 相关性分析
print("\n=== 相关性分析 ===")
numeric_cols = df.select_dtypes(include=[np.number]).columns
correlation_matrix = df[numeric_cols].corr()
print("数值变量相关性矩阵:")
print(correlation_matrix)
// 相关性热力图
plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0)
plt.title('变量相关性热力图')
plt.show()
// 分组分析
print("\n=== 分组分析 ===")
print("不同城市的平均收入:")
print(df.groupby('城市')['收入'].mean())
print("\n不同性别的平均消费分数:")
print(df.groupby('性别')['消费分数'].mean())
// 散点图分析关系
plt.figure(figsize=(10, 6))
sns.scatterplot(data=df, x='年龄', y='收入', hue='城市', style='性别', s=100)
plt.title('年龄与收入关系散点图')
plt.show()