1. 导入packages
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set(style='darkgrid', font_scale=1.4)
from imblearn.over_sampling import SMOTE
import itertools
import warnings
warnings.filterwarnings('ignore')
import plotly.express as px
import time
- %matplotlib inline: 这是一条 Jupyter Notebook 的魔法命令,使图表可以直接显示在 Notebook 单元格中。(如果不是在 Jupyter Notebook 运行,这行代码会报错)
- sns.set(style=‘darkgrid’, font_scale=1.4): 设置默认的绘图风格为 darkgrid(深色网格背景),并调整字体比例,使图例和标签更易读。
- plotly.express (px): 交互式可视化库 Plotly 的简化接口,适用于绘制动态图表。
- SMOTE(Synthetic Minority Over-sampling Technique):从 imblearn.over_sampling 模块导入,用于处理数据不平衡问题,通过合成少数类样本来提升分类模型的表现。
- time: 用于时间管理,比如计算代码运行时间 (time.time() 获取当前时间戳)。
- warnings.filterwarnings(‘ignore’): 忽略所有警告信息,避免影响代码运行时的可读性(但可能隐藏重要警告)。
from sklearn.model_selection import train_test_split, GridSearchCV, RandomizedSearchCV, StratifiedKFold
from sklearn.metrics import accuracy_score, confusion_matrix, recall_score, precision_score, f1_score
from sklearn.metrics import roc_auc_score, ConfusionMatrixDisplay, RocCurveDisplay, roc_curve
from sklearn.preprocessing import StandardScaler, MinMaxScaler, OneHotEncoder, LabelEncoder
from sklearn.feature_selection import mutual_info_classif
from sklearn.decomposition import PCA
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
import eli5
from eli5.sklearn import PermutationImportance
from sklearn.utils import resample
- StratifiedKFold: 分层 K 折交叉验证,确保训练集和验证集中 类别分布相同,适用于分类任务。
- StandardScaler: 标准化(均值 0,方差 1,适用于正态分布数据)。
- PCA: 主成分分析(降维,减少特征数量,保留重要信息)。
- ColumnTransformer: 针对不同列使用不同的预处理方法(例如,数值特征用 StandardScaler,类别特征用 OneHotEncoder)。
# Models
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
from catboost import CatBoostClassifier
from sklearn.naive_bayes import GaussianNB
2. 数据
train = pd.read_csv('/kaggle/input/spaceship-titanic/train.csv')
test = pd.read_csv('/kaggle/input/spaceship-titanic/test.csv')print('Train set shape: ', train.shape)
print('Test set shape: ', test.shape)
train.head()
Train set shape: (8693, 14)
Test set shape: (4277, 13)
缺失值
print('TRAIN SET MISSING VALUES:')
print(train.isna().sum())
print('')
print('TEST SET MISSING VALUES')
print(test.isna().sum())
TRAIN SET MISSING VALUES:
PassengerId 0
HomePlanet 201
CryoSleep 217
Cabin 199
Destination 182
Age 179
VIP 203
RoomService 181
FoodCourt 183
ShoppingMall 208
Spa 183
VRDeck 188
Name 200
Transported 0
dtype: int64TEST SET MISSING VALUES
PassengerId 0
HomePlanet 87
CryoSleep 93
Cabin 100
Destination 92
Age 91
VIP 93
RoomService 82
FoodCourt 106
ShoppingMall 98
Spa 101
VRDeck 80
Name 94
dtype: int64
我们可以看到每一个feature都有缺失值,如何处理这些缺失值非常重要。
重复值
train_duplicate = train.duplicated().sum()
test_duplicate = test.duplicated().sum()print(f'Duplicates in train set: {train_duplicate}, ({np.round(100*train_duplicate/len(train), 1)}%)')
print('')
print(f'Duplicates in test set: {test_duplicate}, ({np.round(100*test_duplicate/len(test), 1)}%)')
Duplicates in train set: 0, (0.0%)Duplicates in test set: 0, (0.0%)
Cardinality of Features(特征的基数)
train.nunique()
PassengerId 8693
HomePlanet 3
CryoSleep 2
Cabin 6560
Destination 3
Age 80
VIP 2
RoomService 1273
FoodCourt 1507
ShoppingMall 1115
Spa 1327
VRDeck 1306
Name 8473
Transported 2
dtype: int64
什么是 Cardinality of Features(特征的基数)?
特征的基数(Cardinality of Features) 指的是 一个特征(变量)中唯一值(类别)的数量,通常用于描述类别特征(categorical features)。
低基数(Low Cardinality) vs. 高基数(High Cardinality)
-
低基数(Low Cardinality):特征的唯一值较少,例如:
["Male", "Female"]
(性别,仅有 2 个唯一值)["Yes", "No"]
(是否订阅,仅有 2 个唯一值)["Red", "Green", "Blue"]
(颜色,仅有 3 个唯一值)
-
高基数(High Cardinality):特征的唯一值较多,例如:
["user_123", "user_456", ..., "user_99999"]
(用户 ID,有数万个唯一值)["google.com", "facebook.com", ..., "randomsite.com"]
(网站访问记录)["New York", "Los Angeles", "Toronto", ..., "Paris"]
(全球城市名称)
为什么基数重要?
不同的基数会影响机器学习模型的性能和存储效率,特别是在类别特征编码时。
基数类型 | 影响 |
---|---|
低基数(Low Cardinality) | - 适合 独热编码(One-Hot Encoding)。 - 易于存储,计算成本低。 |
高基数(High Cardinality) | - One-Hot Encoding 会导致维度爆炸(Curse of Dimensionality)。 - 适合 目标编码(Target Encoding) 或 哈希编码(Hash Encoding)。 |
如何处理高基数特征?
如果类别特征的基数过高,通常有以下几种方法:
- 目标编码(Target Encoding):用该类别对应的目标变量均值代替类别(适用于回归任务)。
- 哈希编码(Hash Encoding):通过哈希函数将类别映射到固定数量的维度(减少特征数)。
- 降维:使用 PCA、UMAP 等方法降低类别特征的维度。
- 合并类别:将出现频率低的类别归为 “Other” 组,减少唯一值数量。
数据类型
train.dtypes
PassengerId object
HomePlanet object
CryoSleep object
Cabin object
Destination object
Age float64
VIP object
RoomService float64
FoodCourt float64
ShoppingMall float64
Spa float64
VRDeck float64
Name object
Transported bool
dtype: object
3. 探索性数据分析
plt.figure(figsize=(6,6))# Pie plot
train['Transported'].value_counts().plot.pie(explode=[0.1, 0.1],autopct='%1.1f%%',shadow=True,textprops={'fontsize': 16}
).set_title("Target distribution")
- 统计 Transported 变量的类别数量,即数据集中该变量的分布情况。
- Transported 变量是一个二分类变量(如 True/False 或 0/1),则 value_counts() 返回每个类别的样本数。
- “炸开” 饼图中的每个扇形,使其稍微分开以提高可视化效果。
- [0.1, 0.1] 表示两个类别的扇形都向外偏移 0.1 个单位。
- 自动显示每个类别占比的百分比,格式为 1 位小数
- 给饼图添加阴影,使图表更立体。
- 设置文本属性,调整 字体大小 为 16 以提高可读性。
年龄
plt.figure(figsize=(10, 4))# Histogram
sns.histplot(data=train, x='Age', hue='Transported', binwidth=1, kde=True)plt.title('Age distribution')
plt.xlabel('Age (years)')
Python 代码解析:绘制年龄分布直方图(Histogram)
plt.figure(figsize=(10, 4))# Histogram
sns.histplot(data=train, x='Age', hue='Transported', binwidth=1, kde=True)plt.title('Age distribution')
plt.xlabel('Age (years)')
我们可以看到0-18岁更容易被运输,18-25岁更不容易被运输,大于25岁的可能性相似。因此,我们可以加入一个特征,显示乘客是哪个年龄组的。
sns.histplot(...)
- 使用
seaborn
的histplot
绘制直方图,用于查看Age
变量的分布情况。
参数 | 作用 |
---|---|
data=train | 使用 train 数据集 |
x='Age' | x 轴为 Age (年龄) |
hue='Transported' | 按 Transported 变量分组(用不同颜色显示) |
binwidth=1 | 每个柱子的宽度为 1(即每个年龄单独分组) |
kde=True | 绘制 核密度估计曲线(平滑版直方图) |
为什么使用 KDE?
- 更平滑、更连续:直方图的分布可能会受 bin(柱子)的数量影响,而 KDE 能更平滑地表示数据分布趋势。
- 更直观地展示数据密度:它能显示数据在哪些区域更集中(密度更高),哪些区域更稀疏。
- 避免直方图的离散性问题:直方图的形状依赖于 binwidth,而 KDE 能提供更连续的分布。
消费
# Expenditure features
exp_feats = ['RoomService', 'FoodCourt', 'ShoppingMall', 'Spa', 'VRDeck']# Plot expenditure features
fig = plt.figure(figsize=(10,20))for i, var_name in enumerate(exp_feats):# left plotax = fig.add_subplot(5, 2, 2*i + 1)sns.histplot(data=train, x=var_name, axes=ax, bins=30, kde=False, hue='Transported')ax.set_title(var_name)# right plot (truncated)ax = fig.add_subplot(5, 2, 2*i + 2)sns.histplot(data=train, x=var_name, axes=ax, bins=30, kde=True, hue='Transported')plt.ylim([0, 100])ax.set_title(var_name)fig.tight_layout()
plt.show()
fig.tight_layout():自动调整子图之间的间距,防止重叠。
左侧:普通直方图(kde=False)。
右侧:带 KDE 的直方图(kde=True,并限制 y 轴)。
通过 hue=‘Transported’,查看 Transported=0 和 Transported=1 之间的差异。
我们可以看到被运输的乘客消费更少。
我们可以看到客房服务支出、水疗支出、VR 甲板支出和美食广场支出、购物中心支出有不同的分布。
- 我们可以创建一个新的特征记录总消费。
- 我们可以创建一个新的特征记录是否有消费。
类别特征
cat_feats = ['HomePlanet', 'CryoSleep', 'Destination', 'VIP']# plot categorical features
fig = plt.figure(figsize=(10, 16))
for i, var_name in enumerate(cat_feats):ax = fig.add_subplot(4, 1, i+1)sns.countplot(data=train, x=var_name, axes=ax, hue='Transported')ax.set_title(var_name)fig.tight_layout()
plt.show()
- CryoSleep:乘客是否处于冷冻睡眠状态(True/False)。
- 这些特征通常是有限离散值,适合使用计数图(countplot)展示。
VIP这个特征分布比较平均,没有什么用处。
CryoSleep是一个非常有用的特征。
Qualitative Features(定性特征)
qual_feats = ['PassengerId', 'Cabin', 'Name']train[qual_feats].head()
Qualitative Features(定性特征)是指无法用数值直接衡量或排序的特征,通常表示类别、属性或标签,而非连续的数值。这类特征也被称为Categorical Features(分类特征)。
- 我们可以从PassengerId获得组别和组别大小这两个特征。
- 我们可以从cabin获取deck, number 和 side这三个特征。
- 我们可以从Name获取Surname这个特征,从而识别families。