请勿推荐,谢谢!
比赛地址
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:PycharmProjectsTianChiProject 0_hardworkercompetitions 16_heartbeat_signalspredict_resultdw_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+。