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。