对于特征进行进一步分析,并对于数据进行处理。完成对于特征工程的分析,并对于数据进行一些图表或者文字总结。
特征工程的主要目的还是在于将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能。比如,异常值处理是为了去除噪声,填补缺失值可以加入先验知识等。
目的是减少脏数据。
-不处理(针对类似XGBoost等树模型)少量样本确实时。
目的是增强数据表达,添加先验知识。
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from operator import itemgetter
from os import getcwd
#导入数据
current_path=getcwd()
train_data = pd.read_csv(current_path+"\\used_car_train_20200313.csv",sep=' ')
test_data = pd.read_csv(current_path+"\\used_car_testA_20200313.csv",sep=' ')
print(train_data.head(),train_data.tail())#查看数据的头和尾
#删除异常值
def outliers_proc(data,col_name,scale=3):
"""
用于清晰异常值,默认用box_plot(scale=3)进行清洗
:param data: 接收pandas数据格式
:param col_name: pandas列名
:param scale: 尺度
:return:
"""
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
val_up = data_ser.quantile(0.75) + iqr
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 column number is : {}".format((data_n.shape[0])))
index_low = np.arange(data_series.shape[0])[rule[0]]
outliers = data_series.iloc[index_low]#提取第index_low行数据
print("Description of data less than the lower bound is:")
print(pd.Series(outliers).describe())
index_up = np.arange(data_series.shape[0])[rule[1]]
outliers = data_series.iloc[index_up]
print("Description of data larger than upper bound is :")#高于上界的数据描述为:
print(pd.Series(outliers).describe())
fig,ax = plt.subplots(1,2, figsize=(10,7))#其中参数1和2分别代表子图的行数和列数,一共有 1x2 个子图像。函数返回一个figure图像和子图ax的array列表。figsize设置子图的宽度,即生成一个1行2个10*7大小的子图
sns.boxplot(y=data[col_name],data=data,palette="Set1",ax=ax[0])
sns.boxplot(y=data_n[col_name],data=data_n,palette="Set1",ax=ax[1])
plt.show()
return data_n
#删除异常数据。PS:test数据不可删
train_data = outliers_proc(train_data,"power",scale=3)
train_data["train"] = 0# 训练集和测试集放在一起,方便构造特征
test_data["train"] = 1
data = pd.concat([train_data,test_data],ignore_index=True)
data["used_time"] = (pd.to_datetime(data["creatDate"],format('%Y%m%d'),errors="coerce")- pd.to_datetime(data["regDate"],format("%Y%m%d"),errors="coerce")).dt.days#使用时间:data['creatDate'] - data['regDate'];数据里有时间出错的格式,所以我们需要 errors='coerce'
print(data["used_time"].isnull().sum())
扩充
pandas.to_datetime(arg,errors ='raise',utc = None,format = None,unit = None )
参数 | 意义 |
---|---|
error | 三种取值,‘ignore’, ‘raise’, ‘coerce’,默认为raise。 ‘raise’,则无效的解析将引发异常;‘coerce’,那么无效解析将被设置为NaT;‘ignore’,那么无效的解析将返回输入值 |
utc | 布尔值,默认为none。返回utc即协调世界时。 |
format | 格式化显示时间的格式。 |
unit |
# 从邮编中提取城市信息,相当于加入了先验知识
data["city"] = data["regionCode"].apply(lambda x:str(x)[:-3])
data = data
#计算某品牌的销售统计量,还可以计算其它特征统计量
train_gb = train_data.groupby("brand")
all_info = {}
for kind,kind_data in train_gb:
info = {}
kind_data = kind_data[kind_data["price"]>0]
info["brand_amount"] = len(kind_data)
info["brand_price_max"] = kind_data.price.max()
info["brand_price_median"] = kind_data.price.median()
info["brand_price_min"] = kind_data.price.min()
info["brand_price_sum"] = kind_data.price.sum()
info["brand_price_std"] = kind_data.price.std()
info["brand_price_average"] = round(kind_data.price.sum()/(len(kind_data)+1),2)#保留两位小数
all_info[kind] = info
brand_fe = pd.DataFrame(all_info).T.reset_index().rename(columns={"index":"brand"})
data = data.merge(brand_fe,how = "left", on= "brand")
PS:详解pandas库的pd.merge函数
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=True, suffixes=('_x', '_y'), py=True, indicator=False,
validate=None)
参数 | 意义 |
---|---|
left | 拼接的左侧DataFrame对象 |
right | 拼接的右侧DataFrame对象 |
on | 要加入的列或索引级别名称。 必须在左侧和右侧DataFrame对象中找到。 如果未传递且left_index和right_index为False,则DataFrame中的列的交集将被推断为连接键。 |
left_on | 左侧DataFrame中的列或索引级别用作键。 可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。 |
right_on | 左侧DataFrame中的列或索引级别用作键。 可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。 |
left_index | 如果为True,则使用左侧DataFrame中的索引(行标签)作为其连接键。 对于具有MultiIndex(分层)的DataFrame,级别数必须与右侧DataFrame中的连接键数相匹配。 |
right_index | 与left_index功能相似。 |
how | One of ‘left’, ‘right’, ‘outer’, ‘inner’. 默认inner。inner是取交集,outer取并集。比如left:[‘A’,‘B’,‘C’];right[’'A,‘C’,‘D’];inner取交集的话,left中出现的A会和right中出现的买一个A进行匹配拼接,如果没有是B,在right中没有匹配到,则会丢失。'outer’取并集,出现的A会进行一一匹配,没有同时出现的会将缺失的部分添加缺失值。 |
sort | 按字典顺序通过连接键对结果DataFrame进行排序。 默认为True,设置为False将在很多情况下显着提高性能。 |
suffixes | 用于重叠列的字符串后缀元组。 默认为(‘x’,’ y’)。 |
copy | 始终从传递的DataFrame对象复制数据(默认为True),即使不需要重建索引也是如此。 |
indicator | 将一列添加到名为_merge的输出DataFrame,其中包含有关每行源的信息。 _merge是分类类型,并且对于其合并键仅出现在“左”DataFrame中的观察值,取得值为left_only,对于其合并键仅出现在“右”DataFrame中的观察值为right_only,并且如果在两者中都找到观察点的合并键,则为left_only。 |
数据分桶
数据分桶原因:
#数据分桶 以power为例
bin = [i*10 for i in range(31)]
data["power_bin"] = pd.cut(data["power"],bin, labels=False) #用cut函数对于power进行分段分组,用bins来对年龄进行分段,左开右闭
print(data[["power_bin","power"]].head())
#(一)相关性分析
print(data["power"].corr(data["price"],method="spearman"))#检查两个变量之间变化趋势的方向以及程度,值范围-1到+1,0表示两个变量不相关,正值表示正相关,负值表示负相关,值越大相关性越强。
print(data["kilometer"].corr(data["price"],method ="spearman"))
print(data["brand_amount"].corr(data["price"],method="spearman"))
print(data["brand_price_average"].corr(data["price"],method="spearman"))
print(data["brand_price_max"].corr(data["price"],method="spearman"))
print(data["brand_price_median"].corr(data["price"],method="spearman"))
PS:
DataFrame.corr(method='pearson', min_periods=1)
pandas相关系数详解。主要用于检查两个变量之间变化趋势的方向以及程度,值范围-1到+1,0表示两个变量不相关,正值表示正相关,负值表示负相关,值越大相关性越强。
参数 | 意义 |
---|---|
method | 可填写 'pearson’、‘kendall’、“spearman”。 pearson:Pearson相关系数来衡量两个数据集合是否在一条线上面,即针对线性数据的相关系数计算,针对非线性数据便会有误差。kendall: |
min_periods | 样本最少的数据量 |
或者用图像表示
data_numeric = data[["power","kilometer","brand_amount","brand_price_average","brand_price_max","brand_price_median"]]
correlation = data_numeric.corr()
f , ax = plt.subplots(figsize=(7,7))
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
sns.heatmap(correlation,annot=True,square=True,vmax=0.8)
plt.show()
#二、包裹式
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
from sklearn.linear_model import LinearRegression
sfs = SFS(LinearRegression(),
k_features=10,
forward=True,
floating=False,
scoring = 'r2',
cv = 0)
x = data.drop(['price'], axis=1)
x = x.fillna(0)
y = data['price']
sfs.fit(x, y)
sfs.k_feature_names_
#画图,可以看到边际效益
from mlxtend.plotting import plot_sequential_feature_selection as plot_sfs
import matplotlib.pyplot as plt
fig1 = plot_sfs(sfs.get_metric_dict(), kind='std_dev')
plt.grid()
plt.show()