From ba1129064d75f95dd9d87cf02616d7fa515ce85a Mon Sep 17 00:00:00 2001
From: benjas <909336740@qq.com>
Date: Mon, 30 Nov 2020 22:07:22 +0800
Subject: [PATCH] =?UTF-8?q?Add=20=E5=B7=A5=E4=B8=9A=E5=8C=96=E5=B7=A5?=
=?UTF-8?q?=E7=94=9F=E4=BA=A7=E9=A2=84=E6=B5=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../工业生产预测-checkpoint.ipynb | 3137 +++++++++++++++++
.../assets/20201130145942327.png | Bin 0 -> 296286 bytes
.../jinnan_round1_testA_20181227.csv | 151 +
.../jinnan_round1_testB_20190121.csv | 150 +
.../jinnan_round1_train_20181227.csv | 1397 ++++++++
.../工业生产预测.ipynb | 3137 +++++++++++++++++
6 files changed, 7972 insertions(+)
create mode 100644 机器学习竞赛实战_优胜解决方案/工业生产预测/.ipynb_checkpoints/工业生产预测-checkpoint.ipynb
create mode 100644 机器学习竞赛实战_优胜解决方案/工业生产预测/assets/20201130145942327.png
create mode 100644 机器学习竞赛实战_优胜解决方案/工业生产预测/jinnan_round1_testA_20181227.csv
create mode 100644 机器学习竞赛实战_优胜解决方案/工业生产预测/jinnan_round1_testB_20190121.csv
create mode 100644 机器学习竞赛实战_优胜解决方案/工业生产预测/jinnan_round1_train_20181227.csv
create mode 100644 机器学习竞赛实战_优胜解决方案/工业生产预测/工业生产预测.ipynb
diff --git a/机器学习竞赛实战_优胜解决方案/工业生产预测/.ipynb_checkpoints/工业生产预测-checkpoint.ipynb b/机器学习竞赛实战_优胜解决方案/工业生产预测/.ipynb_checkpoints/工业生产预测-checkpoint.ipynb
new file mode 100644
index 0000000..de8a0a6
--- /dev/null
+++ b/机器学习竞赛实战_优胜解决方案/工业生产预测/.ipynb_checkpoints/工业生产预测-checkpoint.ipynb
@@ -0,0 +1,3137 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 任务目标:利用异烟酸生产过程中的各参数,预测最终异烟酸的收率\n",
+ "
\n",
+ " - 数据集包括工程中10各步骤的参数,样本id、A1-A28、B1-B14包括原料、辅料、时间、温度、压强以及收率。\n",
+ "
- 冠军ATCG解决方案\n",
+ "
\n",
+ "\n",
+ "**预测具体的值:回归任务**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 数据处理"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import warnings\n",
+ "import xgboost as xgb\n",
+ "from sklearn.model_selection import KFold\n",
+ "from sklearn.metrics import mean_squared_error as mse\n",
+ "\n",
+ "warnings.simplefilter('ignore')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\"\"\"导入数据集\"\"\"\n",
+ "df_trn = pd.read_csv('jinnan_round1_train_20181227.csv', encoding='GB2312') # encoding进行编码\n",
+ "df_tst_a = pd.read_csv('jinnan_round1_testA_20181227.csv', encoding='GB2312')\n",
+ "df_tst_b = pd.read_csv('jinnan_round1_testB_20190121.csv', encoding='GB2312') "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " 样本id | \n",
+ " A1 | \n",
+ " A2 | \n",
+ " A3 | \n",
+ " A4 | \n",
+ " A5 | \n",
+ " A6 | \n",
+ " A7 | \n",
+ " A8 | \n",
+ " A9 | \n",
+ " ... | \n",
+ " B6 | \n",
+ " B7 | \n",
+ " B8 | \n",
+ " B9 | \n",
+ " B10 | \n",
+ " B11 | \n",
+ " B12 | \n",
+ " B13 | \n",
+ " B14 | \n",
+ " 收率 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " sample_1528 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 13:30:00 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 15:30:00 | \n",
+ " ... | \n",
+ " 65 | \n",
+ " 11:30:00 | \n",
+ " 45.0 | \n",
+ " 11:30-13:00 | \n",
+ " 14:00-15:30 | \n",
+ " NaN | \n",
+ " 800.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ " 0.879 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " sample_1698 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 14:00:00 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 16:00:00 | \n",
+ " ... | \n",
+ " 80 | \n",
+ " 6:00:00 | \n",
+ " 45.0 | \n",
+ " 6:00-7:30 | \n",
+ " 7:30-9:00 | \n",
+ " 9:00-10:00 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ " 0.902 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " sample_639 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 14:00:00 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 16:00:00 | \n",
+ " ... | \n",
+ " 80 | \n",
+ " 1:00:00 | \n",
+ " 45.0 | \n",
+ " 1:00-2:30 | \n",
+ " 2:30-4:00 | \n",
+ " 4:00-5:00 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ " 0.936 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " sample_483 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 1:30:00 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 3:00:00 | \n",
+ " ... | \n",
+ " 65 | \n",
+ " 18:00:00 | \n",
+ " 45.0 | \n",
+ " 19:00-20:30 | \n",
+ " 21:30-23:00 | \n",
+ " NaN | \n",
+ " 800.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ " 0.902 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " sample_617 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 22:00:00 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 0:00:00 | \n",
+ " ... | \n",
+ " 80 | \n",
+ " 9:00:00 | \n",
+ " 45.0 | \n",
+ " 9:00-10:30 | \n",
+ " 10:30-12:00 | \n",
+ " 12:00-13:00 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 420 | \n",
+ " 0.983 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 44 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 样本id A1 A2 A3 A4 A5 A6 A7 A8 A9 ... \\\n",
+ "0 sample_1528 300 NaN 405.0 700 13:30:00 38.0 NaN NaN 15:30:00 ... \n",
+ "1 sample_1698 300 NaN 405.0 700 14:00:00 29.0 NaN NaN 16:00:00 ... \n",
+ "2 sample_639 300 NaN 405.0 700 14:00:00 29.0 NaN NaN 16:00:00 ... \n",
+ "3 sample_483 300 NaN 405.0 700 1:30:00 38.0 NaN NaN 3:00:00 ... \n",
+ "4 sample_617 300 NaN 405.0 700 22:00:00 29.0 NaN NaN 0:00:00 ... \n",
+ "\n",
+ " B6 B7 B8 B9 B10 B11 B12 B13 \\\n",
+ "0 65 11:30:00 45.0 11:30-13:00 14:00-15:30 NaN 800.0 0.15 \n",
+ "1 80 6:00:00 45.0 6:00-7:30 7:30-9:00 9:00-10:00 1200.0 0.15 \n",
+ "2 80 1:00:00 45.0 1:00-2:30 2:30-4:00 4:00-5:00 1200.0 0.15 \n",
+ "3 65 18:00:00 45.0 19:00-20:30 21:30-23:00 NaN 800.0 0.15 \n",
+ "4 80 9:00:00 45.0 9:00-10:30 10:30-12:00 12:00-13:00 1200.0 0.15 \n",
+ "\n",
+ " B14 收率 \n",
+ "0 400 0.879 \n",
+ "1 400 0.902 \n",
+ "2 400 0.936 \n",
+ "3 400 0.902 \n",
+ "4 420 0.983 \n",
+ "\n",
+ "[5 rows x 44 columns]"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 观察数据\n",
+ "df_trn.head() # 可以发现A2、A7等有NaN缺失值"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "RangeIndex: 1396 entries, 0 to 1395\n",
+ "Data columns (total 44 columns):\n",
+ "样本id 1396 non-null object\n",
+ "A1 1396 non-null int64\n",
+ "A2 42 non-null float64\n",
+ "A3 1354 non-null float64\n",
+ "A4 1396 non-null int64\n",
+ "A5 1396 non-null object\n",
+ "A6 1396 non-null float64\n",
+ "A7 149 non-null object\n",
+ "A8 149 non-null float64\n",
+ "A9 1396 non-null object\n",
+ "A10 1396 non-null int64\n",
+ "A11 1396 non-null object\n",
+ "A12 1396 non-null int64\n",
+ "A13 1396 non-null float64\n",
+ "A14 1396 non-null object\n",
+ "A15 1396 non-null float64\n",
+ "A16 1396 non-null object\n",
+ "A17 1396 non-null float64\n",
+ "A18 1396 non-null float64\n",
+ "A19 1396 non-null int64\n",
+ "A20 1396 non-null object\n",
+ "A21 1393 non-null float64\n",
+ "A22 1396 non-null float64\n",
+ "A23 1393 non-null float64\n",
+ "A24 1395 non-null object\n",
+ "A25 1396 non-null object\n",
+ "A26 1394 non-null object\n",
+ "A27 1396 non-null int64\n",
+ "A28 1396 non-null object\n",
+ "B1 1386 non-null float64\n",
+ "B2 1394 non-null float64\n",
+ "B3 1394 non-null float64\n",
+ "B4 1396 non-null object\n",
+ "B5 1395 non-null object\n",
+ "B6 1396 non-null int64\n",
+ "B7 1396 non-null object\n",
+ "B8 1395 non-null float64\n",
+ "B9 1396 non-null object\n",
+ "B10 1152 non-null object\n",
+ "B11 547 non-null object\n",
+ "B12 1395 non-null float64\n",
+ "B13 1395 non-null float64\n",
+ "B14 1396 non-null int64\n",
+ "收率 1396 non-null float64\n",
+ "dtypes: float64(18), int64(8), object(18)\n",
+ "memory usage: 480.0+ KB\n"
+ ]
+ }
+ ],
+ "source": [
+ "df_trn.info()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "我们需要解决一些异常值,如某值相对其它值过大的离群点"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def train_abnormal_revise(data):\n",
+ " df_trn = data.copy() # 复制一份数据,不改变原数据\n",
+ " df_trn.loc[(df_trn['A1'] == 200) & (df_trn['A3'] == 405), 'A1'] = 300\n",
+ " # A5会发现三个不合法值,比如1900/1/21 0:00可能要表达的是21:00:00,我们替换掉\n",
+ " df_trn['A5'] = df_trn['A5'].replace('1900/1/21 0:00', '21:00:00')\n",
+ " df_trn['A5'] = df_trn['A5'].replace('1900/1/29 0:00', '14:00:00')\n",
+ " df_trn['A9'] = df_trn['A9'].replace('1900/1/9 7:00', '23:00:00')\n",
+ " # A9有两个不合法值\n",
+ " df_trn['A9'] = df_trn['A9'].replace('1900/1/9 7:00', '23:00:00')\n",
+ " df_trn['A9'] = df_trn['A9'].replace('700', '7:00:00')\n",
+ " # A11有一个不合法值\n",
+ " df_trn['A11'] = df_trn['A11'].replace('1900/1/1 2:30', '2:30:00')\n",
+ " df_trn['A11'] = df_trn['A11'].replace(':30:00', '00:30:00')\n",
+ " df_trn['A16'] = df_trn['A16'].replace('1900/1/12 0:00', '12:00:00')\n",
+ " df_trn['A20'] = df_trn['A20'].replace('6:00-6:30分', '6:00-6:30')\n",
+ " df_trn['A20'] = df_trn['A20'].replace('18:30-15:00', '18:30-19:00')\n",
+ " # A22有个不合法值\n",
+ " df_trn['A22'] = df_trn['A22'].replace(3.5, np.nan)\n",
+ " df_trn['A25'] = df_trn['A25'].replace('1900/3/10 0:00', 70).astype(int)\n",
+ " df_trn['A26'] = df_trn['A26'].replace('1900/3/13 0:00', '13:00:00')\n",
+ " df_trn['B1'] = df_trn['B1'].replace(3.5, np.nan)\n",
+ " df_trn['B4'] = df_trn['B4'].replace('15:00-1600', '15:00-16:00')\n",
+ " df_trn['B4'] = df_trn['B4'].replace('18:00-17:00', '16:00-17:00')\n",
+ " df_trn['B4'] = df_trn['B4'].replace('19:-20:05', '19:05-20:05')\n",
+ " df_trn['B9'] = df_trn['B9'].replace('23:00-7:30', '23:00-00:30')\n",
+ " df_trn['B14'] = df_trn['B14'].replace(40, 400)\n",
+ " return df_trn\n",
+ "\n",
+ "\n",
+ "def test_a_abnormal_revise(data):\n",
+ " df_tst = data.copy()\n",
+ " df_tst['A5'] = df_tst['A5'].replace('1900/1/22 0:00', '22:00:00')\n",
+ " df_tst['A7'] = df_tst['A7'].replace('0:50:00', '21:50:00')\n",
+ " df_tst['B14'] = df_tst['B14'].replace(785, 385)\n",
+ " return df_tst\n",
+ "\n",
+ "\n",
+ "def train_abnormal_adjust(data):\n",
+ " df_trn = data.copy()\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1894', 'A5'] = '14:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1234', 'A9'] = '0:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1020', 'A9'] = '18:30:00'\n",
+ "\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1380', 'A11'] = '15:30:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_844', 'A11'] = '10:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1348', 'A11'] = '17:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_25', 'A11'] = '00:30:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1105', 'A11'] = '4:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_313', 'A11'] = '15:30:00'\n",
+ "\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_291', 'A14'] = '19:30:00'\n",
+ "\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1398', 'A16'] = '11:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1177', 'A20'] = '19:00-20:00'\n",
+ "\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_71', 'A20'] = '16:20-16:50'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_14', 'A20'] = '18:00-18:30'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_69', 'A20'] = '6:10-6:50'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1500', 'A20'] = '23:00-23:30'\n",
+ "\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1524', 'A24'] = '15:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1524', 'A26'] = '15:30:00'\n",
+ "\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1046', 'A28'] = '18:00-18:30'\n",
+ "\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1230', 'B5'] = '17:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_97', 'B7'] = '1:00:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_752', 'B9'] = '11:00-14:00'\n",
+ "\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_609', 'B11'] = '11:00-12:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_643', 'B11'] = '12:00-13:00'\n",
+ " df_trn.loc[df_trn['样本id'] == 'sample_1164', 'B11'] = '5:00-6:00'\n",
+ " return df_trn\n",
+ "\n",
+ "\n",
+ "def test_a_abnormal_adjust(data):\n",
+ " df_tst = data.copy()\n",
+ " df_tst.loc[df_tst['样本id'] == 'sample_919', 'A9'] = '19:50:00'\n",
+ " return df_tst\n",
+ "\n",
+ "\n",
+ "def test_b_abnormal_adjust(data):\n",
+ " df_tst = data.copy()\n",
+ " df_tst.loc[df_tst['样本id'] == 'sample_566', 'A5'] = '18:00:00'\n",
+ " df_tst.loc[df_tst['样本id'] == 'sample_40', 'A20'] = '5:00-5:30'\n",
+ " df_tst.loc[df_tst['样本id'] == 'sample_531', 'B5'] = '1:00'\n",
+ " return df_tst"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_trn = train_abnormal_revise(df_trn).pipe(train_abnormal_adjust)\n",
+ "df_tst_a = test_a_abnormal_revise(df_tst_a).pipe(test_a_abnormal_adjust)\n",
+ "df_tst_b = test_b_abnormal_adjust(df_tst_b)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### 标签与数据集整合"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_trn, df_tst = df_trn.copy(), df_tst_a.copy()\n",
+ "df_target = df_trn['收率'] # 获取数据标签\n",
+ "del df_trn['收率'] # 删除掉训练集的标签,即是训练数据\n",
+ "df_trn_tst = df_trn.append(df_tst, ignore_index=False).reset_index(\n",
+ " drop=True) # 把test合并一起,同时做操作"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for _df in [df_trn, df_tst, df_trn_tst]:\n",
+ " _df['A3'] = _df['A3'].fillna(405) # A3有缺失值,用众数填充"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### 时间段特征处理 "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 所有时间相关列\n",
+ "cols_timer = ['A5', 'A7', 'A9', 'A11', 'A14', 'A16', 'A24', 'A26', 'B5', 'B7']\n",
+ "# 同时对训练和测试集进行相同处理\n",
+ "for _df in [df_trn_tst, df_trn, df_tst]:\n",
+ " # 添加列名标记\n",
+ " _df.rename(columns={_col: _col + '_t' for _col in cols_timer},\n",
+ " inplace=True)\n",
+ " # 遍历所有持续时间相关列例如21:00-21:30\n",
+ " for _col in ['A20', 'A28', 'B4', 'B9', 'B10', 'B11']:\n",
+ " # 取到当前列的索引\n",
+ " _idx_col = _df.columns.tolist().index(_col)\n",
+ " # 添加新的一列,表示起始时间,split表示分别取开始和结束时间,用索引来指定\n",
+ " _df.insert(_idx_col + 1, _col + '_at',\n",
+ " _df[_col].str.split('-').str[0])\n",
+ " # 添加新的一列,表示终止时间\n",
+ " _df.insert(_idx_col + 2, _col + '_bt',\n",
+ " _df[_col].str.split('-').str[1])\n",
+ " # 删除持续时间\n",
+ " del _df[_col]\n",
+ " cols_timer = cols_timer + [_col + '_at', _col + '_bt']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " 样本id | \n",
+ " A1 | \n",
+ " A2 | \n",
+ " A3 | \n",
+ " A4 | \n",
+ " A5_t | \n",
+ " A6 | \n",
+ " A7_t | \n",
+ " A8 | \n",
+ " A9_t | \n",
+ " ... | \n",
+ " B8 | \n",
+ " B9_at | \n",
+ " B9_bt | \n",
+ " B10_at | \n",
+ " B10_bt | \n",
+ " B11_at | \n",
+ " B11_bt | \n",
+ " B12 | \n",
+ " B13 | \n",
+ " B14 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " sample_1528 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 13:30:00 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 15:30:00 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 11:30 | \n",
+ " 13:00 | \n",
+ " 14:00 | \n",
+ " 15:30 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 800.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " sample_1698 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 14:00:00 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 16:00:00 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 6:00 | \n",
+ " 7:30 | \n",
+ " 7:30 | \n",
+ " 9:00 | \n",
+ " 9:00 | \n",
+ " 10:00 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " sample_639 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 14:00:00 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 16:00:00 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 1:00 | \n",
+ " 2:30 | \n",
+ " 2:30 | \n",
+ " 4:00 | \n",
+ " 4:00 | \n",
+ " 5:00 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " sample_483 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 1:30:00 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 3:00:00 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 19:00 | \n",
+ " 20:30 | \n",
+ " 21:30 | \n",
+ " 23:00 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 800.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " sample_617 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 22:00:00 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 0:00:00 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 9:00 | \n",
+ " 10:30 | \n",
+ " 10:30 | \n",
+ " 12:00 | \n",
+ " 12:00 | \n",
+ " 13:00 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 420 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 49 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 样本id A1 A2 A3 A4 A5_t A6 A7_t A8 A9_t ... \\\n",
+ "0 sample_1528 300 NaN 405.0 700 13:30:00 38.0 NaN NaN 15:30:00 ... \n",
+ "1 sample_1698 300 NaN 405.0 700 14:00:00 29.0 NaN NaN 16:00:00 ... \n",
+ "2 sample_639 300 NaN 405.0 700 14:00:00 29.0 NaN NaN 16:00:00 ... \n",
+ "3 sample_483 300 NaN 405.0 700 1:30:00 38.0 NaN NaN 3:00:00 ... \n",
+ "4 sample_617 300 NaN 405.0 700 22:00:00 29.0 NaN NaN 0:00:00 ... \n",
+ "\n",
+ " B8 B9_at B9_bt B10_at B10_bt B11_at B11_bt B12 B13 B14 \n",
+ "0 45.0 11:30 13:00 14:00 15:30 NaN NaN 800.0 0.15 400 \n",
+ "1 45.0 6:00 7:30 7:30 9:00 9:00 10:00 1200.0 0.15 400 \n",
+ "2 45.0 1:00 2:30 2:30 4:00 4:00 5:00 1200.0 0.15 400 \n",
+ "3 45.0 19:00 20:30 21:30 23:00 NaN NaN 800.0 0.15 400 \n",
+ "4 45.0 9:00 10:30 10:30 12:00 12:00 13:00 1200.0 0.15 420 \n",
+ "\n",
+ "[5 rows x 49 columns]"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_trn_tst.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "cols_timer = list(filter(lambda x: x.endswith('t'), df_trn_tst.columns))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['A5_t',\n",
+ " 'A7_t',\n",
+ " 'A9_t',\n",
+ " 'A11_t',\n",
+ " 'A14_t',\n",
+ " 'A16_t',\n",
+ " 'A20_at',\n",
+ " 'A20_bt',\n",
+ " 'A24_t',\n",
+ " 'A26_t',\n",
+ " 'A28_at',\n",
+ " 'A28_bt',\n",
+ " 'B4_at',\n",
+ " 'B4_bt',\n",
+ " 'B5_t',\n",
+ " 'B7_t',\n",
+ " 'B9_at',\n",
+ " 'B9_bt',\n",
+ " 'B10_at',\n",
+ " 'B10_bt',\n",
+ " 'B11_at',\n",
+ " 'B11_bt']"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cols_timer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def time_to_min(x):\n",
+ " # 将时间全部转换成分钟形式\n",
+ " if x is np.nan:\n",
+ " return np.nan\n",
+ " else:\n",
+ " x = x.replace(';', ':').replace(';', ':')\n",
+ " x = x.replace('::', ':').replace('\"', ':')\n",
+ " h, m = x.split(':')[:2]\n",
+ " h = 0 if not h else h\n",
+ " m = 0 if not m else m\n",
+ " return int(h)*60 + int(m)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for _df in [df_trn_tst, df_trn, df_tst]:\n",
+ " for _col in cols_timer:\n",
+ " _df[_col] = _df[_col].map(time_to_min)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " 样本id | \n",
+ " A1 | \n",
+ " A2 | \n",
+ " A3 | \n",
+ " A4 | \n",
+ " A5_t | \n",
+ " A6 | \n",
+ " A7_t | \n",
+ " A8 | \n",
+ " A9_t | \n",
+ " ... | \n",
+ " B8 | \n",
+ " B9_at | \n",
+ " B9_bt | \n",
+ " B10_at | \n",
+ " B10_bt | \n",
+ " B11_at | \n",
+ " B11_bt | \n",
+ " B12 | \n",
+ " B13 | \n",
+ " B14 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " sample_1528 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 810 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 930 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 690 | \n",
+ " 780 | \n",
+ " 840.0 | \n",
+ " 930.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 800.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " sample_1698 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 840 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 960 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 360 | \n",
+ " 450 | \n",
+ " 450.0 | \n",
+ " 540.0 | \n",
+ " 540.0 | \n",
+ " 600.0 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " sample_639 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 840 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 960 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 60 | \n",
+ " 150 | \n",
+ " 150.0 | \n",
+ " 240.0 | \n",
+ " 240.0 | \n",
+ " 300.0 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " sample_483 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 90 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 180 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 1140 | \n",
+ " 1230 | \n",
+ " 1290.0 | \n",
+ " 1380.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 800.0 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " sample_617 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 1320 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 0 | \n",
+ " ... | \n",
+ " 45.0 | \n",
+ " 540 | \n",
+ " 630 | \n",
+ " 630.0 | \n",
+ " 720.0 | \n",
+ " 720.0 | \n",
+ " 780.0 | \n",
+ " 1200.0 | \n",
+ " 0.15 | \n",
+ " 420 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 49 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 样本id A1 A2 A3 A4 A5_t A6 A7_t A8 A9_t ... B8 \\\n",
+ "0 sample_1528 300 NaN 405.0 700 810 38.0 NaN NaN 930 ... 45.0 \n",
+ "1 sample_1698 300 NaN 405.0 700 840 29.0 NaN NaN 960 ... 45.0 \n",
+ "2 sample_639 300 NaN 405.0 700 840 29.0 NaN NaN 960 ... 45.0 \n",
+ "3 sample_483 300 NaN 405.0 700 90 38.0 NaN NaN 180 ... 45.0 \n",
+ "4 sample_617 300 NaN 405.0 700 1320 29.0 NaN NaN 0 ... 45.0 \n",
+ "\n",
+ " B9_at B9_bt B10_at B10_bt B11_at B11_bt B12 B13 B14 \n",
+ "0 690 780 840.0 930.0 NaN NaN 800.0 0.15 400 \n",
+ "1 360 450 450.0 540.0 540.0 600.0 1200.0 0.15 400 \n",
+ "2 60 150 150.0 240.0 240.0 300.0 1200.0 0.15 400 \n",
+ "3 1140 1230 1290.0 1380.0 NaN NaN 800.0 0.15 400 \n",
+ "4 540 630 630.0 720.0 720.0 780.0 1200.0 0.15 420 \n",
+ "\n",
+ "[5 rows x 49 columns]"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_trn_tst.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 创建一个df来准备添加很多特征"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " 样本id | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " sample_1528 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " sample_1698 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " sample_639 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " sample_483 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " sample_617 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 样本id\n",
+ "0 sample_1528\n",
+ "1 sample_1698\n",
+ "2 sample_639\n",
+ "3 sample_483\n",
+ "4 sample_617"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "raw = df_trn_tst.copy()\n",
+ "df = pd.DataFrame(raw['样本id'])\n",
+ "df.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### 温度相关特征"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 加热过程\n",
+ "df['P1_S1_A6_0C'] = raw['A6'] # 容器初始温度\n",
+ "df['P1_S2_A8_1C'] = raw['A8'] # 首次测温温度\n",
+ "df['P1_S3_A10_2C'] = raw['A10'] # 准备水解温度\n",
+ "df['P1_C1_C0_D'] = raw['A8'] - raw['A6'] # 测温温差\n",
+ "df['P1_C2_C0_D'] = raw['A10'] - raw['A6'] # 初次沸腾温差\n",
+ "\n",
+ "# 水解过程\n",
+ "df['P2_S1_A12_3C'] = raw['A12'] # 水解开始温度\n",
+ "df['P2_S2_A15_4C'] = raw['A15'] # 水解过程测温温度\n",
+ "df['P2_S3_A17_5C'] = raw['A17'] # 水解结束温度\n",
+ "df['P2_C3_C0_D'] = raw['A12'] - raw['A6'] # 水解开始与初始温度温差\n",
+ "df['P2_C3_C2_D'] = raw['A12'] - raw['A10'] # 水解开始前恒温温差\n",
+ "df['P2_C4_C3_D'] = raw['A15'] - raw['A12'] # 水解过程中途温差\n",
+ "df['P2_C5_C4_D'] = raw['A17'] - raw['A15'] # 水解结束中途温差\n",
+ "df['P2_C5_C3_KD'] = raw['A17'] - raw['A12'] # 水解起止温差\n",
+ "\n",
+ "# 脱色过程\n",
+ "df['P3_S2_A25_7C'] = raw['A25'] # 脱色保温开始温度\n",
+ "df['P3_S3_A27_8C'] = raw['A27'] # 脱色保温结束温度\n",
+ "df['P3_C7_C5_D'] = raw['A25'] - raw['A17'] # 降温温差\n",
+ "df['P3_C8_C7_KD'] = raw['A27'] - raw['A25'] # 保温温差\n",
+ "\n",
+ "# 结晶过程\n",
+ "df['P4_S2_B6_11C'] = raw['B6'] # 结晶开始温度\n",
+ "df['P4_S3_B8_12C'] = raw['B8'] # 结晶结束温度\n",
+ "df['P4_C11_C8_D'] = raw['B6'] - raw['A27'] # 脱色结束到结晶温差\n",
+ "df['P4_C12_C11_KD'] = raw['B8'] - raw['B6'] # 结晶温差"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### 温度相关统计特征"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "_funcs = ['mean', 'std', 'sum']\n",
+ "# 遍历每一种统计指标\n",
+ "for _func in _funcs:\n",
+ " # 对每一个样本计算各项指标\n",
+ " df[f'P2_C2-C5_{_func}'] = raw[['A10', 'A12', 'A15', 'A17']].\\\n",
+ " agg(_func, axis=1) # 沸腾过程温度\n",
+ " df[f'P2_D3-D5_{_func}'] = \\\n",
+ " df[[f'P2_C{i}_C{i-1}_D' for i in range(3, 6)]].\\\n",
+ " abs().agg(_func, axis=1) # 沸腾过程绝对温差\n",
+ " df[f'P2_C1-C12_KD_ABS_{_func}'] = \\\n",
+ " df[[_f for _f in df.columns if _f.endswith('KD')]].\\\n",
+ " abs().agg(_func, axis=1) # 关键过程绝对温差\n",
+ " df[f'P2_C1-C12_D_{_func}'] = \\\n",
+ " df[[_f for _f in df.columns if _f.endswith('D')]].\\\n",
+ " abs().agg(_func, axis=1) # 所有过程绝对温差\n",
+ " df[f'P2_LARGE_KD_{_func}'] = \\\n",
+ " df[['P2_C3_C0_D', 'P3_C7_C5_D', 'P4_C12_C11_KD']].\\\n",
+ " abs().agg(_func, axis=1) # 大温差绝对温差"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " 样本id | \n",
+ " P1_S1_A6_0C | \n",
+ " P1_S2_A8_1C | \n",
+ " P1_S3_A10_2C | \n",
+ " P1_C1_C0_D | \n",
+ " P1_C2_C0_D | \n",
+ " P2_S1_A12_3C | \n",
+ " P2_S2_A15_4C | \n",
+ " P2_S3_A17_5C | \n",
+ " P2_C3_C0_D | \n",
+ " ... | \n",
+ " P2_C2-C5_std | \n",
+ " P2_D3-D5_std | \n",
+ " P2_C1-C12_KD_ABS_std | \n",
+ " P2_C1-C12_D_std | \n",
+ " P2_LARGE_KD_std | \n",
+ " P2_C2-C5_sum | \n",
+ " P2_D3-D5_sum | \n",
+ " P2_C1-C12_KD_ABS_sum | \n",
+ " P2_C1-C12_D_sum | \n",
+ " P2_LARGE_KD_sum | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " sample_1528 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " 100 | \n",
+ " NaN | \n",
+ " 62.0 | \n",
+ " 102.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 64.0 | \n",
+ " ... | \n",
+ " 1.707825 | \n",
+ " 0.57735 | \n",
+ " 9.643651 | \n",
+ " 24.928565 | \n",
+ " 23.245071 | \n",
+ " 409.0 | \n",
+ " 4.0 | \n",
+ " 27.0 | \n",
+ " 191.0 | \n",
+ " 113.0 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " sample_1698 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " 101 | \n",
+ " NaN | \n",
+ " 72.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 105.0 | \n",
+ " 74.0 | \n",
+ " ... | \n",
+ " 1.707825 | \n",
+ " 0.57735 | \n",
+ " 17.785762 | \n",
+ " 28.887521 | \n",
+ " 25.890796 | \n",
+ " 413.0 | \n",
+ " 4.0 | \n",
+ " 44.0 | \n",
+ " 226.0 | \n",
+ " 134.0 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " sample_639 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " 102 | \n",
+ " NaN | \n",
+ " 73.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 105.0 | \n",
+ " 74.0 | \n",
+ " ... | \n",
+ " 1.290994 | \n",
+ " 0.00000 | \n",
+ " 18.009257 | \n",
+ " 29.231642 | \n",
+ " 25.514702 | \n",
+ " 414.0 | \n",
+ " 3.0 | \n",
+ " 43.0 | \n",
+ " 226.0 | \n",
+ " 135.0 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " sample_483 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " 100 | \n",
+ " NaN | \n",
+ " 62.0 | \n",
+ " 102.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 64.0 | \n",
+ " ... | \n",
+ " 1.707825 | \n",
+ " 0.57735 | \n",
+ " 9.165151 | \n",
+ " 24.617293 | \n",
+ " 22.479620 | \n",
+ " 409.0 | \n",
+ " 4.0 | \n",
+ " 30.0 | \n",
+ " 207.0 | \n",
+ " 118.0 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " sample_617 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " 101 | \n",
+ " NaN | \n",
+ " 72.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 105.0 | \n",
+ " 74.0 | \n",
+ " ... | \n",
+ " 1.707825 | \n",
+ " 0.57735 | \n",
+ " 17.785762 | \n",
+ " 28.887521 | \n",
+ " 25.890796 | \n",
+ " 413.0 | \n",
+ " 4.0 | \n",
+ " 44.0 | \n",
+ " 226.0 | \n",
+ " 134.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 37 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 样本id P1_S1_A6_0C P1_S2_A8_1C P1_S3_A10_2C P1_C1_C0_D \\\n",
+ "0 sample_1528 38.0 NaN 100 NaN \n",
+ "1 sample_1698 29.0 NaN 101 NaN \n",
+ "2 sample_639 29.0 NaN 102 NaN \n",
+ "3 sample_483 38.0 NaN 100 NaN \n",
+ "4 sample_617 29.0 NaN 101 NaN \n",
+ "\n",
+ " P1_C2_C0_D P2_S1_A12_3C P2_S2_A15_4C P2_S3_A17_5C P2_C3_C0_D ... \\\n",
+ "0 62.0 102.0 103.0 104.0 64.0 ... \n",
+ "1 72.0 103.0 104.0 105.0 74.0 ... \n",
+ "2 73.0 103.0 104.0 105.0 74.0 ... \n",
+ "3 62.0 102.0 103.0 104.0 64.0 ... \n",
+ "4 72.0 103.0 104.0 105.0 74.0 ... \n",
+ "\n",
+ " P2_C2-C5_std P2_D3-D5_std P2_C1-C12_KD_ABS_std P2_C1-C12_D_std \\\n",
+ "0 1.707825 0.57735 9.643651 24.928565 \n",
+ "1 1.707825 0.57735 17.785762 28.887521 \n",
+ "2 1.290994 0.00000 18.009257 29.231642 \n",
+ "3 1.707825 0.57735 9.165151 24.617293 \n",
+ "4 1.707825 0.57735 17.785762 28.887521 \n",
+ "\n",
+ " P2_LARGE_KD_std P2_C2-C5_sum P2_D3-D5_sum P2_C1-C12_KD_ABS_sum \\\n",
+ "0 23.245071 409.0 4.0 27.0 \n",
+ "1 25.890796 413.0 4.0 44.0 \n",
+ "2 25.514702 414.0 3.0 43.0 \n",
+ "3 22.479620 409.0 4.0 30.0 \n",
+ "4 25.890796 413.0 4.0 44.0 \n",
+ "\n",
+ " P2_C1-C12_D_sum P2_LARGE_KD_sum \n",
+ "0 191.0 113.0 \n",
+ "1 226.0 134.0 \n",
+ "2 226.0 135.0 \n",
+ "3 207.0 118.0 \n",
+ "4 226.0 134.0 \n",
+ "\n",
+ "[5 rows x 37 columns]"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_temperature = df.set_index('样本id')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " P1_S1_A6_0C | \n",
+ " P1_S2_A8_1C | \n",
+ " P1_S3_A10_2C | \n",
+ " P1_C1_C0_D | \n",
+ " P1_C2_C0_D | \n",
+ " P2_S1_A12_3C | \n",
+ " P2_S2_A15_4C | \n",
+ " P2_S3_A17_5C | \n",
+ " P2_C3_C0_D | \n",
+ " P2_C3_C2_D | \n",
+ " ... | \n",
+ " P2_C2-C5_std | \n",
+ " P2_D3-D5_std | \n",
+ " P2_C1-C12_KD_ABS_std | \n",
+ " P2_C1-C12_D_std | \n",
+ " P2_LARGE_KD_std | \n",
+ " P2_C2-C5_sum | \n",
+ " P2_D3-D5_sum | \n",
+ " P2_C1-C12_KD_ABS_sum | \n",
+ " P2_C1-C12_D_sum | \n",
+ " P2_LARGE_KD_sum | \n",
+ "
\n",
+ " \n",
+ " 样本id | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " sample_1528 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " 100 | \n",
+ " NaN | \n",
+ " 62.0 | \n",
+ " 102.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 64.0 | \n",
+ " 2.0 | \n",
+ " ... | \n",
+ " 1.707825 | \n",
+ " 0.57735 | \n",
+ " 9.643651 | \n",
+ " 24.928565 | \n",
+ " 23.245071 | \n",
+ " 409.0 | \n",
+ " 4.0 | \n",
+ " 27.0 | \n",
+ " 191.0 | \n",
+ " 113.0 | \n",
+ "
\n",
+ " \n",
+ " sample_1698 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " 101 | \n",
+ " NaN | \n",
+ " 72.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 105.0 | \n",
+ " 74.0 | \n",
+ " 2.0 | \n",
+ " ... | \n",
+ " 1.707825 | \n",
+ " 0.57735 | \n",
+ " 17.785762 | \n",
+ " 28.887521 | \n",
+ " 25.890796 | \n",
+ " 413.0 | \n",
+ " 4.0 | \n",
+ " 44.0 | \n",
+ " 226.0 | \n",
+ " 134.0 | \n",
+ "
\n",
+ " \n",
+ " sample_639 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " 102 | \n",
+ " NaN | \n",
+ " 73.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 105.0 | \n",
+ " 74.0 | \n",
+ " 1.0 | \n",
+ " ... | \n",
+ " 1.290994 | \n",
+ " 0.00000 | \n",
+ " 18.009257 | \n",
+ " 29.231642 | \n",
+ " 25.514702 | \n",
+ " 414.0 | \n",
+ " 3.0 | \n",
+ " 43.0 | \n",
+ " 226.0 | \n",
+ " 135.0 | \n",
+ "
\n",
+ " \n",
+ " sample_483 | \n",
+ " 38.0 | \n",
+ " NaN | \n",
+ " 100 | \n",
+ " NaN | \n",
+ " 62.0 | \n",
+ " 102.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 64.0 | \n",
+ " 2.0 | \n",
+ " ... | \n",
+ " 1.707825 | \n",
+ " 0.57735 | \n",
+ " 9.165151 | \n",
+ " 24.617293 | \n",
+ " 22.479620 | \n",
+ " 409.0 | \n",
+ " 4.0 | \n",
+ " 30.0 | \n",
+ " 207.0 | \n",
+ " 118.0 | \n",
+ "
\n",
+ " \n",
+ " sample_617 | \n",
+ " 29.0 | \n",
+ " NaN | \n",
+ " 101 | \n",
+ " NaN | \n",
+ " 72.0 | \n",
+ " 103.0 | \n",
+ " 104.0 | \n",
+ " 105.0 | \n",
+ " 74.0 | \n",
+ " 2.0 | \n",
+ " ... | \n",
+ " 1.707825 | \n",
+ " 0.57735 | \n",
+ " 17.785762 | \n",
+ " 28.887521 | \n",
+ " 25.890796 | \n",
+ " 413.0 | \n",
+ " 4.0 | \n",
+ " 44.0 | \n",
+ " 226.0 | \n",
+ " 134.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 36 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " P1_S1_A6_0C P1_S2_A8_1C P1_S3_A10_2C P1_C1_C0_D P1_C2_C0_D \\\n",
+ "样本id \n",
+ "sample_1528 38.0 NaN 100 NaN 62.0 \n",
+ "sample_1698 29.0 NaN 101 NaN 72.0 \n",
+ "sample_639 29.0 NaN 102 NaN 73.0 \n",
+ "sample_483 38.0 NaN 100 NaN 62.0 \n",
+ "sample_617 29.0 NaN 101 NaN 72.0 \n",
+ "\n",
+ " P2_S1_A12_3C P2_S2_A15_4C P2_S3_A17_5C P2_C3_C0_D P2_C3_C2_D \\\n",
+ "样本id \n",
+ "sample_1528 102.0 103.0 104.0 64.0 2.0 \n",
+ "sample_1698 103.0 104.0 105.0 74.0 2.0 \n",
+ "sample_639 103.0 104.0 105.0 74.0 1.0 \n",
+ "sample_483 102.0 103.0 104.0 64.0 2.0 \n",
+ "sample_617 103.0 104.0 105.0 74.0 2.0 \n",
+ "\n",
+ " ... P2_C2-C5_std P2_D3-D5_std P2_C1-C12_KD_ABS_std \\\n",
+ "样本id ... \n",
+ "sample_1528 ... 1.707825 0.57735 9.643651 \n",
+ "sample_1698 ... 1.707825 0.57735 17.785762 \n",
+ "sample_639 ... 1.290994 0.00000 18.009257 \n",
+ "sample_483 ... 1.707825 0.57735 9.165151 \n",
+ "sample_617 ... 1.707825 0.57735 17.785762 \n",
+ "\n",
+ " P2_C1-C12_D_std P2_LARGE_KD_std P2_C2-C5_sum P2_D3-D5_sum \\\n",
+ "样本id \n",
+ "sample_1528 24.928565 23.245071 409.0 4.0 \n",
+ "sample_1698 28.887521 25.890796 413.0 4.0 \n",
+ "sample_639 29.231642 25.514702 414.0 3.0 \n",
+ "sample_483 24.617293 22.479620 409.0 4.0 \n",
+ "sample_617 28.887521 25.890796 413.0 4.0 \n",
+ "\n",
+ " P2_C1-C12_KD_ABS_sum P2_C1-C12_D_sum P2_LARGE_KD_sum \n",
+ "样本id \n",
+ "sample_1528 27.0 191.0 113.0 \n",
+ "sample_1698 44.0 226.0 134.0 \n",
+ "sample_639 43.0 226.0 135.0 \n",
+ "sample_483 30.0 207.0 118.0 \n",
+ "sample_617 44.0 226.0 134.0 \n",
+ "\n",
+ "[5 rows x 36 columns]"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_temperature.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### 时间相关特征"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 时间计算方式转换\n",
+ "def duration_outer(series1, series2):\n",
+ " # 处理隔了一天如21:30 - 01:30\n",
+ " duration = series1 - series2\n",
+ " duration = np.where(duration < 0, duration + 24*60, duration)\n",
+ " duration = np.where(duration > 12*60, 24*60 - duration, duration)\n",
+ " duration = np.where(duration > 6*60, 12*60 - duration, duration)\n",
+ " return duration"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "raw = df_trn_tst.copy()\n",
+ "df = pd.DataFrame(raw['样本id'])\n",
+ "# 加热过程\n",
+ "df['P1_S1_A5_0T'] = raw['A5_t'] # 初始时刻\n",
+ "df['P1_S2_A9_2T'] = raw['A9_t'] # 初始时刻\n",
+ "df['P1_T1_T0_D'] = duration_outer(raw['A7_t'], raw['A5_t'])\n",
+ "# 初次测温时间差\n",
+ "df['P1_T2_T1_D'] = duration_outer(raw['A9_t'], raw['A7_t'])\n",
+ "# 二次测温时间差\n",
+ "df['P1_T2_T0_K_D'] = duration_outer(raw['A9_t'], raw['A5_t'])\n",
+ "# 开始加热至沸腾时间差\n",
+ "\n",
+ "# 水解过程\n",
+ "df['P2_S1_A11_3T'] = raw['A11_t'] # 水解开始时刻\n",
+ "df['P2_S1_A16_5T'] = raw['A16_t'] # 水解结束时刻\n",
+ "\n",
+ "df['P2_T3_T0_K_D'] = duration_outer(raw['A11_t'], raw['A5_t'])\n",
+ "# 开始加热至投料时间差\n",
+ "df['P2_T3_T2_K_D'] = duration_outer(raw['A11_t'], raw['A9_t'])\n",
+ "# 恒温至投料投料时间差\n",
+ "# df['P2_T4_T3_D'] = raw['A14_t'] - raw['A11_t'] # 水解初次测温时间差\n",
+ "# df['P2_T5_T4_D'] = raw['A16_t'] - raw['A14_t'] # 水解结束时间差\n",
+ "df['P2_T5_T3_K_D'] = duration_outer(raw['A16_t'], raw['A11_t'])\n",
+ "# 水解时间差\n",
+ "\n",
+ "# 脱色过程\n",
+ "df['P3_S1_A20_6T'] = raw['A20_at'] # 中和开始时刻\n",
+ "df['P3_S2_A25_7T'] = raw['A24_t'] # 保温时刻\n",
+ "\n",
+ "df['P3_T6_T5_K_D'] = duration_outer(raw['A20_at'], raw['A16_t'])\n",
+ "# 水解结束至中和间歇时间\n",
+ "df['P3_T6_T6_K_D'] = duration_outer(raw['A20_bt'], raw['A20_at'])\n",
+ "# 酸碱度中和时间\n",
+ "df['P3_T7_T6_D'] = duration_outer(raw['A24_t'], raw['A20_bt'])\n",
+ "# 中和结束至脱色间歇时间\n",
+ "df['P3_T8_T7_K_D'] = duration_outer(raw['A26_t'], raw['A24_t'])\n",
+ "# 脱色保温时间\n",
+ "df['P3_T9_T8_D'] = duration_outer(raw['A28_at'], raw['A26_t'])\n",
+ "# 脱色至抽滤间歇时间\n",
+ "df['P3_T9_T9_K_D'] = duration_outer(raw['A28_bt'], raw['A28_at'])\n",
+ "# 抽滤时间\n",
+ "df['P3_T9_T5_1D'] = duration_outer(raw['A28_bt'], raw['A16_t'])\n",
+ "df['P3_T9_T6_2D'] = duration_outer(raw['A28_bt'], raw['A20_at'])\n",
+ "# 脱色总时间\n",
+ "\n",
+ "# 结晶过程\n",
+ "df['P4_S1_B4_10T'] = raw['B4_at'] # 酸化开始时刻\n",
+ "df['P4_S2_B5_11T'] = raw['B5_t'] # 结晶开始时刻\n",
+ "df['P4_S3_B7_12T'] = raw['B7_t'] # 结晶结束时刻\n",
+ "\n",
+ "df['P4_T10_T9_D'] = duration_outer(raw['B4_at'], raw['A28_bt'])\n",
+ "# 抽滤结束至酸化间歇时间\n",
+ "df['P4_T10_T10_K_D'] = duration_outer(raw['B4_bt'], raw['B4_at'])\n",
+ "# 酸化时间\n",
+ "df['P4_T11_T10_K_D'] = duration_outer(raw['B5_t'], raw['B4_bt'])\n",
+ "# 酸化至结晶间歇时间\n",
+ "df['P4_T12_T11_K_D'] = duration_outer(raw['B7_t'], raw['B5_t'])\n",
+ "# 自然结晶时间\n",
+ "df['P4_T12_T9_1D'] = duration_outer(raw['B7_t'], raw['A28_bt'])\n",
+ "df['P4_T12_T10_2D'] = duration_outer(raw['B7_t'], raw['B4_at'])\n",
+ "# 结晶总时间\n",
+ "\n",
+ "# 甩滤过程\n",
+ "df['P5_S1_B9_13T'] = raw['B9_at'] # 甩滤开始时刻\n",
+ "df['P5_S3_B12_15T'] = np.where(\n",
+ " raw['B11_bt'].isnull(),\n",
+ " np.where(raw['B10_bt'].isnull(), raw['B9_bt'], raw['B10_bt']),\n",
+ " raw['B11_bt']) # 甩滤结束时刻\n",
+ "df['P5_T13_T12_D'] = duration_outer(raw['B9_at'], raw['B7_t'])\n",
+ "# 酸化结束至甩滤间歇时间\n",
+ "df['P5_T13_T13_K_D'] = duration_outer(raw['B9_bt'], raw['B9_at'])\n",
+ "# 基本甩滤时间\n",
+ "df['P5_T14_T13_D'] = duration_outer(raw['B10_at'], raw['B9_bt'])\n",
+ "# 基本甩滤至补充甩滤1间歇时间\n",
+ "df['P5_T14_T14_K_D'] = duration_outer(raw['B10_bt'], raw['B10_at'])\n",
+ "# 补充甩滤1时间\n",
+ "df['P5_T15_T14_D'] = duration_outer(raw['B11_at'], raw['B10_bt'])\n",
+ "# 补充甩滤1至补充甩滤2间歇时间\n",
+ "df['P5_T15_T13_K_D'] = duration_outer(raw['B11_bt'], raw['B11_at'])\n",
+ "# 补充甩滤2时间\n",
+ "df['P5_T15_T13_1D'] = \\\n",
+ " df[['P5_T13_T13_K_D', 'P5_T14_T14_K_D', 'P5_T13_T13_K_D']].sum(axis=1)\n",
+ "df['P5_T15_T12_2D'] = duration_outer(\n",
+ " df['P5_S3_B12_15T'], df['P4_S3_B7_12T'])\n",
+ "df['P5_T15_T12_3D'] = duration_outer(\n",
+ " df['P5_S3_B12_15T'], df['P5_S1_B9_13T'])\n",
+ "# 总甩滤时间\n",
+ "\n",
+ "# 总流程时长\n",
+ "df['P5_T15_T1_4D'] = \\\n",
+ " df[['P5_T15_T12_2D', 'P4_T12_T9_1D', 'P3_T9_T5_1D',\n",
+ " 'P2_T3_T0_K_D', 'P2_T5_T3_K_D']].sum(axis=1)\n",
+ "_funcs = ['mean', 'std', 'sum']\n",
+ "for _func in _funcs:\n",
+ " df[f'P5__D_{_func}'] = \\\n",
+ " df[[_f for _f in df.columns if _f.endswith('_D')]].\\\n",
+ " abs().agg(_func, axis=1)\n",
+ " df[f'P5_K_D_{_func}'] = \\\n",
+ " df[[_f for _f in df.columns if _f.endswith('_K_D')]]. \\\n",
+ " abs().agg(_func, axis=1)\n",
+ " df[f'P5__D_{_func}'] = \\\n",
+ " df[[_f for _f in df.columns if _f.endswith('D')]]. \\\n",
+ " abs().agg(_func, axis=1)\n",
+ "df_duration = df.set_index('样本id')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " P1_S1_A5_0T | \n",
+ " P1_S2_A9_2T | \n",
+ " P1_T1_T0_D | \n",
+ " P1_T2_T1_D | \n",
+ " P1_T2_T0_K_D | \n",
+ " P2_S1_A11_3T | \n",
+ " P2_S1_A16_5T | \n",
+ " P2_T3_T0_K_D | \n",
+ " P2_T3_T2_K_D | \n",
+ " P2_T5_T3_K_D | \n",
+ " ... | \n",
+ " P5_T15_T13_1D | \n",
+ " P5_T15_T12_2D | \n",
+ " P5_T15_T12_3D | \n",
+ " P5_T15_T1_4D | \n",
+ " P5__D_mean | \n",
+ " P5_K_D_mean | \n",
+ " P5__D_std | \n",
+ " P5_K_D_std | \n",
+ " P5__D_sum | \n",
+ " P5_K_D_sum | \n",
+ "
\n",
+ " \n",
+ " 样本id | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " sample_1528 | \n",
+ " 810 | \n",
+ " 930 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 120 | \n",
+ " 990 | \n",
+ " 1110 | \n",
+ " 180 | \n",
+ " 60 | \n",
+ " 120 | \n",
+ " ... | \n",
+ " 270.0 | \n",
+ " 240.0 | \n",
+ " 240.0 | \n",
+ " 840.0 | \n",
+ " 145.384615 | \n",
+ " 90.000000 | \n",
+ " 169.852425 | \n",
+ " 63.639610 | \n",
+ " 3780.0 | \n",
+ " 1170.0 | \n",
+ "
\n",
+ " \n",
+ " sample_1698 | \n",
+ " 840 | \n",
+ " 960 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 120 | \n",
+ " 1020 | \n",
+ " 1140 | \n",
+ " 180 | \n",
+ " 60 | \n",
+ " 120 | \n",
+ " ... | \n",
+ " 270.0 | \n",
+ " 240.0 | \n",
+ " 240.0 | \n",
+ " 960.0 | \n",
+ " 136.071429 | \n",
+ " 90.000000 | \n",
+ " 188.588113 | \n",
+ " 76.258669 | \n",
+ " 3810.0 | \n",
+ " 1260.0 | \n",
+ "
\n",
+ " \n",
+ " sample_639 | \n",
+ " 840 | \n",
+ " 960 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 120 | \n",
+ " 1020 | \n",
+ " 1140 | \n",
+ " 180 | \n",
+ " 60 | \n",
+ " 120 | \n",
+ " ... | \n",
+ " 270.0 | \n",
+ " 240.0 | \n",
+ " 240.0 | \n",
+ " 900.0 | \n",
+ " 123.214286 | \n",
+ " 75.000000 | \n",
+ " 173.654693 | \n",
+ " 49.575118 | \n",
+ " 3450.0 | \n",
+ " 1050.0 | \n",
+ "
\n",
+ " \n",
+ " sample_483 | \n",
+ " 90 | \n",
+ " 180 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 90 | \n",
+ " 240 | \n",
+ " 360 | \n",
+ " 150 | \n",
+ " 60 | \n",
+ " 120 | \n",
+ " ... | \n",
+ " 270.0 | \n",
+ " 300.0 | \n",
+ " 240.0 | \n",
+ " 990.0 | \n",
+ " 158.076923 | \n",
+ " 73.846154 | \n",
+ " 195.448596 | \n",
+ " 46.822086 | \n",
+ " 4110.0 | \n",
+ " 960.0 | \n",
+ "
\n",
+ " \n",
+ " sample_617 | \n",
+ " 1320 | \n",
+ " 0 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 120 | \n",
+ " 60 | \n",
+ " 180 | \n",
+ " 180 | \n",
+ " 60 | \n",
+ " 120 | \n",
+ " ... | \n",
+ " 270.0 | \n",
+ " 240.0 | \n",
+ " 240.0 | \n",
+ " 900.0 | \n",
+ " 123.214286 | \n",
+ " 77.142857 | \n",
+ " 173.846539 | \n",
+ " 48.107024 | \n",
+ " 3450.0 | \n",
+ " 1080.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 47 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " P1_S1_A5_0T P1_S2_A9_2T P1_T1_T0_D P1_T2_T1_D P1_T2_T0_K_D \\\n",
+ "样本id \n",
+ "sample_1528 810 930 NaN NaN 120 \n",
+ "sample_1698 840 960 NaN NaN 120 \n",
+ "sample_639 840 960 NaN NaN 120 \n",
+ "sample_483 90 180 NaN NaN 90 \n",
+ "sample_617 1320 0 NaN NaN 120 \n",
+ "\n",
+ " P2_S1_A11_3T P2_S1_A16_5T P2_T3_T0_K_D P2_T3_T2_K_D \\\n",
+ "样本id \n",
+ "sample_1528 990 1110 180 60 \n",
+ "sample_1698 1020 1140 180 60 \n",
+ "sample_639 1020 1140 180 60 \n",
+ "sample_483 240 360 150 60 \n",
+ "sample_617 60 180 180 60 \n",
+ "\n",
+ " P2_T5_T3_K_D ... P5_T15_T13_1D P5_T15_T12_2D P5_T15_T12_3D \\\n",
+ "样本id ... \n",
+ "sample_1528 120 ... 270.0 240.0 240.0 \n",
+ "sample_1698 120 ... 270.0 240.0 240.0 \n",
+ "sample_639 120 ... 270.0 240.0 240.0 \n",
+ "sample_483 120 ... 270.0 300.0 240.0 \n",
+ "sample_617 120 ... 270.0 240.0 240.0 \n",
+ "\n",
+ " P5_T15_T1_4D P5__D_mean P5_K_D_mean P5__D_std P5_K_D_std \\\n",
+ "样本id \n",
+ "sample_1528 840.0 145.384615 90.000000 169.852425 63.639610 \n",
+ "sample_1698 960.0 136.071429 90.000000 188.588113 76.258669 \n",
+ "sample_639 900.0 123.214286 75.000000 173.654693 49.575118 \n",
+ "sample_483 990.0 158.076923 73.846154 195.448596 46.822086 \n",
+ "sample_617 900.0 123.214286 77.142857 173.846539 48.107024 \n",
+ "\n",
+ " P5__D_sum P5_K_D_sum \n",
+ "样本id \n",
+ "sample_1528 3780.0 1170.0 \n",
+ "sample_1698 3810.0 1260.0 \n",
+ "sample_639 3450.0 1050.0 \n",
+ "sample_483 4110.0 960.0 \n",
+ "sample_617 3450.0 1080.0 \n",
+ "\n",
+ "[5 rows x 47 columns]"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_duration.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### 水耗相关特征"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "na_value=405\n",
+ "\n",
+ "df_trn_tst = df_trn_tst.copy()\n",
+ "df = pd.DataFrame(raw['样本id'])\n",
+ "# 耗水\n",
+ "df['P2_W_1M'] = raw['A4']\n",
+ "df['P2_W_2M'] = raw['A19']\n",
+ "# 耗盐酸\n",
+ "df['P3_H_1M'] = raw['A21'].fillna(50)\n",
+ "df['P4_H_2M'] = raw['B1'].fillna(320)\n",
+ "# 氢氧化钠\n",
+ "df['P2_N_1M'] = raw['A3'].fillna(na_value)\n",
+ "# 4-氰基吡啶\n",
+ "df['P2_C_1M'] = raw['A1']\n",
+ "\n",
+ "df['P5_W_3M'] = raw['B12'].fillna(1200)\n",
+ "df['P5_W_1M'] = df['P2_W_1M'] + df['P2_W_2M']\n",
+ "df['P5_W_3M'] = df['P2_W_1M'] + df['P2_W_2M'] + df['P5_W_3M']\n",
+ "df['P5_H_1M'] = df['P3_H_1M'] + df['P4_H_2M']\n",
+ "df['P5_M_0M'] = raw['A1'] + df['P2_N_1M'] + df['P5_W_1M'] + df['P4_H_2M']\n",
+ "df['P5_M_1M'] = df['P5_M_0M'] + df['P5_W_3M']\n",
+ "df['P5_M_2M'] = df['P5_M_1M'] + df['P3_H_1M']\n",
+ "# 理论产出\n",
+ "df['P5_O_1M'] = raw['B14']\n",
+ "df['P5_O_5M'] = raw['B14'].replace(418, 420).replace(405, 400).\\\n",
+ " replace(395, 390).replace(392, 390).replace(387, 380).\\\n",
+ " replace(385, 380).replace(370, 360).replace(350, 360).\\\n",
+ " replace(350, 360).replace(340, 360).replace(290, 280).\\\n",
+ " replace(260, 280).replace(256, 280)\n",
+ "_fs = [_f for _f in df.columns if _f.endswith('M')]\n",
+ "for _f in _fs[:-2]:\n",
+ " df[f'{_f}_P5_O_1M_R'] = df['P5_O_1M'] / df[_f]\n",
+ " df[f'{_f}_P5_O_5M_R'] = df['P5_O_5M'] / df[_f]\n",
+ "for i in range(len(_fs[:6])):\n",
+ " _f, _sub_fs = _fs[i], _fs[(i+1):6]\n",
+ " for _f_div in _sub_fs:\n",
+ " df[f'{_f}_{_f_div}_R'] = df[_f] / df[_f_div]\n",
+ "df_materials = df.set_index('样本id')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "raw = df_trn_tst.copy()\n",
+ "df = pd.DataFrame(raw['样本id'])\n",
+ "df['P5_NOT_NUM_N'] = raw.iloc[:, 1:-1].notnull().sum(axis=1)\n",
+ "df['P5_PH_1N'] = raw['A22']\n",
+ "df['P5_PH_2N'] = raw['A23']\n",
+ "df['P5_PH_2N'] = raw['B2']\n",
+ "df['P5_A7_1N'] = raw['A7_t'].isnull().astype(int)\n",
+ "df['P5_O_2M'] = (raw['B14'] <= 360).astype(int)\n",
+ "df['P5_1_3M'] = raw['B13']\n",
+ "df_interact = df.set_index('样本id')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " P5_NOT_NUM_N | \n",
+ " P5_PH_1N | \n",
+ " P5_PH_2N | \n",
+ " P5_A7_1N | \n",
+ " P5_O_2M | \n",
+ " P5_1_3M | \n",
+ "
\n",
+ " \n",
+ " 样本id | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " sample_1528 | \n",
+ " 42 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ "
\n",
+ " \n",
+ " sample_1698 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ "
\n",
+ " \n",
+ " sample_639 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ "
\n",
+ " \n",
+ " sample_483 | \n",
+ " 42 | \n",
+ " 10.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ "
\n",
+ " \n",
+ " sample_617 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " P5_NOT_NUM_N P5_PH_1N P5_PH_2N P5_A7_1N P5_O_2M P5_1_3M\n",
+ "样本id \n",
+ "sample_1528 42 9.0 3.5 1 0 0.15\n",
+ "sample_1698 44 9.0 3.5 1 0 0.15\n",
+ "sample_639 44 9.0 3.5 1 0 0.15\n",
+ "sample_483 42 10.0 3.5 1 0 0.15\n",
+ "sample_617 44 9.0 3.5 1 0 0.15"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_interact.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 合并所有特征"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_feature = pd.concat([df_materials,\n",
+ " df_duration,\n",
+ " df_temperature,\n",
+ " df_interact], axis=1).reset_index()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_trn = df_feature.iloc[:len(df_trn)].reset_index(drop=True)\n",
+ "df_trn['收率'] = df_target\n",
+ "df_tst = df_feature.iloc[len(df_trn):].reset_index(drop=True)\n",
+ "df_tst['收率'] = np.nan"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " 样本id | \n",
+ " P2_W_1M | \n",
+ " P2_W_2M | \n",
+ " P3_H_1M | \n",
+ " P4_H_2M | \n",
+ " P2_N_1M | \n",
+ " P2_C_1M | \n",
+ " P5_W_3M | \n",
+ " P5_W_1M | \n",
+ " P5_H_1M | \n",
+ " ... | \n",
+ " P2_C1-C12_KD_ABS_sum | \n",
+ " P2_C1-C12_D_sum | \n",
+ " P2_LARGE_KD_sum | \n",
+ " P5_NOT_NUM_N | \n",
+ " P5_PH_1N | \n",
+ " P5_PH_2N | \n",
+ " P5_A7_1N | \n",
+ " P5_O_2M | \n",
+ " P5_1_3M | \n",
+ " 收率 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " sample_1528 | \n",
+ " 700 | \n",
+ " 300 | \n",
+ " 50.0 | \n",
+ " 350.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 1800.0 | \n",
+ " 1000 | \n",
+ " 400.0 | \n",
+ " ... | \n",
+ " 27.0 | \n",
+ " 191.0 | \n",
+ " 113.0 | \n",
+ " 42 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.879 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " sample_1698 | \n",
+ " 700 | \n",
+ " 200 | \n",
+ " 50.0 | \n",
+ " 320.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 2100.0 | \n",
+ " 900 | \n",
+ " 370.0 | \n",
+ " ... | \n",
+ " 44.0 | \n",
+ " 226.0 | \n",
+ " 134.0 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.902 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " sample_639 | \n",
+ " 700 | \n",
+ " 200 | \n",
+ " 50.0 | \n",
+ " 320.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 2100.0 | \n",
+ " 900 | \n",
+ " 370.0 | \n",
+ " ... | \n",
+ " 43.0 | \n",
+ " 226.0 | \n",
+ " 135.0 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.936 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " sample_483 | \n",
+ " 700 | \n",
+ " 200 | \n",
+ " 50.0 | \n",
+ " 290.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 1700.0 | \n",
+ " 900 | \n",
+ " 340.0 | \n",
+ " ... | \n",
+ " 30.0 | \n",
+ " 207.0 | \n",
+ " 118.0 | \n",
+ " 42 | \n",
+ " 10.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.902 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " sample_617 | \n",
+ " 700 | \n",
+ " 200 | \n",
+ " 50.0 | \n",
+ " 320.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 2100.0 | \n",
+ " 900 | \n",
+ " 370.0 | \n",
+ " ... | \n",
+ " 44.0 | \n",
+ " 226.0 | \n",
+ " 134.0 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.983 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 144 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 样本id P2_W_1M P2_W_2M P3_H_1M P4_H_2M P2_N_1M P2_C_1M P5_W_3M \\\n",
+ "0 sample_1528 700 300 50.0 350.0 405.0 300 1800.0 \n",
+ "1 sample_1698 700 200 50.0 320.0 405.0 300 2100.0 \n",
+ "2 sample_639 700 200 50.0 320.0 405.0 300 2100.0 \n",
+ "3 sample_483 700 200 50.0 290.0 405.0 300 1700.0 \n",
+ "4 sample_617 700 200 50.0 320.0 405.0 300 2100.0 \n",
+ "\n",
+ " P5_W_1M P5_H_1M ... P2_C1-C12_KD_ABS_sum P2_C1-C12_D_sum \\\n",
+ "0 1000 400.0 ... 27.0 191.0 \n",
+ "1 900 370.0 ... 44.0 226.0 \n",
+ "2 900 370.0 ... 43.0 226.0 \n",
+ "3 900 340.0 ... 30.0 207.0 \n",
+ "4 900 370.0 ... 44.0 226.0 \n",
+ "\n",
+ " P2_LARGE_KD_sum P5_NOT_NUM_N P5_PH_1N P5_PH_2N P5_A7_1N P5_O_2M \\\n",
+ "0 113.0 42 9.0 3.5 1 0 \n",
+ "1 134.0 44 9.0 3.5 1 0 \n",
+ "2 135.0 44 9.0 3.5 1 0 \n",
+ "3 118.0 42 10.0 3.5 1 0 \n",
+ "4 134.0 44 9.0 3.5 1 0 \n",
+ "\n",
+ " P5_1_3M 收率 \n",
+ "0 0.15 0.879 \n",
+ "1 0.15 0.902 \n",
+ "2 0.15 0.936 \n",
+ "3 0.15 0.902 \n",
+ "4 0.15 0.983 \n",
+ "\n",
+ "[5 rows x 144 columns]"
+ ]
+ },
+ "execution_count": 30,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_trn.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for _df in [df_trn, df_tst]:\n",
+ " _df.insert(1, 'id', _df['样本id'].str.split('_').str[1].astype(float))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " 样本id | \n",
+ " id | \n",
+ " P2_W_1M | \n",
+ " P2_W_2M | \n",
+ " P3_H_1M | \n",
+ " P4_H_2M | \n",
+ " P2_N_1M | \n",
+ " P2_C_1M | \n",
+ " P5_W_3M | \n",
+ " P5_W_1M | \n",
+ " ... | \n",
+ " P2_C1-C12_KD_ABS_sum | \n",
+ " P2_C1-C12_D_sum | \n",
+ " P2_LARGE_KD_sum | \n",
+ " P5_NOT_NUM_N | \n",
+ " P5_PH_1N | \n",
+ " P5_PH_2N | \n",
+ " P5_A7_1N | \n",
+ " P5_O_2M | \n",
+ " P5_1_3M | \n",
+ " 收率 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " sample_1528 | \n",
+ " 1528.0 | \n",
+ " 700 | \n",
+ " 300 | \n",
+ " 50.0 | \n",
+ " 350.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 1800.0 | \n",
+ " 1000 | \n",
+ " ... | \n",
+ " 27.0 | \n",
+ " 191.0 | \n",
+ " 113.0 | \n",
+ " 42 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.879 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " sample_1698 | \n",
+ " 1698.0 | \n",
+ " 700 | \n",
+ " 200 | \n",
+ " 50.0 | \n",
+ " 320.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 2100.0 | \n",
+ " 900 | \n",
+ " ... | \n",
+ " 44.0 | \n",
+ " 226.0 | \n",
+ " 134.0 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.902 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " sample_639 | \n",
+ " 639.0 | \n",
+ " 700 | \n",
+ " 200 | \n",
+ " 50.0 | \n",
+ " 320.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 2100.0 | \n",
+ " 900 | \n",
+ " ... | \n",
+ " 43.0 | \n",
+ " 226.0 | \n",
+ " 135.0 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.936 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " sample_483 | \n",
+ " 483.0 | \n",
+ " 700 | \n",
+ " 200 | \n",
+ " 50.0 | \n",
+ " 290.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 1700.0 | \n",
+ " 900 | \n",
+ " ... | \n",
+ " 30.0 | \n",
+ " 207.0 | \n",
+ " 118.0 | \n",
+ " 42 | \n",
+ " 10.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.902 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " sample_617 | \n",
+ " 617.0 | \n",
+ " 700 | \n",
+ " 200 | \n",
+ " 50.0 | \n",
+ " 320.0 | \n",
+ " 405.0 | \n",
+ " 300 | \n",
+ " 2100.0 | \n",
+ " 900 | \n",
+ " ... | \n",
+ " 44.0 | \n",
+ " 226.0 | \n",
+ " 134.0 | \n",
+ " 44 | \n",
+ " 9.0 | \n",
+ " 3.5 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 0.15 | \n",
+ " 0.983 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 145 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 样本id id P2_W_1M P2_W_2M P3_H_1M P4_H_2M P2_N_1M P2_C_1M \\\n",
+ "0 sample_1528 1528.0 700 300 50.0 350.0 405.0 300 \n",
+ "1 sample_1698 1698.0 700 200 50.0 320.0 405.0 300 \n",
+ "2 sample_639 639.0 700 200 50.0 320.0 405.0 300 \n",
+ "3 sample_483 483.0 700 200 50.0 290.0 405.0 300 \n",
+ "4 sample_617 617.0 700 200 50.0 320.0 405.0 300 \n",
+ "\n",
+ " P5_W_3M P5_W_1M ... P2_C1-C12_KD_ABS_sum P2_C1-C12_D_sum \\\n",
+ "0 1800.0 1000 ... 27.0 191.0 \n",
+ "1 2100.0 900 ... 44.0 226.0 \n",
+ "2 2100.0 900 ... 43.0 226.0 \n",
+ "3 1700.0 900 ... 30.0 207.0 \n",
+ "4 2100.0 900 ... 44.0 226.0 \n",
+ "\n",
+ " P2_LARGE_KD_sum P5_NOT_NUM_N P5_PH_1N P5_PH_2N P5_A7_1N P5_O_2M \\\n",
+ "0 113.0 42 9.0 3.5 1 0 \n",
+ "1 134.0 44 9.0 3.5 1 0 \n",
+ "2 135.0 44 9.0 3.5 1 0 \n",
+ "3 118.0 42 10.0 3.5 1 0 \n",
+ "4 134.0 44 9.0 3.5 1 0 \n",
+ "\n",
+ " P5_1_3M 收率 \n",
+ "0 0.15 0.879 \n",
+ "1 0.15 0.902 \n",
+ "2 0.15 0.936 \n",
+ "3 0.15 0.902 \n",
+ "4 0.15 0.983 \n",
+ "\n",
+ "[5 rows x 145 columns]"
+ ]
+ },
+ "execution_count": 32,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_trn.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "df_trn['收率'].plot(kind='hist')\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_trn = df_trn.query('收率 > 0.8671').reset_index(drop=True) # 筛选常规数据\n",
+ "df_trn = df_trn.query('收率 < 0.9861').reset_index(drop=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "df_trn['收率'].plot(kind='hist')\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 训练模型"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def xgb_cv(train, test, params, fit_params, feature_names, nfold, seed):\n",
+ " \"\"\"\n",
+ " train训练数据\n",
+ " test测试数据\n",
+ " params参数\n",
+ " fit_params训练参数\n",
+ " feature_names特征名\n",
+ " nfold几折交叉\n",
+ " seed随机种子\n",
+ " \"\"\"\n",
+ " # 创建结果df\n",
+ " train_pred = pd.DataFrame({\n",
+ " 'id': train['样本id'],\n",
+ " 'true': train['收率'],\n",
+ " 'pred': np.zeros(len(train))})\n",
+ " # 测试提交结果\n",
+ " test_pred = pd.DataFrame({'id': test['样本id'], 'pred': np.zeros(len(test))})\n",
+ " # 交叉验证\n",
+ " kfolder = KFold(n_splits=nfold, shuffle=True, random_state=seed)\n",
+ " # 构造测试DMatrix\n",
+ " xgb_tst = xgb.DMatrix(data=test[feature_names])\n",
+ " print('\\n')\n",
+ " # 遍历cv中每一折数据,通过索引来指定\n",
+ " for fold_id, (trn_idx, val_idx) in enumerate(kfolder.split(train['收率'])):\n",
+ " # 构造当前训练的DMatrix\n",
+ " xgb_trn = xgb.DMatrix(\n",
+ " train.iloc[trn_idx][feature_names],\n",
+ " train.iloc[trn_idx]['收率'])\n",
+ " # 构造当前验证的DMatrix\n",
+ " xgb_val = xgb.DMatrix(\n",
+ " train.iloc[val_idx][feature_names],\n",
+ " train.iloc[val_idx]['收率'])\n",
+ " # 训练回归模型\n",
+ " xgb_reg = xgb.train(params=params, dtrain=xgb_trn, **fit_params,\n",
+ " evals=[(xgb_trn, 'train'), (xgb_val, 'valid')])\n",
+ " # 得到验证结果\n",
+ " val_pred = xgb_reg.predict(\n",
+ " xgb.DMatrix(train.iloc[val_idx][feature_names]),\n",
+ " ntree_limit=xgb_reg.best_ntree_limit)\n",
+ " train_pred.loc[val_idx, 'pred'] = val_pred\n",
+ " # print(f'Fold_{fold_id}', mse(train.iloc[val_idx]['收率'], val_pred))\n",
+ " test_pred['pred'] += xgb_reg.predict(\n",
+ " xgb_tst, ntree_limit=xgb_reg.best_ntree_limit) / nfold\n",
+ " print('\\nCV LOSS:', mse(train_pred['true'], train_pred['pred']), '\\n')\n",
+ " return test_pred\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 设置训练参数\n",
+ "fit_params = {'num_boost_round': 10800,\n",
+ " 'verbose_eval': 300,\n",
+ " 'early_stopping_rounds': 360}\n",
+ "params_xgb = {'eta': 0.01, 'max_depth': 7, 'subsample': 0.8,\n",
+ " 'booster': 'gbtree', 'colsample_bytree': 0.8,\n",
+ " 'objective': 'reg:linear', 'silent': True, 'nthread': 4}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "\n",
+ "[0]\ttrain-rmse:0.42052\tvalid-rmse:0.417952\n",
+ "Multiple eval metrics have been passed: 'valid-rmse' will be used for early stopping.\n",
+ "\n",
+ "Will train until valid-rmse hasn't improved in 360 rounds.\n",
+ "[300]\ttrain-rmse:0.023717\tvalid-rmse:0.023667\n",
+ "[600]\ttrain-rmse:0.00645\tvalid-rmse:0.011488\n",
+ "[900]\ttrain-rmse:0.004691\tvalid-rmse:0.011727\n",
+ "Stopping. Best iteration:\n",
+ "[600]\ttrain-rmse:0.00645\tvalid-rmse:0.011488\n",
+ "\n",
+ "[0]\ttrain-rmse:0.419812\tvalid-rmse:0.420785\n",
+ "Multiple eval metrics have been passed: 'valid-rmse' will be used for early stopping.\n",
+ "\n",
+ "Will train until valid-rmse hasn't improved in 360 rounds.\n",
+ "[300]\ttrain-rmse:0.02374\tvalid-rmse:0.025614\n",
+ "[600]\ttrain-rmse:0.006597\tvalid-rmse:0.01204\n",
+ "[900]\ttrain-rmse:0.004692\tvalid-rmse:0.01197\n",
+ "Stopping. Best iteration:\n",
+ "[810]\ttrain-rmse:0.005159\tvalid-rmse:0.011948\n",
+ "\n",
+ "[0]\ttrain-rmse:0.419963\tvalid-rmse:0.420191\n",
+ "Multiple eval metrics have been passed: 'valid-rmse' will be used for early stopping.\n",
+ "\n",
+ "Will train until valid-rmse hasn't improved in 360 rounds.\n",
+ "[300]\ttrain-rmse:0.023604\tvalid-rmse:0.025064\n",
+ "[600]\ttrain-rmse:0.006202\tvalid-rmse:0.01245\n",
+ "[900]\ttrain-rmse:0.004472\tvalid-rmse:0.012215\n",
+ "[1200]\ttrain-rmse:0.003453\tvalid-rmse:0.012209\n",
+ "Stopping. Best iteration:\n",
+ "[1062]\ttrain-rmse:0.003866\tvalid-rmse:0.012199\n",
+ "\n",
+ "[0]\ttrain-rmse:0.420254\tvalid-rmse:0.419025\n",
+ "Multiple eval metrics have been passed: 'valid-rmse' will be used for early stopping.\n",
+ "\n",
+ "Will train until valid-rmse hasn't improved in 360 rounds.\n",
+ "[300]\ttrain-rmse:0.02381\tvalid-rmse:0.024832\n",
+ "[600]\ttrain-rmse:0.006467\tvalid-rmse:0.010957\n",
+ "[900]\ttrain-rmse:0.004619\tvalid-rmse:0.010752\n",
+ "[1200]\ttrain-rmse:0.003542\tvalid-rmse:0.010815\n",
+ "Stopping. Best iteration:\n",
+ "[873]\ttrain-rmse:0.004751\tvalid-rmse:0.01075\n",
+ "\n",
+ "[0]\ttrain-rmse:0.419487\tvalid-rmse:0.422069\n",
+ "Multiple eval metrics have been passed: 'valid-rmse' will be used for early stopping.\n",
+ "\n",
+ "Will train until valid-rmse hasn't improved in 360 rounds.\n",
+ "[300]\ttrain-rmse:0.023859\tvalid-rmse:0.024063\n",
+ "[600]\ttrain-rmse:0.006739\tvalid-rmse:0.0102\n",
+ "[900]\ttrain-rmse:0.004817\tvalid-rmse:0.010053\n",
+ "[1200]\ttrain-rmse:0.003709\tvalid-rmse:0.010089\n",
+ "Stopping. Best iteration:\n",
+ "[872]\ttrain-rmse:0.004956\tvalid-rmse:0.010047\n",
+ "\n",
+ "\n",
+ "CV LOSS: 0.0001280110217167903 \n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 开始训练\n",
+ "pred_xgb_a = xgb_cv(df_trn, df_tst, \n",
+ " params_xgb, fit_params,\n",
+ " df_trn.columns.tolist()[1:-1], 5, 0)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 得到预测结果\n",
+ "df_tst_a['收率'] = pred_xgb_a['pred'].values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " 样本id | \n",
+ " A1 | \n",
+ " A2 | \n",
+ " A3 | \n",
+ " A4 | \n",
+ " A5 | \n",
+ " A6 | \n",
+ " A7 | \n",
+ " A8 | \n",
+ " A9 | \n",
+ " ... | \n",
+ " B6 | \n",
+ " B7 | \n",
+ " B8 | \n",
+ " B9 | \n",
+ " B10 | \n",
+ " B11 | \n",
+ " B12 | \n",
+ " B13 | \n",
+ " B14 | \n",
+ " 收率 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " sample_1656 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 6:00:00 | \n",
+ " 29 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 8:00:00 | \n",
+ " ... | \n",
+ " 79 | \n",
+ " 17:00:00 | \n",
+ " 45 | \n",
+ " 17:00-18:30 | \n",
+ " 18:30-20:00 | \n",
+ " 20:00-21:00 | \n",
+ " 1200 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ " 0.905793 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " sample_1548 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 12:30:00 | \n",
+ " 39 | \n",
+ " 12:50:00 | \n",
+ " 80.0 | \n",
+ " 14:20:00 | \n",
+ " ... | \n",
+ " 65 | \n",
+ " 10:00:00 | \n",
+ " 45 | \n",
+ " 12:00-13:00 | \n",
+ " 14:00-15:30 | \n",
+ " NaN | \n",
+ " 800 | \n",
+ " 0.15 | \n",
+ " 385 | \n",
+ " 0.879575 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " sample_769 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 6:00:00 | \n",
+ " 80 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 8:00:00 | \n",
+ " ... | \n",
+ " 80 | \n",
+ " 17:00:00 | \n",
+ " 45 | \n",
+ " 17:00-20:00 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 1200 | \n",
+ " 0.15 | \n",
+ " 440 | \n",
+ " 0.934695 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " sample_1881 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 22:00:00 | \n",
+ " 29 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 0:00:00 | \n",
+ " ... | \n",
+ " 80 | \n",
+ " 9:00:00 | \n",
+ " 45 | \n",
+ " 9:00-10:30 | \n",
+ " 10:30-12:00 | \n",
+ " 12:00-13:00 | \n",
+ " 1200 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ " 0.903490 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " sample_1807 | \n",
+ " 300 | \n",
+ " NaN | \n",
+ " 405.0 | \n",
+ " 700 | \n",
+ " 22:00:00 | \n",
+ " 30 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 0:00:00 | \n",
+ " ... | \n",
+ " 79 | \n",
+ " 9:00:00 | \n",
+ " 45 | \n",
+ " 9:00-10:30 | \n",
+ " 10:30-12:00 | \n",
+ " 12:00-13:00 | \n",
+ " 1200 | \n",
+ " 0.15 | \n",
+ " 400 | \n",
+ " 0.928534 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
5 rows × 44 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 样本id A1 A2 A3 A4 A5 A6 A7 A8 A9 \\\n",
+ "0 sample_1656 300 NaN 405.0 700 6:00:00 29 NaN NaN 8:00:00 \n",
+ "1 sample_1548 300 NaN 405.0 700 12:30:00 39 12:50:00 80.0 14:20:00 \n",
+ "2 sample_769 300 NaN 405.0 700 6:00:00 80 NaN NaN 8:00:00 \n",
+ "3 sample_1881 300 NaN 405.0 700 22:00:00 29 NaN NaN 0:00:00 \n",
+ "4 sample_1807 300 NaN 405.0 700 22:00:00 30 NaN NaN 0:00:00 \n",
+ "\n",
+ " ... B6 B7 B8 B9 B10 B11 B12 B13 \\\n",
+ "0 ... 79 17:00:00 45 17:00-18:30 18:30-20:00 20:00-21:00 1200 0.15 \n",
+ "1 ... 65 10:00:00 45 12:00-13:00 14:00-15:30 NaN 800 0.15 \n",
+ "2 ... 80 17:00:00 45 17:00-20:00 NaN NaN 1200 0.15 \n",
+ "3 ... 80 9:00:00 45 9:00-10:30 10:30-12:00 12:00-13:00 1200 0.15 \n",
+ "4 ... 79 9:00:00 45 9:00-10:30 10:30-12:00 12:00-13:00 1200 0.15 \n",
+ "\n",
+ " B14 收率 \n",
+ "0 400 0.905793 \n",
+ "1 385 0.879575 \n",
+ "2 440 0.934695 \n",
+ "3 400 0.903490 \n",
+ "4 400 0.928534 \n",
+ "\n",
+ "[5 rows x 44 columns]"
+ ]
+ },
+ "execution_count": 41,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_tst_a.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.7.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/机器学习竞赛实战_优胜解决方案/工业生产预测/assets/20201130145942327.png b/机器学习竞赛实战_优胜解决方案/工业生产预测/assets/20201130145942327.png
new file mode 100644
index 0000000000000000000000000000000000000000..c04cdd965f9d7282967d22f710493bc02553d618
GIT binary patch
literal 296286
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