【心跳信号分类预测】Datawhale打卡- Task03 特征工程

请勿推荐,谢谢!

比赛地址
https://tianchi.aliyun.com/competition/entrance/531883/information

3.1 学习目标

  • 学习时间序列数据的特征预处理方法
  • 学习时间序列特征处理工具 Tsfresh(TimeSeries Fresh)的使用

3.2 内容介绍

  • 数据预处理
    • 时间序列数据格式处理
    • 加入时间步特征time
  • 特征工程
    • 时间序列特征构造
    • 特征筛选
    • 使用 tsfresh 进行时间序列特征处理

baseline

1.导入第三方包

import time
import warnings
import lightgbm as lgb
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.model_selection import KFold
from sklearn.preprocessing import OneHotEncoder
warnings.filterwarnings('ignore')
"""
sns 相关设置
@return:
"""
import datetime
import seaborn as sns
sns.set()
sns.set_style("whitegrid")
sns.set_context('talk')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
sns.set(font='SimHei')

t0 = time.time()
print('import done, sns & plt preset done, clock() start', datetime.datetime.now())
import done, sns & plt preset done, clock() start 2021-03-16 18:00:24.924459
#### 1.1 公共变量
win_file_path = 'E:\\competition-data\\016_heartbeat_signals\\'

now = datetime.datetime.now().strftime('%Y-%m-%d_%H_%M_%S')

out_path = 'E:\\PycharmProjects\\TianChiProject\\00_hardworker\\competitions\\016_heartbeat_signals\\predict_result\\'+ 'dw_baseline_predict_{}.csv'.format(now)
print('out_path: ', out_path)
out_path:  E:\PycharmProjects\TianChiProject\00_hardworker\competitions\016_heartbeat_signals\predict_result\dw_baseline_predict_2021-03-16_18_00_24.csv

2.读取数据

data_train = pd.read_csv(win_file_path+'train.csv')
data_test_A=pd.read_csv(win_file_path+'testA.csv')
data_train.head()
id heartbeat_signals label
0 0 0.9912297987616655,0.9435330436439665,0.764677... 0.0
1 1 0.9714822034884503,0.9289687459588268,0.572932... 0.0
2 2 1.0,0.9591487564065292,0.7013782792997189,0.23... 2.0
3 3 0.9757952826275774,0.9340884687738161,0.659636... 0.0
4 4 0.0,0.055816398940721094,0.26129357194994196,0... 2.0
data_test_A.head()
id heartbeat_signals
0 100000 0.9915713654170097,1.0,0.6318163407681274,0.13...
1 100001 0.6075533139615096,0.5417083883163654,0.340694...
2 100002 0.9752726292239277,0.6710965234906665,0.686758...
3 100003 0.9956348033996116,0.9170249621481004,0.521096...
4 100004 1.0,0.8879490481178918,0.745564725322326,0.531...

3.数据预处理

对心电特征进行行转列处理,同时为每个心电信号加入时间步特征time

train_heartbeat_df = data_train["heartbeat_signals"].str.split(",", expand=True).stack()
train_heartbeat_df = train_heartbeat_df.reset_index()
train_heartbeat_df = train_heartbeat_df.set_index("level_0")
train_heartbeat_df.index.name = None
train_heartbeat_df.rename(columns={"level_1":"time", 0:"heartbeat_signals"}, inplace=True)
train_heartbeat_df["heartbeat_signals"] = train_heartbeat_df["heartbeat_signals"].astype(float)

train_heartbeat_df
time heartbeat_signals
0 0 0.991230
0 1 0.943533
0 2 0.764677
0 3 0.618571
0 4 0.379632
... ... ...
99999 200 0.000000
99999 201 0.000000
99999 202 0.000000
99999 203 0.000000
99999 204 0.000000

20500000 rows × 2 columns

将处理后的心电特征加入到训练数据中,同时将训练数据label列单独存储

data_train_label = data_train["label"]
data_train = data_train.drop("label", axis=1)
data_train = data_train.drop("heartbeat_signals", axis=1)
data_train = data_train.join(train_heartbeat_df)

data_train
id time heartbeat_signals
0 0 0 0.991230
0 0 1 0.943533
0 0 2 0.764677
0 0 3 0.618571
0 0 4 0.379632
... ... ... ...
99999 99999 200 0.000000
99999 99999 201 0.000000
99999 99999 202 0.000000
99999 99999 203 0.000000
99999 99999 204 0.000000

20500000 rows × 3 columns

可以看到,每个样本的心电特征都由205个时间步的心电信号组成。

3 使用 tsfresh 进行时间序列特征处理

1. 使用tsfresh特征抽取

Tsfresh(TimeSeries Fresh)是一个Python第三方工具包。 它可以自动计算大量的时间序列数据的特征。此外,该包还包含了特征重要性评估、特征选择的方法,因此,不管是基于时序数据的分类问题还是回归问题,tsfresh都会是特征提取一个不错的选择。官方文档:Introduction — tsfresh 0.17.1.dev24+g860c4e1 documentation

from tsfresh import extract_features

# 特征提取
train_features = extract_features(data_train, column_id='id', column_sort='time', n_jobs=6)
train_features
Feature Extraction:  100%|███████████████████████████████                           

import pickle
import pandas as pd

# train_features_filtered = pd.DataFrame({'Gender':['F','F','M','M'], 'Height':[163, 160, 175, 180]})

pickle_file_path = 'E:\\competition-data\\016_heartbeat_signals\\pickle_model\\'+ 'train_features.csv'
train_features.to_csv(pickle_file_path, index=False)
#
# train_features_filtered = pd.read_csv(pickle_file_path)
# train_features_filtered.head()

2. 特征选择

train_features中包含了heartbeat_signals的779种常见的时间序列特征(所有这些特征的解释可以去看官方文档),这其中有的特征可能为NaN值(产生原因为当前数据不支持此类特征的计算),使用以下方式去除NaN值:

from tsfresh.utilities.dataframe_functions import impute

# 去除抽取特征中的NaN值
impute(train_features)

接下来,按照特征和响应变量之间的相关性进行特征选择,这一过程包含两步:首先单独计算每个特征和响应变量之间的相关性,然后利用Benjamini-Yekutieli procedure [1] 进行特征选择,决定哪些特征可以被保留。

from tsfresh import select_features

# 按照特征和数据label之间的相关性进行特征选择
train_features_filtered = select_features(train_features, data_train_label, multiclass=True, n_jobs=6)
pickle_file_path = 'E:\\competition-data\\016_heartbeat_signals\\pickle_model\\'+ 'train_features_filtered.csv'
train_features_filtered.to_csv(pickle_file_path, index=False)

# train_features_filtered = pd.read_csv(pickle_file_path)
# train_features_filtered.head()
print(train_features_filtered.columns)
print(type(train_features_filtered))
print('id' in np.array(train_features_filtered.columns))
print('label' in np.array(train_features_filtered.columns))

4.训练数据/测试数据准备

x_train = train_features_filtered.drop(['id','label'], axis=1)
y_train = train_features_filtered['label']
x_test=data_test_A.drop(['id'], axis=1)

5.模型训练

from tsfresh import extract_features

# 特征提取
train_features = extract_features(data_train, column_id='id', column_sort='time')
train_features

2. 特征选择

train_features中包含了heartbeat_signals的779种常见的时间序列特征(所有这些特征的解释可以去看官方文档),这其中有的特征可能为NaN值(产生原因为当前数据不支持此类特征的计算),使用以下方式去除NaN值:

from tsfresh.utilities.dataframe_functions import impute

# 去除抽取特征中的NaN值
impute(train_features)

接下来,按照特征和响应变量之间的相关性进行特征选择,这一过程包含两步:首先单独计算每个特征和响应变量之间的相关性,然后利用Benjamini-Yekutieli procedure [1] 进行特征选择,决定哪些特征可以被保留。

from tsfresh import select_features

# 按照特征和数据label之间的相关性进行特征选择
train_features_filtered = select_features(train_features, data_train_label)
print(train_features_filtered.columns)
print(type(train_features_filtered))
print('id' in np.array(train_features_filtered.columns))
print('label' in np.array(train_features_filtered.columns))

5. 补充之前记过的笔记,做一下更多的特征选择

3.3.7 特征选择/特征筛选/特征精简

  • 1.1 Filter
    • a. 方差选择法
    • b. 相关系数法(pearson 相关系数)
    • c. 卡方检验
    • d. 互信息法
  • 2.2 Wrapper (RFE)
    • a. 递归特征消除法
  • 3.3 Embedded
    • a. 基于惩罚项的特征选择法
    • b. 基于树模型的特征选择

3.3.7.1 Fi特征重要性评估后,可以获得更好的数据拟合效果,更低的方差和偏差,实际rank上提分80+。 筛选特征列 : 相关系数法/卡方检验/互信息法

# 基于特征间的关系进行筛选  方差选择法
#  方差选择法中,先要计算各个特征的方差,然后根据设定的阈值,选择方差大于阈值的特征
from sklearn.feature_selection import VarianceThreshold
#其中参数threshold为方差的阈值
VarianceThreshold(threshold=3).fit_transform(train, target_train)

# 相关系数法
# Pearson 相关系数
# 皮尔森相关系数是一种最简单的,可以帮助理解特征和响应变量之间关系的方法,该方法衡量的是变量之间的线性相关性。
# 结果的取值区间为 [-1,1] , -1 表示完全的负相关, +1表示完全的正相关,0 表示没有线性相关。
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#选择K个最好的特征,返回选择特征后的数据
# #第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,
# #输出二元组(评分,P值)的数组,数组第i项为第i个特征的评分和P值。在此定义为计算相关系数
# #参数k为选择的特征个数
SelectKBest(k=5).fit_transform(train, target_train)

# 卡方检验
# 1. 经典的卡方检验是用于检验自变量对因变量的相关性。 假设自变量有N种取值,因变量有M种取值,考虑自变
# 量等于i且因变量等于j的样本频数的观察值与期望的差距。 其统计量如下: χ2=∑(A−T)2T,其中A为实际值,
# T为理论值
# 2. (注:卡方只能运用在正定矩阵上,否则会报错Input X must be non-negative)
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2 #参数k为选择的特征个数
SelectKBest(chi2, k=5).fit_transform(train, target_train)

# 互信息法
#  经典的互信息也是评价自变量对因变量的相关性的。 在feature_selection库的SelectKBest类结合最大信息系数
#   法可以用于选择特征,
from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由于MINE的设计不是函数式的,定义mic方法将其为函数式的,
# #返回一个二元组,二元组的第2项设置成固定的P值0.5
def mic(x, y):
    m = MINE()
    m.compute_score(x, y)
    return (m.mic(), 0.5) #参数k为选择的特征个数
    SelectKBest(lambda X, Y: np.array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(train,target_train)

3.3.7.2 Wrapper (Recursive feature elimination,RFE)递归特征消除法

递归消除特征法

#  递归消除特征法使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,
# 再基于新的特征集进行下一轮训练。 在feature_selection库的RFE类可以用于选择特征,相关代码如下(以逻辑
# 回归为例):

# from sklearn.feature_selection import RFE
# from sklearn.linear_model import LogisticRegression #递归特征消除法,返回特征选择后的数据 #参数estimator为基模型 #参数
# # n_features_to_select为选择的特征个数
# RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(train, target_train)

3.3.7.3 Embedded (汉译:嵌入式的/基模型)

# # 基于惩罚项的特征选择法 使用带惩罚项的基模型,除了筛选出特征外,同时也进行了降维。 在
# # feature_selection库的SelectFromModel类结合逻辑回归模型可以用于选择特征,相关代码如下:
# from sklearn.feature_selection import SelectFromModel
# from sklearn.linear_model import LogisticRegression #带L1惩罚项的逻辑回归作为基模型的特征选择
# SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(train, target_train)

# # 基于树模型的特征选择 树模型中GBDT也可用来作为基模型进行特征选择。 在feature_selection库的
# #   SelectFromModel类结合GBDT模型可以用于选择特征,相关代码如下:
# from sklearn.feature_selection import SelectFromModel
# from sklearn.ensemble import GradientBoostingClassifier #GBDT作为基模型的特征选择
# SelectFromModel(GradientBoostingClassifier()).fit_transform(train, target_train)

6. 小结

  • tsfresh后,可以获得更多特征, 707列特征,直接训练会导致过拟合——泛化能力大幅降低。
  • 通过多轮特征重要性评估后,可以获得更好的数据拟合效果,更低的方差和偏差,实际rank上提分80+。
posted @ 2021-04-21 23:42  山枫叶纷飞  阅读(437)  评论(0编辑  收藏  举报