-
重要性:调参带来的效果增幅是非常有限的,但特征工程的好坏往往会决定了最终的排名和成绩。特征工程可以将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能
-
具体情况具体分析:不同模型对于数据集的要求不同,因此处理完的数据应该分开来存储。
-
缺失:加入先验知识 异常:清除噪声
-
集中:数据集中(归一化、标准化)、变量集中(特征筛选、降维)
-
有价值:数据有价值(数据分桶)、变量有价值(特征构造)
一、自动化EDA
# pip install pandas_profiling
import pandas as pd
import seaborn as sns
mpg = sns.load_dataset('mpg')
mpg.head()
from pandas_profiling import ProfileReport
profile = ProfileReport(mpg, title='MPG Pandas Profiling Report', explorative = True)
profile
二、准备工作
(一)合并数据
# 训练集和测试集放在一起,方便构造特征
Train_data['train']=1
Test_data['train']=0
data = pd.concat([Train_data, Test_data], ignore_index=True) # ignore_index=True被拼接的两个表的索引都不重要
#
df2 非空DataFrame
df0=pd.DataFrame(columns=df2.columns) # concat时如果df0是空的会报错
df1=pd.concat([df0,df2])
(二)groupby聚合观察数据特征
#求分组后y1的min,y2的max,y3的std
df1=df.groupby(['x1','x2','x3'],as_index=False)['y1','y2','y3'].agg({
'y1':min,'y2':max,'y3':np.std})
#求分组后y1的min
df1=df.groupby(['x1','x2','x3'],as_index=False)['y1'].min()
(三)去重
data2=data.drop_duplicates(subset=['x2','x3']).reset_index(drop=True) #去重之后索引会改变,需要重置。并且一定要改名字,防止重复累积计算。
df.drop_duplicates(keep='first',inplace=True) #inplace=True是直接在df的基础上操作,最好还是构造新表
(四)按列排序
df2=df1.sort_index(by=['x1','x2']).reset_index(drop=True) #排序后要重置索引
(五)随机抽数
df2=df1.sample(n=8000,random_state=123).reset_index(drop=True) #抽数后要重置索引
(六)保存、创建、与拼接
包含大数据量的计算,如果能够持久化存储,一定要存下来,节省下次计算的大量的宝贵时间。
# 保存
data.to_csv('data.csv',encoding='utf-8',index_label=False,header=1) #不包含索引列,包含列名
# 创建新表
df=pd.DataFrame() #空表
df['a']=range(1,100)
df['b']=0
## 等同于
df=pd.DataFrame({'a':range(1,100),'b':0})
# 拼接
#列相同,做行连接
df = pd.concat([df1, df2, df3]) #keys=['x', 'y', 'z']识别来源于哪张表
#列连接,推荐用merge
df = pd.concat([df1, df2], axis=1) #join='inner'/'outer':交集/并集
df0=pd.merge(df,df_temp2[['device_id','ds','rw']],how='right',on=['device_id','ds','rw']) #从df中删除这异常的13个片段
(七)转换数据格式
df[2] = df[2].astype('int')
在使用Toad包时,需要把string转换成float,如果不转换会报错,怎样找到报错的变量是哪个,并一次性记录下来?
list_drop=[]
for x in df_v1.columns:
if 'n' in df_v1[x].value_counts():
list_drop.append(x)
print(df_v1[x].value_counts())
print('\n')
print(list_drop)
(八)删除列
to_drop = ['APP_ID_C','month'] # 去掉ID列和month列
data.drop(to_drop,axis=1) # 用新的数据
三、特征中的异常值处理
- 作用:去除噪声
- 步骤:01-箱线图、直方图看分布;02-删:箱线图公式删除异常值,真实场景中除了设置scale之外,更重要的是根据先验知识;03-不删:尝试箱线图或先验的异常值截断、box-cox的幂变换/对数变换/导数变换处理有偏分布
(一)箱线图公式处理异常值
1. 删除
- 删除需谨慎,除非是根据先验知道数据确实异常,否则随意删除很容易改变数据分布。并且只能对训练集删除,测试集不能删。
def outliers_proc(data, col_name, scale=1.5):
"""
用于清洗异常值,默认用 box_plot(scale=1.5)进行清洗(scale=1.5表示异常值,scale=3表示极端值)
:param scale: 尺度
"""
def box_plot_outliers(data_ser, box_scale):
"""
利用箱线图去除异常值
:param data_ser: 接收 pandas.Series 数据格式
:param box_scale: 箱线图尺度,
:return:
"""
iqr = box_scale * (data_ser.quantile(0.75) - data_ser.quantile(0.25))
val_low = data_ser.quantile(0.25) - iqr
print('val_low:',val_low)
val_up = data_ser.quantile(0.75) + iqr
print('val_up:',val_up)
rule_low = (data_ser < val_low) # 下离群点
rule_up = (data_ser > val_up) # 上离群点
return (rule_low, rule_up), (val_low, val_up)
data_n = data.copy()
data_series = data_n[col_name]
rule, value = box_plot_outliers(data_series, box_scale=scale)
index = np.arange(data_series.shape[0])[rule[0] | rule[1]]
print("Delete number is: {}".format(len(index)))
data_n = data_n.drop(index)
data_n.reset_index(drop=True, inplace=True)
print("Now row number is: {}".format(data_n.shape[0]))
index_low = np.arange(data_series.shape[0])[rule[0]]
outliers = data_series.iloc[index_low]
print('\n',"Description of data less than the lower bound is:")
print(pd.Series(outliers).describe())
index_up = np.arange(data_series.shape[