9.2 pandas与sklearn

9.2.1 导入数据集

import pandas as pd

# 读取CSV文件
df = pd.read_csv(path)

# 读取Excel文件
df = pd.read_excel(path)
# 读取Excel文件中的多个sheet,存储为字典
df = pd.read_excel(path, sheet_name=['Sheet1', 'Sheet2'])
# 读取Excel文件中所有sheet,存储为字典
df = pd.read_excel(path, sheet_name=None)

9.2.2 数据预处理

  1. 缺失值处理
# 各列缺失值数量
df.count()
df.isna().sum()   # df.notna()

# 各列缺失值比例
df.isnull().mean() * 100

# 缺失值可视化
import missingno as msno
import matplotlib.pyplot as plt
msno.matrix(df) # 矩阵图:直观展示缺失值在数据中的分布
plt.show()

msno.bar(df)    # 条形图:按列展示完整数据比例
plt.show()

# 删除缺失值
# axis表示要压缩的维度。若axis=0,则压缩行,保留列方向的操作结果
df = df.dropna()                         # 删除包含任何缺失值的行
df = df.dropna(axis=1, how='all')        # 删除全是缺失值的列
df = df.dropna(subset=["col1", "col2"])  # 删除特定列缺失值所在的行

# 填充缺失值
df_filled = df.fillna(0)                    # 用固定值填充
df['A'] = df['A'].fillna(df['A'].mean())    # 均值
df['B'] = df['B'].fillna(df['B'].median())  # 中位数
df = df.ffill()                             # 前向填充
df = df.bfill()                             # 后向填充
df = df.interpolate()                       # 用插值法填充(更平滑的填充方式)
  1. 异常值处理
# Z-score
df_num = df.select_dtypes(include=['number'])   # 筛选数值列
df_zscore = df_num.apply(lambda col:(col-col.mean())/col.std(), axis = 0) # df_zscore是数据框
df[(df_zscores.abs() > 2).any(axis = 1)]

# 四分位距
Q1 = num_df.quantile(0.25)
Q3 = num_df.quantile(0.75)
IQR = Q3 - Q1
outliers = ((num_df < (Q1 - 1.5 * IQR)) | (num_df > (Q3 + 1.5 * IQR)))
df[df_num.columns] = df_num.clip(lower=Q1, upper=Q3, axis = 1)
  1. 标准化
from sklearn.preprocessing import StandardScaler
# from sklearn.preprocessing import MinMaxScaler

# 选取数值列
numeric_cols = df.select_dtypes(include=['number']).columns
# 标准化并替换
scaler = StandardScaler()    # scaler = MinMaxScaler()
df[numeric_cols] = scaler.fit_transform(df[numeric_cols])
  1. 编码
# 独热编码
df = pd.get_dummies(df, dtype = int)
# 也可考虑from sklearn.preprocessing import OneHotEncoder

# 哑变量编码
df = pd.get_dummies(df, dtype = int, drop_first=True)

# 频率编码
frequency = df['A'].value_counts(normalize=True)
df['A'] = df['A'].map(frequency)

# 有序变量编码
df['评分'] = pd.Categorical(
    df['评分'], 
    categories=['低', '中', '高', '极高'], 
    ordered=True
)
df['评分编码'] = df['评分'].cat.codes

# 自定义编码
edu_map = {'小学': 1, '中学': 2, '大学': 3, '硕士': 4, '博士': 5}
df['edu'] = df['edu'].map(edu_map)
  1. 表的连接与拼接
# on表示主键
# how表示连接方式:inner、outer、left、right
df_merge = df1.merge(df2, on='id', how='inner')
df_merge = pd.merge(df1, df2, on='id', how='inner')
# 当键名不同时
df = pd.merge(df1, df2, left_on='id', right_on='user_id', how='inner')

# 表拼接
# ignore_index=True表示充值索引
df_concat = pd.concat([df1, df2], axis = 0) # 纵向堆叠
df_concat = pd.concat([df1, df2], axis = 1) # 横向堆叠
  1. 数据透视表

.pivot()pd.melt()都不会保留未用到的列,得注意。

# 长表变宽表
wide = df.pivot(index='name', columns='subject', values='score').reset_index()  # 将索引列转化为第一列
wide = wide.merge(df[['name', 'age']].drop_duplicates(), on='name', how='left') # 保留原始列
# 若index存在重复值,则考虑pivot_table(),可以指定处理重复值的聚合函数


# 宽表变长表
# 参数value_vars是个列表,存储需要压缩的列名,如果不填,默认除id_vars外的所有列
pd.melt(wide, id_vars=['name', 'age'], var_name='subject', value_name='score')
  1. 分组聚合
# 核心表达式
DataFrame.groupby(keys)[columns].agg(func) # 如果是多个列则columns应该再用列表嵌套

# 单函数聚合
df.groupby('region')['revenue'].agg('sum')

# 多函数聚合
df.groupby('region')[['revenue', 'unit']].agg(['sum', 'mean'])

# 字典映射(只对特定列进行聚合):列名为键,函数为值
df.groupby('region').agg({
    'revenue': 'sum',
    'units': 'mean'
})

# 命名聚合:新列名=('旧列名', '函数名')
df.groupby('region').agg(
    total_revenue=('revenue', 'sum'),
    avg_units=('units', 'mean'),
    max_revenue=('revenue', 'max')
)

# 自定义函数
df.groupby('region')['revenue'].agg(lambda x: x.max() - x.min())

9.2.3 分割数据集

from sklearn.model_selection import train_test_split

# 训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=42)

# 分层分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify= categorical_var)

# 交叉验证
from sklearn.model_selection import KFold
kf = KFold(n_splits=10, shuffle=True, random_state=42)
for train_index, test_index in kf.split(X, y):
    # 获取分割后的训练集和测试集
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    ...
# 也可使用cross_val_score及cross_validate来简化交叉验证流程
cross_val_score(model, X, y, cv=5, scoring='accuracy')   # 单个评估指标
cross_validate(model, X, y, cv=5, scoring=['accuracy', 'f1_macro'], return_train_score=True) # 多个评估指标