数据挖掘入门项目二手交易车价格预测之特征工程

文章目录

  • 目标
  • 常见的特征工程
  • 具体步骤
    • 1. 导入数据
    • 2. 删除异常值
    • 3. 特征构造
      • 3.1 为树模型构造特征
      • 3.2 为LR NN 之类的模型构造特征
    • 4. 特征筛选
      • 过滤式
      • 包裹式
      • 嵌入式
    • 5. 总结

本文数据集来自阿里天池:https://tianchi.aliyun.com/competition/entrance/231784/information
主要参考了Datawhale的整个操作流程:https://tianchi.aliyun.com/notebook/95501
小编也是第一次接触数据挖掘,所以先跟着Datawhale写的教程操作了一遍,不懂的地方加了一点点自己的理解,感谢Datawhale!

目标

  • 将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能

常见的特征工程

  1. 异常处理:
  • 通过箱线图(或 3-Sigma)分析删除异常值
    ①比如在使用箱线图分析删除异常值时,我们可以将大于或小于1/4分位数的值都删掉;
    ②3-Sigma分析假设数据服从正态分布,根据3-Sigma法则,异常值通常被定义为距离均值超过3个标准差的数据点。因此,可以计算上下阈值,即均值加减3倍标准差
  • BOX-COX 转换(处理有偏分布)
    Box-Cox转换是一种统计方法,用于使数据集更接近于正态分布。它通过对数据进行幂变换来实现这一目的,可以处理偏态分布或方差不稳定的数据
  • 长尾截断
  1. 特征归一化/标准化:
  • 标准化(转换为标准正态分布)
  • 归一化(抓换到 [0,1] 区间)
  • 针对幂律分布,可以采用公式
  1. 数据分桶:
  • 等频分桶
    等频分桶的基本思想是根据数据的频率分布将数据均匀地划分为指定数量的桶。每个桶中包含的数据数量大致相等,因此每个桶中的数据密度相对均匀。这有助于减少数据的离散性,使得数据分析更加稳定和可靠
  • 等距分桶
    等距分桶的基本思想是将数据范围划分成相等宽度的区间,每个区间称为一个桶
  • Best-KS 分桶(类似利用基尼指数进行二分类)
    KS统计量(Kolmogorov-Smirnov statistic)通常用于评估两个概率分布的差异性。Best-KS分桶的目标是在保持数据分布的情况下,将连续型数据分成若干个桶(bin),使得每个桶内的数据尽可能服从同一种分布,并且不同桶之间的分布差异尽可能大
  • 卡方分桶
    用于对连续型特征进行分桶(binning)或分箱(binning)。它通过最大化特征与目标变量之间的卡方统计量来确定最优的分桶方案。
  1. 缺失值处理:
  • 不处理(针对类似 XGBoost 等树模型);
  • 删除(缺失数据太多);
  • 插值补全,包括均值/中位数/众数/建模预测/多重插补/压缩感知补全/矩阵补全等;
  • 分箱,缺失值一个箱;
  1. 特征构造:
  • 构造统计量特征,报告计数、求和、比例、标准差等;
  • 时间特征,包括相对时间和绝对时间,节假日,双休日等;
  • 地理信息,包括分箱,分布编码等方法;
  • 非线性变换,包括 log/ 平方/ 根号等;
  • 特征组合,特征交叉;
  • 仁者见仁,智者见智。
  1. 特征筛选
  • 过滤式(filter):先对数据进行特征选择,然后在训练学习器,常见的方法有 Relief/方差选择发/相关系数法/卡方检验法/互信息法;
  • 包裹式(wrapper):直接把最终将要使用的学习器的性能作为特征子集的评价准则,常见方法有 LVM(Las Vegas Wrapper) ;
  • 嵌入式(embedding):结合过滤式和包裹式,学习器训练过程中自动进行了特征选择,常见的有 lasso 回归;
  1. 降维
  • PCA/ LDA/ ICA;
  • 特征选择也是一种降维。

具体步骤

1. 导入数据

# 导入数据
train_data=pd.read_csv(train_path,sep=' ')
test_data=pd.read_csv(test_path,sep=' ')
# 查看数据
train_data.head()
# 查看数据形状
train_data.shape
# 查看数据的列
train_data.columns

2. 删除异常值

# 这里包装了一个异常值处理的代码,可以随便调用。
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:"""# 计算四分位距,并通过box_scale进行缩放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)# reset_index重新设置 DataFrame 的索引# 参数 drop=True 表示重置索引后丢弃原来的索引列# inplace 参数用于指定是否在原始 DataFrame 上进行修改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]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 the upper bound is:")print(pd.Series(outliers).describe())# 创建一个包含两个子图的画布。参数 1, 2 表示创建一个1行2列的子图网格,figsize=(10, 7) 表示画布的大小为宽10英寸,高7英寸# fig 是整个画布对象,ax 是一个包含两个子图对象的数组fig, ax = plt.subplots(1, 2, figsize=(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])return data_n

结果展示:
在这里插入图片描述

3. 特征构造

3.1 为树模型构造特征

  • 训练集和测试集放在一起,方便构造特征
train_data['train']=1
test_data['train']=0
data = pd.concat([train_data, test_data], ignore_index=True)
  • 加入使用时间:data[‘creatDate’] - data[‘regDate’],反应汽车使用时间,一般来说价格与使用时间成反比
# 注意,数据里有时间出错的格式,所以我们需要 errors='coerce',表示如果出现无法转换的情况,将会将其转换为 NaT(Not a Time)值,而不是抛出错误
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
  • 查看空数据
# 看一下空数据,发现有 15k 个样本的时间是有问题的,可以选择删除,也可以选择放着。
# 但是这里不建议删除,因为删除缺失数据占总样本量过大,7.5%
# 如果使用 XGBoost 之类的决策树,其本身就能处理缺失值,所以可以不用管;
data['used_time'].isnull().sum()
  • 加入从邮编中提取城市信息,相当于加入了先验知识
data['city'] = data['regionCode'].apply(lambda x : str(x)[:-3])
data = data
  • 加入某品牌的销售统计量
# 对数据按brand分组,结果是每个分组结果组成的结果
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
# 因为字典的键对应的是dataframe的列,所以我们要进行转置
brand_fe = pd.DataFrame(all_info).T.reset_index().rename(columns={"index": "brand"})
# 将结果合并到我们的原数据中,这里采用的是左连接,连接条件是brand
# 左连接就是说,data表显示所有,brand_fe表只显示brand值相匹配的行
data = data.merge(brand_fe, how='left', on='brand')

同理,我们还可以加入不同车型、不同燃油类型、不同变速箱、不同地区的销售统计量,这里不再一一列举

  • 对power数据进行分桶

为什么要做数据分桶呢?

    1. 离散后稀疏向量内积乘法运算速度更快,计算结果也方便存储,容易扩展;
    1. 离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大的干扰;
    1. LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,能够提升模型的表达能力,加大拟合;
    1. 离散后特征可以进行特征交叉,提升表达能力,由 M+N 个变量编程 M*N 个变量,进一步引入非线形,提升了表达能力;
    1. 特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化
    1. 当然还有很多原因,LightGBM 在改进 XGBoost 时就增加了数据分桶,增强了模型的泛化性
# 创建了一个包含31个元素的列表,每个元素是按照10的倍数递增的数字。这个列表将用作分桶的边界
bin = [i*10 for i in range(31)]
# 第一个参数是要分箱的数据,
# 第二个参数是分箱的边界,
# 第三个参数labels=False表示我们希望返回的结果是分箱后每个样本所在的箱的索引而不是标签。
# 这一行代码的结果将是一个新的Series,其中每个元素表示对应样本所在的箱的索引。
data['power_bin'] = pd.cut(data['power'], bin, labels=False)
  • 导出数据
# 删除不需要的数据
data = data.drop(['creatDate', 'regDate', 'regionCode'], axis=1)
# 目前的数据已经可以给树模型使用了,所以先导出一下
data.to_csv('data_for_tree.csv', index=0)

3.2 为LR NN 之类的模型构造特征

注:不同模型对数据集的要求不同所以分开构造

  • 对数值特征做归一化
    这里先以power列为例
    查看power的分布:
data['power'].plot.hist()

在这里插入图片描述
可以发现,直方图只有0-2500这一列,且该列的值很大,猜测数据可能分布不均匀,这里我们可以先log(数据平滑处理)一下再归一化:

data['power'] = np.log(data['power'] + 1) 
data['power'] = ((data['power'] - np.min(data['power'])) / (np.max(data['power']) - np.min(data['power'])))
data['power'].plot.hist()

在这里插入图片描述
其他列这里不再一一列举
这里可以定义一个归一化函数,将其他列传入即可

def max_min(x):return (x - np.min(x)) / (np.max(x) - np.min(x))
  • 对类别特征进行 OneEncoder
# get_dummies是pandas库中用于进行独热编码(One-Hot Encoding)的函数
data = pd.get_dummies(data, columns=['model', 'brand', 'bodyType', 'fuelType','gearbox', 'notRepairedDamage', 'power_bin'])
# 参数
# data: 这是一个DataFrame或者类似于DataFrame的数据结构,包含需要进行独热编码的数据。
# columns: 这是一个列表,包含需要进行独热编码的列名。函数将对这些列进行独热编码处理

查看一下形状,发现多了很多列,这里需要理解一下get_dummies是怎么进行one-hot编码的,比如brand有A,B两个类型,那么data里面就会把brand转化为A,B两个列,该行数据属于A类型,那么A类型这一列就为1否则为0

print(data.shape)
print(data.columns)

在这里插入图片描述

  • 保存特征
data.to_csv('data_for_lr.csv', index=0)
# index=0表示不在文件中写入行索引

4. 特征筛选

过滤式

  • 可单独计算某列特征和标签之间的相关性
# 相关性分析
print(data['power'].corr(data['price'], method='spearman'))
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'))

在这里插入图片描述

  • 也可以通过画相关性热力图来看各个特征之间的相关性
data_numeric = data[['power', 'kilometer', 'brand_amount', 'brand_price_average', 'brand_price_max', 'brand_price_median']]
# corr() 方法会计算特征之间的皮尔逊相关系数,生成一个相关性矩阵
correlation = data_numeric.corr()f , ax = plt.subplots(figsize = (7, 7))
# 这行代码给图形添加了标题,标题内容为 'Correlation of Numeric Features with Price', 
# y=1 参数将标题的位# 置设置在图形顶部,size=16 参数指定了标题的字体大小为16号
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
#使用Seaborn库中的 heatmap 函数绘制了热力图。热力图展示了相关性矩阵 correlation 中各特征之间的相关性。
# square=True 参数确保热力图是正方形的,vmax=0.8 参数设置了颜色映射的最大值,这有助于突出显示高相关性
sns.heatmap(correlation,square = True,  vmax=0.8)

在这里插入图片描述
可以看出上述对角线颜色是最浅的,因为对角线是特征自己跟自己的相关性,power跟brand_price_average, brand_price_max, brand_price_median之间的相关性比跟kilometer, brand_amount之间的相关性更强

包裹式

小编这里这一部分没有跑通,暂时没有排查出是哪里出问题了???

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()

嵌入式

待补充——

5. 总结

  • 特征工程的主要目的还是在于将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能。比如,异常值处理是为了去除噪声,填补缺失值可以加入先验知识等
  • 特征构造也属于特征工程的一部分,其目的是为了增强数据的表达
  • 有些比赛的特征是匿名特征,这导致我们并不清楚特征相互直接的关联性,这时我们就只有单纯基于特征进行处理,比如装箱,groupby,agg 等这样一些操作进行一些特征统计,此外还可以对特征进行进一步的 log,exp 等变换,或者对多个特征进行四则运算(如上面我们算出的使用时长),多项式组合等然后进行筛选。
  • 对于知道特征含义(非匿名)的特征工程,特别是在工业类型比赛中,会基于信号处理,频域提取,丰度,偏度等构建更为有实际意义的特征,这就是结合背景的特征构建,在推荐系统中也是这样的,各种类型点击率统计,各时段统计,加用户属性的统计等等,这样一种特征构建往往要深入分析背后的业务逻辑或者说物理原理,从而才能更好的找到 magic。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/293203.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOV5训练自己的数据集教程(万字整理,实现0-1)

文章目录 一、YOLOV5下载地址 二、版本及配置说明 三、初步测试 四、制作自己的数据集及转txt格式 1、数据集要求 2、下载labelme 3、安装依赖库 4、labelme操作 五、.json转txt、.xml转txt 六、修改配置文件 1、coco128.yaml->ddjc_parameter.yaml 2、yolov5x.…

【Lazy ORM 框架学习】

Gitee 点赞关注不迷路 项目地址 快速入门 模块所属层级描述快照版本正式版本wu-database-lazy-lambdalambda针对不同数据源wu-database-lazy-orm-coreorm 核心orm核心处理wu-database-lazy-sqlsql核心处理成处理sql解析、sql执行、sql映射wu-elasticsearch-starterESESwu-hb…

[图像处理] MFC载入图片并进行二值化处理和灰度处理及其效果显示

文章目录 工程效果重要代码完整代码参考 工程效果 载入图片&#xff0c;并在左侧显示原始图片、二值化图片和灰度图片。 双击左侧的图片控件&#xff0c;可以在右侧的大控件中&#xff0c;显示双击的图片。 初始画面&#xff1a; 载入图片&#xff1a; 双击左侧的第二个控件…

设计模式学习笔记 - 设计模式与范式 -行为型:2.观察者模式(下):实现一个异步非阻塞的EventBus框架

概述 《1.观察者模式&#xff08;上&#xff09;》我们学习了观察者模式的原理、实现、应用场景&#xff0c;重点节介绍了不同应用场景下&#xff0c;几种不同的实现方式&#xff0c;包括&#xff1a;同步阻塞、异步非阻塞、进程内、进程间的实现方式。 同步阻塞最经典的实现…

Android进阶学习:移动端开发重点学习的十点,不能再得过且过的写业务代码了

最近有朋友问我&#xff1a;“安卓开发是不是没人要了&#xff0c;除了画 UI 别的都不会怎么办&#xff1f;” 考虑到这可能是很多人共同的疑问&#xff0c;决定简单写一下。 说了很多遍了&#xff0c;**不是安卓开发没人要了&#xff0c;是初级安卓没人要了。**现在还在大量…

ES的RestClient相关操作

ES的RestClient相关操作 Elasticsearch使用Java操作。 本文仅介绍CURD索引库和文档&#xff01;&#xff01;&#xff01; Elasticsearch基础&#xff1a;https://blog.csdn.net/weixin_46533577/article/details/137207222 Elasticsearch Clients官网&#xff1a;https://ww…

C#,按类型删除指定文件的工具软件

点击下载本文软件&#xff08;积分&#xff09;&#xff1a; https://download.csdn.net/download/beijinghorn/89059141https://download.csdn.net/download/beijinghorn/89059141 下载审核通过之前&#xff0c;请从百度网盘下载&#xff08;无积分&#xff09;&#xff1a;…

【Linux 10】环境变量

文章目录 &#x1f308; Ⅰ 命令行参数⭐ 1. main 函数的参数⭐ 2. main 函数参数的意义⭐ 3. 查看 argv 数组的内容⭐ 4. 命令行参数结论⭐ 5. 为什么要有命令行参数⭐ 6. 命令行参数传递由谁执行 &#x1f308; Ⅱ 环境变量基本概念⭐ 1. 常见环境变量 &#x1f308; Ⅲ 查看…

鸿蒙OS开发实战:【网络管理HTTP数据请求】

一、场景介绍 应用通过HTTP发起一个数据请求&#xff0c;支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。 二、 接口说明 HTTP数据请求功能主要由http模块提供。 使用该功能需要申请ohos.permission.INTERNET权限。 涉及的接口如下表&#xff0c;…

Unix中的进程和线程-1

目录 1.如何创建一个进程 2.如何终止进程 2.2遗言函数 3.进程资源的回收 4.孤儿进程和僵尸进程 孤儿进程 (Orphan Process)&#xff1a; 僵尸进程 (Zombie Process)&#xff1a; 代码示例&#xff1a; 5. 进程映像的更新 在Linux中&#xff0c;进程和线程是操作系统进行工作调…

保研线性代数机器学习基础复习2

1.什么是群&#xff08;Group&#xff09;&#xff1f; 对于一个集合 G 以及集合上的操作 &#xff0c;如果G G-> G&#xff0c;那么称&#xff08;G&#xff0c;&#xff09;为一个群&#xff0c;并且满足如下性质&#xff1a; 封闭性&#xff1a;结合性&#xff1a;中性…

从零开始的软件开发实战:互联网医院APP搭建详解

今天&#xff0c;笔者将以“从零开始的软件开发实战&#xff1a;互联网医院APP搭建详解”为主题&#xff0c;深入探讨互联网医院APP的开发过程和关键技术。 第一步&#xff1a;需求分析和规划 互联网医院APP的主要功能包括在线挂号、医生预约、医疗咨询、健康档案管理等。我们…

金融衍生品市场

金融衍生品市场 衍生金融品的作用衍生金融工具远期合约期货合约期权 衍生金融品的作用 套期保值&#xff08;Hedging&#xff09; 组合多头头寸(long position)与空头头寸(short position)例&#xff1a;股票与股指期货 投机 衍生金融工具 远期合约 定义&#xff1a;在将来…

论文笔记 - :MonoLSS: Learnable Sample Selection For Monocular 3D Detection

论文笔记✍MonoLSS: Learnable Sample Selection For Monocular 3D Detection &#x1f4dc; Abstract &#x1f528; 主流做法限制 &#xff1a; 以前的工作以启发式的方式使用特征来学习 3D 属性&#xff0c;没有考虑到不适当的特征可能会产生不利影响。 &#x1f528; 本…

Optimizer神经网络中各种优化器介绍

1. SGD 1.1 batch-GD 每次更新使用全部的样本&#xff0c;注意会对所有的样本取均值&#xff0c;这样每次更新的速度慢。计算量大。 1.2 SGD 每次随机取一个样本。这样更新速度更快。SGD算法在于每次只去拟合一个训练样本&#xff0c;这使得在梯度下降过程中不需去用所有训…

css3之3D转换transform

css3之3D转换 一.特点二.坐标系三.3D移动&#xff08;translate3d)1.概念2.透视&#xff08;perpective)(近大远小&#xff09;&#xff08;写在父盒子上&#xff09; 四.3D旋转&#xff08;rotate3d)1.概念2.左手准则3.呈现&#xff08;transfrom-style)&#xff08;写父级盒子…

智能革命:ChatGPT3.5与GPT4.0的融合,携手DALL·E 3和Midjourney开启艺术新纪元

迷图网(kk.zlrxjh.top)是一个融合了顶尖人工智能技术的多功能助手&#xff0c;集成了ChatGPT3.5、GPT4.0、DALLE 3和Midjourney等多种智能系统&#xff0c;为用户提供了丰富的体验。以下是对这些技术的概述&#xff1a; ChatGPT3.5是由OpenAI开发的一个自然语言处理模型&#x…

KeepAlived使用介绍

目录 1、Introduce 2、基本使用 &#xff08;1&#xff09;安装 &#xff08;2&#xff09;配置文件 &#xff08;3&#xff09;使用教程 1、Introduce keepalived是一个用于实现高可用性和负载均衡的开源软件。它提供了一种轻量级的方式来管理多个服务器&#xff0c;并确保…

使用Detours进行HOOK

文章目录 Detours介绍Detours配置Detours进行Sleep Hook Detours介绍 Detours是微软研究院开发的一款软件工具&#xff0c;用于Windows平台上的应用程序重定向和修改。 它可以在运行时修改应用程序的执行路径&#xff0c;允许开发人员注入自定义代码来改变应用程序的 行为&…

数据分析之Tebleau 的度量名称和度量值

度量名称 包含所有的维度 度量值 包含所有的度量 度量名称包含上面所有的维度&#xff0c;度量值包含上面所有的度量 当同时创建两个或两个以上度量或维度时&#xff0c;会自动创建度量名称和度量值 拖入省份为行(这会是还没有值的) 可以直接将销售金额拖到数值这里 或者将销售…