{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "077f5f8a-ffe5-4405-8806-1b5559140a5d",
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install pandas hyperopt xgboost scikit-learn matplotlib numpy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a3901bba-d66d-4358-89a7-50dc4b3dd91e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from hyperopt import hp, fmin, tpe, STATUS_OK, Trials\n",
    "from sklearn.model_selection import train_test_split\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a4713d33-c5a2-4f49-8aed-873069543bec",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>比表面积</th>\n",
       "      <th>总孔体积</th>\n",
       "      <th>微孔体积</th>\n",
       "      <th>平均孔径</th>\n",
       "      <th>氮掺杂量at</th>\n",
       "      <th>氧掺杂量</th>\n",
       "      <th>ID/IG</th>\n",
       "      <th>电流密度</th>\n",
       "      <th>比电容</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1141.8</td>\n",
       "      <td>0.46</td>\n",
       "      <td>0.42</td>\n",
       "      <td>1.61</td>\n",
       "      <td>1.74</td>\n",
       "      <td>3.84</td>\n",
       "      <td>1.1</td>\n",
       "      <td>0.5</td>\n",
       "      <td>206.5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1141.8</td>\n",
       "      <td>0.46</td>\n",
       "      <td>0.42</td>\n",
       "      <td>1.61</td>\n",
       "      <td>1.74</td>\n",
       "      <td>3.84</td>\n",
       "      <td>1.1</td>\n",
       "      <td>1.0</td>\n",
       "      <td>179.1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1141.8</td>\n",
       "      <td>0.46</td>\n",
       "      <td>0.42</td>\n",
       "      <td>1.61</td>\n",
       "      <td>1.74</td>\n",
       "      <td>3.84</td>\n",
       "      <td>1.1</td>\n",
       "      <td>2.0</td>\n",
       "      <td>163.3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1141.8</td>\n",
       "      <td>0.46</td>\n",
       "      <td>0.42</td>\n",
       "      <td>1.61</td>\n",
       "      <td>1.74</td>\n",
       "      <td>3.84</td>\n",
       "      <td>1.1</td>\n",
       "      <td>5.0</td>\n",
       "      <td>146.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1141.8</td>\n",
       "      <td>0.46</td>\n",
       "      <td>0.42</td>\n",
       "      <td>1.61</td>\n",
       "      <td>1.74</td>\n",
       "      <td>3.84</td>\n",
       "      <td>1.1</td>\n",
       "      <td>10.0</td>\n",
       "      <td>137.8</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     比表面积  总孔体积  微孔体积  平均孔径  氮掺杂量at  氧掺杂量  ID/IG  电流密度    比电容\n",
       "0  1141.8  0.46  0.42  1.61    1.74  3.84    1.1   0.5  206.5\n",
       "1  1141.8  0.46  0.42  1.61    1.74  3.84    1.1   1.0  179.1\n",
       "2  1141.8  0.46  0.42  1.61    1.74  3.84    1.1   2.0  163.3\n",
       "3  1141.8  0.46  0.42  1.61    1.74  3.84    1.1   5.0  146.0\n",
       "4  1141.8  0.46  0.42  1.61    1.74  3.84    1.1  10.0  137.8"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = pd.read_excel('./data/20240617/电容性能新.xlsx')\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "24f58281-9f13-49ef-b44d-81d0644d6976",
   "metadata": {},
   "outputs": [],
   "source": [
    "out_cols = ['比电容']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "92d5da6b-f714-4a78-9aa7-7cf9dff1d0a0",
   "metadata": {},
   "outputs": [],
   "source": [
    "feature_cols = [x for x in data.columns if x not in out_cols]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e4946bd7-ae94-4981-82ed-66e2b496e035",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_data = data.reset_index(drop=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "4109685a-4d5b-4c63-b4e2-eb9db3989d02",
   "metadata": {},
   "outputs": [],
   "source": [
    "import xgboost as xgb\n",
    "from sklearn.metrics import mean_absolute_error, mean_squared_error, mean_absolute_percentage_error, r2_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "a140942f-4206-49e5-a51b-932c55170436",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义超参数的搜索空间\n",
    "space = {\n",
    "    'eta': hp.loguniform('eta', -5, 0),  # 学习率，搜索范围是 [1e-5, 1]\n",
    "    'max_depth': hp.choice('max_depth', range(5, 30)),  # 树的最大深度，搜索范围是 [1, 10]\n",
    "    'min_child_weight': hp.uniform('min_child_weight', 0, 10),  # 子节点最小的权重和\n",
    "    'gamma': hp.loguniform('gamma', -5, 0),  # 叶子节点分裂所需的最小损失减少\n",
    "    'subsample': hp.uniform('subsample', 0.5, 1),  # 训练集的采样率\n",
    "    'colsample_bytree': hp.uniform('colsample_bytree', 0.5, 1),  # 特征的采样率\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "7dd2dc64-0e80-4504-b84a-1d549f2cf90d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 划分训练集和测试集\n",
    "X_train, X_test, y_train, y_test = train_test_split(train_data[feature_cols], \n",
    "                                                    train_data[out_cols], \n",
    "                                                    test_size=0.3, random_state=42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "68669fde-52ab-4e62-8efc-b60dcf13734b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义目标函数，用于评估模型的性能\n",
    "def objective(params):\n",
    "    # 创建决策树分类器实例\n",
    "    gbr = xgb.XGBRegressor(**params)\n",
    "    # 训练模型\n",
    "    gbr.fit(X_train, y_train)\n",
    "    # 使用模型进行预测\n",
    "    y_pred = gbr.predict(X_test)\n",
    "    mae = mean_absolute_error(y_test, y_pred)\n",
    "    return {'loss': mae, 'status': STATUS_OK}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e89097ea-fee2-4298-81a2-ff528688857e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100%|██████████| 100/100 [00:08<00:00, 11.55trial/s, best loss: 12.132344347686164]\n"
     ]
    }
   ],
   "source": [
    "# 创建 Trials 对象来记录搜索历史\n",
    "trials = Trials()\n",
    "\n",
    "# 使用 fmin 函数进行超参数优化\n",
    "best_params = fmin(fn=objective, space=space, algo=tpe.suggest, max_evals=100, trials=trials)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "0ccfb873-6f5a-4606-9b17-a63cdbcf8acc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'colsample_bytree': 0.8857035476046763, 'eta': 0.11588664776521924, 'gamma': 0.007847746718601799, 'max_depth': 10, 'min_child_weight': 6.396614191886977, 'subsample': 0.7070880429614513}\n"
     ]
    }
   ],
   "source": [
    "print(best_params)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2bbdcd34-16c1-43ba-b249-6c7d54db8ac2",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import KFold, train_test_split\n",
    "kf = KFold(n_splits=10, shuffle=True, random_state=42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "94af2a3a-6f61-46bf-8cd4-2b7e0da8b2c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "num_boost_round = 1000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "f17eadb3-4767-4eca-bbed-880bf9cbb7a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "5bfcc8aa-f13c-4a7d-9d15-b79087e11017",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams[\"font.sans-serif\"] = [\"SimHei\"]  # 设置字体\n",
    "plt.rcParams[\"axes.unicode_minus\"] = False  # 正常显示负号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "db4dbc2d-534e-4a7e-b45c-ea25ab269502",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MSE: 164.2816, RMSE: 12.8172, MAE: 9.1819, MAPE: 4.33 %, R_2: 0.9534\n",
      "MSE: 172.8146, RMSE: 13.1459, MAE: 8.4597, MAPE: 4.24 %, R_2: 0.9475\n",
      "MSE: 105.637, RMSE: 10.278, MAE: 7.1138, MAPE: 3.19 %, R_2: 0.9736\n",
      "MSE: 306.2548, RMSE: 17.5001, MAE: 10.3353, MAPE: 4.27 %, R_2: 0.9348\n",
      "MSE: 212.1827, RMSE: 14.5665, MAE: 10.452, MAPE: 4.64 %, R_2: 0.9467\n",
      "MSE: 311.2193, RMSE: 17.6414, MAE: 10.62, MAPE: 3.97 %, R_2: 0.929\n",
      "MSE: 479.0079, RMSE: 21.8862, MAE: 11.6752, MAPE: 5.11 %, R_2: 0.8952\n",
      "MSE: 153.6563, RMSE: 12.3958, MAE: 8.8708, MAPE: 4.44 %, R_2: 0.9502\n",
      "MSE: 285.905, RMSE: 16.9087, MAE: 10.4152, MAPE: 5.35 %, R_2: 0.9522\n",
      "MSE: 570.9538, RMSE: 23.8946, MAE: 12.4216, MAPE: 5.98 %, R_2: 0.8954\n"
     ]
    }
   ],
   "source": [
    "eva_list = list()\n",
    "eva_cols = ['MSE', 'RMSE', 'MAE', 'MAPE', 'R2']\n",
    "for (train_index, test_index) in kf.split(train_data):\n",
    "    train = train_data.loc[train_index]\n",
    "    valid = train_data.loc[test_index]\n",
    "    X_train, Y_train = train[feature_cols], train[out_cols]\n",
    "    X_valid, Y_valid = valid[feature_cols], valid[out_cols]\n",
    "    dtrain = xgb.DMatrix(X_train, Y_train)\n",
    "    dvalid = xgb.DMatrix(X_valid, Y_valid)\n",
    "    watchlist = [(dvalid, 'eval')]\n",
    "    gb_model = xgb.train(best_params, dtrain, num_boost_round, evals=watchlist,\n",
    "                    early_stopping_rounds=100, verbose_eval=False)\n",
    "    y_pred = gb_model.predict(xgb.DMatrix(X_valid))\n",
    "    y_true = Y_valid.values\n",
    "    MSE = mean_squared_error(y_true, y_pred)\n",
    "    RMSE = np.sqrt(mean_squared_error(y_true, y_pred))\n",
    "    MAE = mean_absolute_error(y_true, y_pred)\n",
    "    MAPE = mean_absolute_percentage_error(y_true, y_pred)\n",
    "    R_2 = r2_score(y_true, y_pred)\n",
    "    print('MSE:', round(MSE, 4), end=', ')\n",
    "    print('RMSE:', round(RMSE, 4), end=', ')\n",
    "    print('MAE:', round(MAE, 4), end=', ')\n",
    "    print('MAPE:', round(MAPE*100, 2), '%', end=', ')\n",
    "    print('R_2:', round(R_2, 4))  #R方为负就说明拟合效果比平均值差\n",
    "    eva_list.append([MSE, RMSE, MAE, MAPE, R_2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "844d8b9f-a820-4d59-85f5-df434ca3da8d",
   "metadata": {},
   "outputs": [],
   "source": [
    "eva_df = pd.DataFrame.from_records(eva_list, columns=eva_cols)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "6c7c4910-81a2-4703-948a-152ccc7b859d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MSE     276.191297\n",
       "RMSE     16.103459\n",
       "MAE       9.954548\n",
       "MAPE      0.045525\n",
       "R2        0.937810\n",
       "dtype: float64"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eva_df.mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "0beadfa6-eef9-47fd-adb7-8ed245fa942d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 144976 characters]",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(12, 8))\n",
    "plt.plot(range(len(y_true)), y_true, 'o-', label='real')\n",
    "plt.plot(range(len(y_pred)), y_pred, '*-', label='pred')\n",
    "plt.legend(loc='best')\n",
    "plt.title(f'{out_cols}')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b69f612e-3548-41d6-9512-7591c47ca50e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
