赛题理解
赛题状况
比赛要求参赛选手根据给定的数据集,建立模型,预测不同的心跳信号。赛题以预测心电图心跳信号类别为任务,数据集报名后可见并可下载,该该数据来自某平台心电图数据记录,总数据量超过20万,主要为1列心跳信号序列数据,其中每个样本的信号序列采样频次一致,长度相等。为了保证比赛的公平性,将会从中抽取10万条作为训练集,2万条作为测试集A,2万条作为测试集B,同时会对心跳信号类别(label)信息进行脱敏。
数据理解
train.csv
- id 为心跳信号分配的唯一标识
- heartbeat_signals 心跳信号序列(数据之间采用“,”进行分隔)
- label 心跳信号类别(0、1、2、3)
testA.csv
- id 心跳信号分配的唯一标识
- heartbeat_signals 心跳信号序列(数据之间采用“,”进行分隔)
赛题分析
- 本题为传统的数据挖掘问题,通过数据科学以及机器学习深度学习的办法来进行建模得到结果。
- 本题为典型的多分类问题,心跳信号一共有4个不同的类别
- 主要应用xgb、lgb、catboost,以及pandas、numpy、matplotlib、seabon、sklearn、keras等等数据挖掘常用库或者框架来进行数据挖掘任务。
baseline学习
导入第三方包
import os
import gc
import math
import pandas as pd
import numpy as np
import lightgbm as lgb
import xgboost as xgb
from catboost import CatBoostRegressor
from sklearn.linear_model import SGDRegressor, LinearRegression, Ridge
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.metrics import log_loss
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
from tqdm import tqdm
import matplotlib.pyplot as plt
import time
import warnings
warnings.filterwarnings('ignore')
数据读取
train = pd.read_csv(r'D:\比赛\数据挖掘心电图\train.csv')
print(train.head())
print('******************************************')
test = pd.read_csv(r'D:\比赛\数据挖掘心电图\testA.csv')
print(test.head())
得到的结果如下:
数据预处理
首先要进行内存优化
def reduce_mem_usage(df):
start_mem = df.memory_usage().sum() / 1024 ** 2
print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))
for col in df.columns:
col_type = df[col].dtype
if col_type != object:
c_min = df[col].min()
c_max = df[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
df[col] = df[col].astype(np.int64)
else:
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
else:
df[col] = df[col].astype('category')
end_mem = df.memory_usage().sum() / 1024 ** 2
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))
return df
对数据进行简单预处理
train_list = []
# print(train.values)
for items in train.values:
train_list.append([items[0]]+[float(i) for i in items[1].split(',')]+[items[2]])
train = pd.DataFrame(np.array(train_list))
train.columns = ['id']+['s_'+str(i) for i in range(len(train_list[0])-2)]+['label']
train = reduce_mem_usage(train)
此时为减少数据的内存
训练数据/测试数据准备
pandas之drop()函数
pandas中drop()函数:删除 Series 的元素或 DataFrame 的某一行(列)
drop([ ],axis=0,inplace=False)
默认情况下删除某一行或者几行,如果要删除列必须axis=1
x_train = train.drop(['id','label'],axis=1)
y_train = train['label']
x_test=test.drop(['id'], axis=1)
模型训练
KFold()简介
KFold()在sklearn中属于model_slection模块
KFold(n_splits=’warn’, shuffle=False, random_state=None)
参数:
n_splits 表示划分为几块(至少是2)
shuffle 表示是否打乱划分,默认False,即不打乱
random_state 表示是否固定随机起点,Used when shuffle == True.
独热编码OneHotEncoder简介
在分类和聚类运算中我们经常计算两个个体之间的距离,对于连续的数字(Numric)这一点不成问题,但是对于名词性(Norminal)的类别,计算距离很难。即使将类别与数字对应,例如{‘A’,‘B’,‘C’}与[0,1,2]对应,我们也不能认为A与B,B与C距离为1,而A与C距离为2。独热编码正是为了处理这种距离的度量,该方法认为每个类别之间的距离是一样的。该方法将类别与向量对应,例如{‘A’,‘B’,‘C’}分别与[1,0,0],[0,1,0],[0,0,1]对应,注意现在各个类别之间的欧式距离是相同的。
现在我们说明OneHotEncoder函数的使用
data=np.array([[1,0,3.25], [0,0,5.2], [2,1,3.6]]) enc=OneHotEncoder(categorical_features=np.array([0,1]),n_values=[3,2]) enc.fit(data) data=enc.transform(data).toarray() print(data)
运行结果为:
categorical_features是需要独热编码的列索引,n_values是对应categorical_features中各列下类别的数目,也就是原来的列拓展出新的列数。注意这里两个值可以不指定,直接使用fit_transform函数也可以,程序将统计各列中类别的多少。但是只对整数有效,对浮点数会转换为整数之后再统计,也就是对于3.5和3.6默认都是3,也就是同一类。如果指定了这两个参数,就要对未转换的数据提出要求,各列必须是以{0,1,2,3,4…}来编码,而不能以{1,10,100,200…}这种随意的方式来编码。否则会出现数组越界的错误
def abs_sum(y_pre,y_tru):
y_pre=np.array(y_pre)
y_tru=np.array(y_tru)
loss=sum(sum(abs(y_pre-y_tru)))
return loss
def cv_model(clf, train_x, train_y, test_x, clf_name):
folds = 5
seed = 2021
kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
test = np.zeros((test_x.shape[0], 4))
cv_scores = []
onehot_encoder = OneHotEncoder(sparse=False)
for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
print('************************************ {} ************************************'.format(str(i + 1)))
trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], \
train_y[valid_index]
if clf_name == "lgb":
train_matrix = clf.Dataset(trn_x, label=trn_y)
valid_matrix = clf.Dataset(val_x, label=val_y)
params = {
'boosting_type': 'gbdt',
'objective': 'multiclass',
'num_class': 4,
'num_leaves': 2 ** 5,
'feature_fraction': 0.8,
'bagging_fraction': 0.8,
'bagging_freq': 4,
'learning_rate': 0.1,
'seed': seed,
'nthread': 28,
'n_jobs': 24,
'verbose': -1,
}
model = clf.train(params,
train_set=train_matrix,
valid_sets=valid_matrix,
num_boost_round=2000,
verbose_eval=100,
early_stopping_rounds=200)
val_pred = model.predict(val_x, num_iteration=model.best_iteration)
test_pred = model.predict(test_x, num_iteration=model.best_iteration)
val_y = np.array(val_y).reshape(-1, 1)
val_y = onehot_encoder.fit_transform(val_y)
print('预测的概率矩阵为:')
print(test_pred)
test += test_pred
score = abs_sum(val_y, val_pred)
cv_scores.append(score)
print(cv_scores)
print("%s_scotrainre_list:" % clf_name, cv_scores)
print("%s_score_mean:" % clf_name, np.mean(cv_scores))
print("%s_score_std:" % clf_name, np.std(cv_scores))
test = test / kf.n_splits
return test
def lgb_model(x_train, y_train, x_test):
lgb_test = cv_model(lgb, x_train, y_train, x_test, "lgb")
return lgb_test
lgb_test = lgb_model(x_train, y_train, x_test)
得到的结果如下:
预测结果
temp=pd.DataFrame(lgb_test)
result=pd.read_csv('sample_submit.csv')
result['label_0']=temp[0]
result['label_1']=temp[1]
result['label_2']=temp[2]
result['label_3']=temp[3]
result.to_csv('test.csv',index=False)
结果提交
参考
1.《第23期组队学习_零基础入门数据挖掘(心跳信号分类)》:http://datawhale.club/t/topic/1576
2. pandas之drop()函数:https://zhuanlan.zhihu.com/p/107120035
3. sklearn KFold()简介:https://blog.csdn.net/weixin_43685844/article/details/88635492
4. 独热编码OneHotEncoder简介:https://www.cnblogs.com/sgdd123/p/7767256.html