Back to AI

人工智慧新手村

Coming soon

floatingOnTheSea

DemoProject – 大災難發生時的生存率

每當社會群體中有所謂大型活動, 大型建築物時, 設計師, 建築師, 消防規劃師….等. 都必須預想有不姓的事情發生時, 群眾如何安全的逃離所在建築, 活動區域, 甚至是災難現場. 透過大數據的分析可以讓我們再不幸的事情發生時, 多一點準備, 少一點意外. 我們這篇就以鐵達尼號沈船事件來做一個災難模擬分析預測系統.

程式碼 Concept
這個專案的目標是二元分類:預測乘客 「會活下來 (1)」 還是 「不幸罹難 (0)」。所以這是一個分類問題

這個專案對新手的最大價值在於學習 資料前處理 (Data Preprocessing),特別是如何處理「缺少的資料(如年齡)」以及如何把「文字(如性別)」
轉換成電腦看得懂的數字

這次我們是使用直觀且強大的 「決策樹 (Decision Tree)」 模型來製作這次的專案

開發重點:
1. 處理缺漏值 (fillna):
   鐵達尼號資料中,很多人的年齡 (age) 是空白的。如果直接刪掉這些人,資料會變太少。
   我們使用 df['age'].median() 算出所有人的年齡中位數(約 28 歲),然後把空白的格子都填上這個數字。

2. 文字轉數字 (One-Hot Encoding / Dummy Variables):
   a. pd.get_dummies(..., columns=['sex'])
   b. 模型無法計算 "male" * 0.5 這種數學式。
   c. 所以我們把它轉換成 sex_male 欄位:如果是 1 代表是男生,0 代表不是男生(即女生)

3. 決策樹 (Decision Tree):
   a. 為什麼選這個?因為它跟人類思考很像。它會建立一系列的 if-else 規則。
   b. 例如:if (是男生?) then (死亡機率高) -> else if (坐頭等艙?) then (存活機率高)
   c. 我們設定 max_depth=3,限制樹不要長太深,這樣比較不會「死記硬背」(Overfitting),通用性較好

Output 圖表與結果說明

1. 準確率 (Accuracy)
   通常這個簡單的模型能達到 78% - 82% 左右的準確率。這意味著每 10 個人,它能猜對 8 個人的生死

2. 特徵重要性圖表 (Feature Importance)
   a. 執行後您會看到一張長條圖。
   b. 通常 sex_male (性別) 會是條最長的,代表「性別」是決定生死的最大關鍵(女士優先)。
   c. 其次通常是 pclass (艙等) 或 fare (票價)(有錢人優先)

3. Jack 與 Rose 的預測
   a. 程式碼最後我手動輸入了電影主角的資料。
   b. 不出意外的話,模型會準確預測 Jack 死亡 (三等艙+男性),而 Rose 存活 (頭等艙+女性)。
      這證明了模型學到了當時社會「婦孺與富人優先」的殘酷現實

demo code

# 引入必要的套件
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import os  # 【新增】用來檢查檔案是否存在的套件
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, confusion_matrix

# --- 設定中文字型 (macOS 專用) ---
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# --------------------------------

# ---------------------------------------------------------
# 第一步:載入資料
# ---------------------------------------------------------
print("正在載入鐵達尼號資料集...")
df = sns.load_dataset('titanic')

# ---------------------------------------------------------
# 第二步:資料清洗與特徵工程
# ---------------------------------------------------------
print("正在進行資料清洗...")

features = ['pclass', 'sex', 'age', 'sibsp', 'parch', 'fare']
target = 'survived'

# 只保留我們要的欄位
df_model = df[features + [target]].copy()

# 處理缺漏值 (Age)
df_model['age'] = df_model['age'].fillna(df_model['age'].median())

# 處理文字資料 (Sex)
df_model = pd.get_dummies(df_model, columns=['sex'], drop_first=True)
# 轉換後 'sex' 變成了 'sex_male' (1=男, 0=女)

print("資料清洗完成!")

# ---------------------------------------------------------
# 第三步:切分資料 (Training vs Testing)
# ---------------------------------------------------------
X = df_model.drop('survived', axis=1) # 特徵
y = df_model['survived']              # 答案

# 切分資料 (75% 訓練, 25% 測試)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42
)

# ---------------------------------------------------------
# 【新增功能】輸出 CSV (含檔案存在檢查)
# ---------------------------------------------------------
print("-" * 30)
# 定義檔名
train_filename = 'titanic_train.csv'
test_filename = 'titanic_test.csv'

# 檢查訓練資料檔是否存在
if os.path.exists(train_filename):
    print(f"⚠️  檔案已存在:{train_filename},跳過輸出步驟。")
else:
    # 合併 X 和 y 並存檔
    train_df = pd.concat([X_train, y_train], axis=1)
    train_df.to_csv(train_filename, index=False)
    print(f"✅ 已建立新檔案:{train_filename}")

# 檢查測試資料檔是否存在
if os.path.exists(test_filename):
    print(f"⚠️  檔案已存在:{test_filename},跳過輸出步驟。")
else:
    test_df = pd.concat([X_test, y_test], axis=1)
    test_df.to_csv(test_filename, index=False)
    print(f"✅ 已建立新檔案:{test_filename}")

print("-" * 30)

# ---------------------------------------------------------
# 第四步:建立並訓練模型
# ---------------------------------------------------------
print("正在訓練決策樹模型...")
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
print("訓練完成!")

# ---------------------------------------------------------
# 第五步:模型評估
# ---------------------------------------------------------
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)

print(f"【模型準確率 (Accuracy)】: {accuracy:.2%}")
print("\n【混淆矩陣】(左上:正確死亡, 右下:正確存活)")
print(confusion_matrix(y_test, y_pred))

# ---------------------------------------------------------
# 第六步:視覺化 - 關鍵特徵重要性 (已修正警告)
# ---------------------------------------------------------
plt.figure(figsize=(8, 5))
importances = model.feature_importances_
feature_names = X.columns

# 加入 hue=feature_names 和 legend=False 解決警告
sns.barplot(x=importances, y=feature_names, hue=feature_names, legend=False, palette='viridis')

plt.title('鐵達尼號生存預測 - 關鍵特徵權重')
plt.xlabel('重要性 (Importance)')
plt.ylabel('特徵 (Feature)')
plt.tight_layout() # 讓版面自動調整,避免文字被切掉
plt.show()

# ---------------------------------------------------------
# 額外 Demo:Jack & Rose 預測 (已修正 DataFrame 格式)
# ---------------------------------------------------------
print("\n【電影主角命運預測】")

columns = ['pclass', 'age', 'sibsp', 'parch', 'fare', 'sex_male']
# pclass,艙等
# age,年齡
# sibsp,兄弟姊妹/配偶數
# parch,父母/子女數
# fare,票價
# sex_male,性別

# 建立 DataFrame 並指定欄位名稱
jack_data = pd.DataFrame([[3, 20, 0, 0, 7.25, 1]], columns=columns)
rose_data = pd.DataFrame([[1, 17, 1, 2, 100, 0]], columns=columns)

pred_jack = model.predict(jack_data)[0]
pred_rose = model.predict(rose_data)[0]

print(f"Jack 預測結果: {'存活' if pred_jack==1 else '死亡'}")
print(f"Rose 預測結果: {'存活' if pred_rose==1 else '死亡'}")

說明文件:

訓練文件:

驗證文件:

Leave a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *