脫發因素機器學習數據分析
一、背景描述
隨著年齡增長,脫發成為影響外貌與健康的重要問題。
本數據集包含遺傳、荷爾蒙變化、醫療狀況、藥物治療、營養缺乏、心理壓力等12個可能導致脫發的因素,
旨在通過數據分析挖掘各因素與脫發的潛在關聯,為健康管理和醫療干預提供參考。
二、數據說明
字段 | 說明 | 數據類型 |
---|---|---|
Id | 標識符 | 整數 |
Genetics | 是否有禿頭家族史(1:是 / 0:否) | 二分類(0/1) |
Hormonal Changes | 是否經歷荷爾蒙變化 | 二分類(0/1) |
Medical Conditions | 病史(多選項) | 字符串(逗號分隔) |
Medications & Treatments | 藥物治療史(多選項) | 字符串(逗號分隔) |
Nutritional Deficiencies | 營養缺乏(多選項) | 字符串(逗號分隔) |
Stress | 壓力水平(低/中/高) | 分類變量 |
Age | 年齡 | 整數 |
Poor Hair Care Habits | 是否有不良護發習慣 | 二分類(0/1) |
Environmental Factors | 是否暴露于有害環境 | 二分類(0/1) |
Smoking | 是否吸煙 | 二分類(0/1) |
Weight Loss | 是否經歷顯著體重減輕 | 二分類(0/1) |
Hair Loss | 是否脫發 | 二分類(0/1) |
三、需求
1. 描述統計
- 計算平均年齡與年齡分布
- 統計最常見的醫療條件及其頻率
- 統計營養缺乏的種類及出現頻率
2. 可視化分析
- 不同年齡段脫發比例(柱狀圖)
- 各因素與脫發的相關性(熱力圖)
- 不同壓力水平下的脫發情況(柱狀圖)
3. 機器學習建模
- 構建分類模型預測脫發(邏輯回歸、隨機森林)
- 聚類分析探索脫發群體類型(KMeans)
- 識別關鍵影響因素(隨機森林特征重要性)
四、代碼實現
導包
# 先設置環境變量,避免CPU核心數警告
import os# 設置使用的CPU核心數(根據實際情況調整,建議為邏輯核心數的一半)
os.environ["LOKY_MAX_CPU_COUNT"] = "4"# 導入所需庫
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.cluster import KMeans
from sklearn.metrics import accuracy_score, classification_report
from sklearn.preprocessing import StandardScaler
import warnings
warnings.filterwarnings('ignore')# 配置matplotlib支持中文字體
plt.rcParams.update({"font.family": ["SimHei", "serif"],"axes.unicode_minus": False
})
數據預處理
# ---------------------- 數據讀取與預處理 ---------------------- #
# 讀取數據(確保列名與數據說明一致)
data = pd.read_csv('data/08/predict_hair_fall.csv')# ---------------------- 1. 二分類字段轉換(Yes/No轉0/1)---------------------- #
binary_columns = ['Genetics', 'Hormonal Changes', 'Poor Hair Care Habits','Environmental Factors', 'Smoking', 'Weight Loss', 'Hair Loss'
]
for col in binary_columns:data[col] = data[col].replace({'Yes': 1, 'No': 0}) # 假設數據用Yes/No表示# ---------------------- 2. 多選項字段拆分(生成二進制特征)---------------------- #
def split_multiple_features(df, column_name, prefix):"""拆分多選項字段為二進制特征"""df[column_name] = df[column_name].fillna('') # 處理空值# 拆分并生成虛擬變量dummies = df[column_name].str.split(', ', expand=True).stack().reset_index(level=1, drop=True)dummies = pd.get_dummies(dummies, prefix=prefix)return df.join(dummies.groupby(level=0).sum())# 拆分具體字段(注意列名需與數據集完全一致)
data = split_multiple_features(data, 'Medical Conditions', '病史')
data = split_multiple_features(data, 'Medications & Treatments', '藥物')
data = split_multiple_features(data, 'Nutritional Deficiencies', '營養')# ---------------------- 3. 壓力水平轉換(文本轉數值)---------------------- #
stress_mapping = {'Low': 1, 'Moderate': 2, 'High': 3}
data['Stress'] = data['Stress'].map(stress_mapping)# ---------------------- 4. 準備建模數據(排除非數值列)---------------------- #
drop_columns = ['Medical Conditions', 'Medications & Treatments', 'Nutritional Deficiencies', 'Id' # 排除原始字符串列和ID
]
model_data = data.drop(drop_columns, axis=1).copy() # 建模專用數據集(無字符串)
描述統計
# ---------------------- 描述統計 ---------------------- #
# 1. 年齡統計
average_age = model_data['Age'].mean()
print(f"平均年齡:{average_age:.1f}歲")plt.figure(figsize=(8, 4))
sns.histplot(model_data['Age'], bins=10, kde=True, color='skyblue')
plt.title('年齡分布直方圖')
plt.xlabel('年齡')
plt.ylabel('人數')
plt.show()# 2. 常見醫療條件統計
medical_counts = model_data.filter(like='病史_').sum().sort_values(ascending=False)
print("\n常見醫療條件(前5):")
print(medical_counts.head(5))# 3. 營養缺乏統計
nutritional_counts = model_data.filter(like='營養_').sum().sort_values(ascending=False)
print("\n營養缺乏種類(前5):")
print(nutritional_counts.head(5))
平均年齡:34.2歲
常見醫療條件(前5):
病史_No Data 110
病史_Alopecia Areata 107
病史_Psoriasis 100
病史_Thyroid Problems 99
病史_Androgenetic Alopecia 98
dtype: int64營養缺乏種類(前5):
營養_Zinc Deficiency 108
營養_Vitamin D Deficiency 104
營養_Biotin Deficiency 99
營養_Vitamin A Deficiency 99
營養_Omega-3 fatty acids 92
dtype: int64
可視化分析
# ---------------------- 可視化分析(使用原始數據創建分組)---------------------- #
# 單獨處理可視化數據(保留年齡分組)
visual_data = data.copy()
visual_data['年齡分組'] = pd.cut(visual_data['Age'], bins=[0, 20, 30, 40, 50, 60, 100],labels=['<20', '20-30', '30-40', '40-50', '50-60', '>60'])
不同年齡段脫發比例
# 1. 不同年齡段脫發比例
age_loss_ratio = visual_data.groupby('年齡分組')['Hair Loss'].mean().reset_index()plt.figure(figsize=(10, 6))
sns.barplot(x='年齡分組', y='Hair Loss', data=age_loss_ratio, palette='viridis')
plt.title('不同年齡段脫發比例')
plt.xlabel('年齡分組')
plt.ylabel('脫發比例')
plt.xticks(rotation=45)
plt.show()
因素與脫發的相關性熱力圖(使用建模數據,全為數值型)
# 2. 因素與脫發的相關性熱力圖(使用建模數據,全為數值型)
corr = model_data.corr()plt.figure(figsize=(12, 8))
sns.heatmap(corr[['Hair Loss']].sort_values(by='Hair Loss', ascending=False), annot=True, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('各因素與脫發的相關性')
plt.show()
不同壓力水平脫發情況
# 3. 不同壓力水平脫發情況
stress_loss = model_data.groupby('Stress')['Hair Loss'].mean().reset_index()
stress_loss['壓力水平'] = stress_loss['Stress'].map({1:'低', 2:'中', 3:'高'})plt.figure(figsize=(8, 5))
sns.barplot(x='壓力水平', y='Hair Loss', data=stress_loss, palette='rocket')
plt.title('不同壓力水平脫發比例')
plt.xlabel('壓力水平')
plt.ylabel('脫發比例')
plt.show()
機器學習建模
# ---------------------- 機器學習建模 ---------------------- #
X = model_data.drop('Hair Loss', axis=1)
y = model_data['Hair Loss']# 劃分數據集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
邏輯回歸模型
# 1. 邏輯回歸模型
logreg = LogisticRegression(max_iter=1000)
logreg.fit(X_train, y_train)
print(f"邏輯回歸準確率:{accuracy_score(y_test, logreg.predict(X_test)):.2f}")
邏輯回歸準確率:0.47
隨機森林模型
# 2. 隨機森林模型
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
print(f"隨機森林準確率:{accuracy_score(y_test, rf.predict(X_test)):.2f}")
隨機森林準確率:0.43
聚類分析 K-means 模型
# 3. 聚類分析(KMeans)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)# 肘部法則確定聚類數
inertia = []
for k in range(2, 6):kmeans = KMeans(n_clusters=k, random_state=42)inertia.append(kmeans.fit(X_scaled).inertia_)plt.figure(figsize=(8, 4))
plt.plot(range(2, 6), inertia, marker='o', linestyle='--', color='b')
plt.title('肘部法則確定聚類數')
plt.xlabel('聚類數k')
plt.ylabel('慣性值')
plt.show()
執行聚類
# 執行聚類(假設k=3)
kmeans = KMeans(n_clusters=3, random_state=42)
model_data['Cluster'] = kmeans.fit_predict(X_scaled)
print("\n聚類分布:")
print(model_data['Cluster'].value_counts())
聚類分布:
Cluster
2 601
1 226
0 172
Name: count, dtype: int64
重要特征分布
# 4. 特征重要性分析
features = X.columns
importances = rf.feature_importances_
importance_df = pd.DataFrame({'特征': features, '重要性': importances}).sort_values(by='重要性', ascending=False)plt.figure(figsize=(10, 6))
sns.barplot(x='重要性', y='特征', data=importance_df.head(10), palette='Set3')
plt.title('前10重要特征')
plt.xlabel('重要性得分')
plt.ylabel('特征')
plt.show()