当前位置: 首页 > news >正文

机器学习DAY7: 特征工程和特征选择(数据预处理)(完)

本文通过特征提取、特征转换、特征选择三个过程介绍数据预处理方法,特征提取将原始数据转换为适合建模的特征,特征转换将数据进行变换以提高算法的准确性,特征选择用来删除无用的特征。

知识点
  • 特征提取
  • 特征转换
  • 特征选择

本次实验的一些示例将使用 Renthop 公司的数据集。首先载入数据集。

# 下载数据并解压
!wget -nc "https://labfile.oss.aliyuncs.com/courses/1283/renthop_train.json.gz"
!gunzip "renthop_train.json.gz"

import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings('ignore')

df = pd.read_json('renthop_train.json')
df.head()

特征提取 

在实践中,很少有数据是以矩阵形式保存、可以直接使用的,这就是为什么需要对数据进行特征提取。首先看看在一些常见的数据类型中特征提取是如何进行的。

文本数据

文本的处理方法非常多,本次实验介绍最流行的一种处理过程:

  • 在处理文本之前,必须对文本进行切分词(tokenzie)操作,也就是将文本切分为单元(token)。在最简单的情形下,一个 token 就是一个单词。但直接按单词切分可能会损失一些信息,比如「Santa Barbara」应该是一个整体,却被切分为 2 个 token。现成的分词器(tokenizer)会考虑语言的特性,但也会出错,特别是当你处理特定来源的文本时(报纸、俚语、误拼、笔误)。
  • 接下来需要正则化数据。对文本而言,这涉及词干提取(stemming)和词形还原(lemmatization)方法。这两个方法是词形规范化的两类重要方式,都能够达到有效归并词形的目的,二者既有联系也有区别。两者的区别可以参考《Introduction to Information Retrieval》一书的  Stemming and lemmatization 一节。
  • 当文档被转换为单词序列之后,就可以用向量表示它。最简单的方法是词袋(Bag of Words)模型:创建一个长度等于字典的向量,计算每个单词出现在文本中的次数,然后将次数放入向量对应的位置中。

下面用代码来表述词袋模型。

import numpy as np
import pandas as pd
texts = ['i have a cat','you have a dog','you and i have a cat and a dog']vocabulary = list(enumerate(set([word for sentencein texts for word in sentence.split()])))
print('Vocabulary:', vocabulary)def vectorize(text):vector = np.zeros(len(vocabulary))for i, word in vocabulary:num = 0for w in text:if w == word:num += 1if num:vector[i] = numreturn vectorprint('Vectors:')
for sentence in texts:print(vectorize(sentence.split()))

下图是一个简化的词袋模型实现过程,在实际应用中,还需要考虑停止词,字典的最大长度等问题。 

                   

当使用词袋模型时,文本中的单词顺序信息会丢失,这意味着向量化之后,“i have no cows”(我没有牛)和“no, i have cows”(没,我有牛)会变得一样,尽管事实上它们的意思截然相反。

为了避免这个问题,可以转而使用 N-Gram 模型。下面载入相关库,建立 N-Gram 模型。 

from sklearn.feature_extraction.text import CountVectorizervect = CountVectorizer(ngram_range=(1, 1))
vect.fit_transform(['no i have cows', 'i have no cows']).toarray()

PS:这个toarray()把稀疏矩阵转换为密集矩阵了

  1. 稀疏矩阵

    • 仅记录非零元素的位置(行、列)和数值;绝大部分零不需显式保存。
    • 例如 CSR(Compressed Sparse Row)格式只保留若干数组,分别存储非零元素及其在行列上的索引。
  2. 密集矩阵

    • 用常规二维数组方式存储:从第一行第一个元素到最后一行最后一个元素,每个位置都在内存中占一个位置,无论是 0 还是非 0。
    • 如果矩阵非常大且零很多,这会浪费大量内存。

比如说这个CSR(Compressed Sparse Row): 

  • 对矩阵的每一行,记录非零元素的“列索引”和“数值”,并用一个额外的数组来标记各行在存储数组中的起始位置。
  • 核心思路:依次扫描每行,遇到非零元素就把“列索引”、“数值”存下来,行与行之间的边界用一个专门数组记下。
  • 结果:可以想象把整个矩阵“行顺序”排成一条线;对每行非零部分做顺序存储。

打印结果

vect.vocabulary_

改变参数,再次建立 N-Gram 模型。

vect = CountVectorizer(ngram_range=(1, 2))
vect.fit_transform(['no i have cows', 'i have no cows']).toarray()

打印结果。

vect.vocabulary_

除了基于单词生成 N-Gram 模型,在某些情形下,可以基于字符生成 N-Gram 模型,以考虑相关单词的相似性或笔误,下面基于字符生成 N-Gram 模型,并查看它们之间的欧氏距离。

from scipy.spatial.distance import euclidean
from sklearn.feature_extraction.text import CountVectorizervect = CountVectorizer(ngram_range=(3, 3), analyzer='char_wb')n1, n2, n3, n4 = vect.fit_transform(['andersen', 'petersen', 'petrov', 'smith']).toarray()euclidean(n1, n2), euclidean(n2, n3), euclidean(n3, n4)

有时候,在语料库(数据集的全部文档)中罕见但在当前文本中出现的专业词汇可能会非常重要。因此,通过增加专业词汇的权重把它们和常用词区分开,是很合理的,这一方法称为 TF-IDF(词频 - 逆向文档频率),其默认选项为: 

                                       

使用上述这些传统方法及模型,在简单问题上就可能得到不错的效果,可以作为后续模型的基线。然而,倘若不喜欢前面的传统方法,还有 Word2Vec、GloVe、Fasttext 等方法可以选择。

Word2Vec 是词嵌入算法的一个特殊情形。使用 Word2Vec 和类似的模型,不仅可以向量化高维空间(通常是成百上千维的空间)中的单词,还能比较它们的语义相似度。下图演示了一个经典例子:king(王)- man(男)+ woman(女) = queen(皇后)。

                                                

图像数据

处理图像既简单又复杂。简单是因为现在我们可以直接使用某个流行的预训练网络,而不用思考太多;复杂是因为,如果深入图像领域,那么就需要考虑非常多的细节问题。

在 GPU 不够强的年代,图像的特征提取本身是一个非常复杂的领域。我们需要对较低的层进行提取,检测角点、区域边界、色彩分布统计等。如果你对这些经典方法感兴趣,可以看下 skimage 和 SimpleCV 这两个库。

现在,和图像相关的问题,常常可以直接使用卷积神经网络来完成。你不需要从头设计网络架构,从头训练网络,下载一个当前最先进的预训练网络及其权重,“分离”网络的最后一个全连接层,增加针对特定任务的新层,接着在新数据上训练网络即可。这一让预训练网络适应特定任务的过程被称为微调(fine-tuning)。

下图是 fine-tuning 的一个例子。

 

如果任务仅仅是对图像进行向量化(抽取图像的特征),那么只需移除最后一层,使用前一层的输出即可,下面通过调用 Keras 中的预训练网络进行图像特征抽取。首先加载相关库。

from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input
from tensorflow.keras.preprocessing import image
from scipy.misc import face
import numpy as np

同时,由于原 ResNet50 模型托管在外网上,速度较慢。我们直接通过服务器来下载到线上环境指定路径。

# 直接运行下载预训练模型,本地练习时无需本行代码,直接去掉即可
!wget -P "~/.keras/models" -nc "http://labfile.oss.aliyuncs.com/courses/1283/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5"

加载 Keras 中的预训练网络 ResNet50,且移除最后一层。

resnet_settings = {'include_top': False, 'weights': 'imagenet'}
resnet = ResNet50(**resnet_settings)
resnet.summary()

PS: **resnet_settings:字典解包语法:把字典解包成关键字参数

           *resnet_settings:字典解包语法:把字典解包成函数的位置参数

查看所输入的图片,这是一张浣熊图片。

img = image.array_to_img(face())
img

                      

通过 resize() 方法将图像尺寸调整为(224,224)。

img = img.resize((224, 224))

通过 expand_dims() 方法添加一个额外的维度,以适配网络模型的输入格式,其输入格式为张量形状(batch_size, width, height, n_channels)。

x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
features = resnet.predict(x)
features

上面的结果就是抽取的浣熊图像特征矩阵。 

如果想识别图像上的文字,无需使用复杂的神经网络,使用 pytesseract 库即可完成。首先载入相关库。

!pip install pytesseract  # 安装必要的模块
!sudo apt update
!sudo apt install tesseract-ocr -y
!sudo apt install libtesseract-dev -y

import pytesseract
from PIL import Image
import requests
from io import BytesIO

搜索一张图片并使用 pytesseract 库进行识别。

img = 'https://doc.shiyanlou.com/courses/uid214893-20190430-1556614744119'
img = requests.get(img)
img = Image.open(BytesIO(img.content))
text = pytesseract.image_to_string(img)

打印结果:

text

当然,pytesseract 并不能识别所有图片上的文字。比如,下面一张源自 Renthop 的图片,仅能识别其上的几个单词,还有大部分文字无法识别。

img = requests.get('https://doc.shiyanlou.com/courses/uid214893-20190505-1557033014576')
img = Image.open(BytesIO(img.content))
pytesseract.image_to_string(img)
地理空间数据

地理空间数据相对文本和图像而言并不那么常见,但掌握处理地理空间数据的基本技术仍然是有用的,并且这一领域中有很多相当成熟的解决方案可以直接使用。

地理空间数据常常以地址或坐标(经纬度)的形式保存。根据任务需求的不同,可能需要用到两种互逆的操作:地理编码(由地址重建坐标点)和逆地理编码(由坐标点重建地址)。在实际项目中,这两个操作都可以通过访问外部 API(谷歌地图或 OpenStreetMap)来使用。不同的地理编码器各有其特性,不同地区的编码质量也不一样。幸运的是,GeoPy 之类的通用库封装了这些操作。

如果有大量数据,那么很快便会达到外部 API 的限制。此外,从 HTTP 获取信息并不总是最快的方案。因此,有必要考虑使用本地版的 OpenStreetMap。

如果只有少量的数据,并且不想使用一些新奇的功能,就可以使用 reverse_geocoder 来代替 OpenStreetMap,代码如下。

!pip install reverse_geocoder  # 安装必要模块

import reverse_geocoder as revgc
revgc.search((df.latitude.iloc[0], df.longitude.iloc[0]))

处理地理编码时,别忘了地址可能包含错误值,因此需要清洗数据。坐标的错误值较少,但由于 GPS 噪声或特定地点(比如隧道、商业区)的精确度较低,可能导致坐标不准确。如果数据源是移动设备,地理位置可能不是由 GPS 而是由该区域的 WiFi 网络决定的,这会导致出现空间和远距离传送的 Bug,例如,当你经过曼哈顿时,可能会突然碰到芝加哥的 WiFi 地点,出现错误的坐标信息。

WiFi 的位置追踪功能基于 SSID 和 MAC 地址,同一 SSID 和 MAC 地址可能对应不同的地点,例如,联合供应商标准化 MAC 地址路由,并将其投放于不同城市。甚至一家公司带着路由器搬迁到另一个办公地点都可能造成坐标信息的错误。

地点周边常常有许多基础设施。因此,可以充分发挥想象力,基于生活经验和领域知识自己构建几个特征,如「地点到地铁口的距离」、「建筑物中的商户数」、「到最近的商店的距离」、「周边的 ATM 数目」等。对每个任务都可以很容易的想到几十个特征并从不同的外部资源中获取它们。当地点位于城市以外时,可以考虑从更加专业的数据源获取到的特征,比如海拔。 

如果两个以上的地点相互连接,可能有必要基于地点之间的路由提取特征。比如,距离(直线距离和基于路由图计算得出的道路距离),转弯数(包括左转和右转的比例),红路灯数,交叉路口数,桥梁数。 

日期和时间数据

你可能认为日期和时间是标准化的,因为它们是如此普遍,不过,其中仍然有一些坑。

有些任务可能需要额外的日历特征。比如,现金提取可能与「账单日」相关联;地铁月卡的购买可能和「月初」相关联。一般而言,处理时序数据时,最好有一份包含公众节假日、异常天气情况及其他重要事件的日历。

处理小时和分钟不像看起来那么简单。如果你将小时作为实数变量,那么 0<23,但实际上 0:00:00 02.01>23:00:00 01.01。如果将它们编码为类别变量,那么会生成大量特征,同时丢失时间接近度的信息,即 22 和 23 之间的差异将与 22 和 7 之间的差异相同。

所以,我们可以使用一些更加复杂的方法来处理这些数据,比如将时间投影到圆上,然后使用其 cos 和 sin 值作为两个坐标的值。

def make_harmonic_features(value, period=24):value *= 2 * np.pi / periodreturn np.cos(value), np.sin(value)

这一转换保留了时间点间的距离,对于需要估计距离的算法(kNN、SVM、k-均值等)使用这种方法来处理时间数据会很有帮助。下面计算经这种方法转化后 23 点和 1 点的距离。

from scipy.spatial import distance
euclidean(make_harmonic_features(23), make_harmonic_features(1))

计算 9 点和 11 点的距离

euclidean(make_harmonic_features(9), make_harmonic_features(11))

计算 9 点和 22 点的距离

euclidean(make_harmonic_features(9), make_harmonic_features(22))

上面结果可知,它们之间的距离各不相同,距离信息被保留。

Web 数据

Web 数据通常有用户的 User Agent 信息,这个信息非常重要,首先,从中可以提取操作系统信息。其次,可以据此创建「is_mobile」(是否是移动端)特征。最后,可以通过它查看到浏览器类别。下面看看是如何操作的。

首先,加载相关库和数据。

!pip install user_agents  # 安装所需模块
import user_agentsua = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/56.0.2924.76 Chrome/56.0.2924.76 Safari/537.36'
ua = user_agents.parse(ua)

打印结果。

print('Is a bot? ', ua.is_bot)
print('Is mobile? ', ua.is_mobile)
print('Is PC? ', ua.is_pc)
print('OS Family: ', ua.os.family)
print('OS Version: ', ua.os.version)
print('Browser Family: ', ua.browser.family)
print('Browser Version: ', ua.browser.version)

 除了操作系统和浏览器外,你还可以查看 referrer、Accept-Language 和其他元信息。

 另一个有用的特征是 IP 地址,基于该数据可以提取出国家,乃至城市、网络运营商、连接类型(是否为移动网络)等信息。当然,该特征可能由于代理和数据库过期导致提取出的信息不准确,出现噪声。网络管理专家可能会尝试提取出更专业的信息,比如是否使用 VPN。另外,IP 地址数据和 Accept-Languag 是一对优秀的组合,它们可以互相印证:如果用户的 IP 地址显示在智利,而浏览器的本地化设为 ru_RU(俄罗斯),那么该用户的所在地就不清楚了,我们需要查看对应的特征栏「is_traveler_or_proxy_user」(是旅行者还是代理用户)。

特征转换

对有些算法而言,特征转换是关键,而对另一些算法而言,该转换则毫无帮助。不是所有人都有能力或者愿意去进行特征转换,这是为什么决策树及其变体(随机森林、梯度提升)变得更加流行,因为它们在异常分布上的鲁棒性很好。

标准化和分布变换

最简单的转换是标准缩放(Standard Scaling),又称 Z 值标准化(Z-score normalization):

 

注意,严格意义上说,标准缩放并不生成正态分布,下面验证这一结论,首先载入相关库。

from sklearn.preprocessing import StandardScaler
from scipy.stats import beta
from scipy.stats import shapiro
import numpy as np

使用夏皮罗 - 威尔克检验(Shapiro–Wilk test)查看数据是否符合正态分布,首先输出原数据的检测统计量和假设检验所得的 p 值。

data = beta(1, 10).rvs(1000).reshape(-1, 1)
shapiro(data)

然后输出经标准缩放处理后数据的检测统计量和假设检验所得的 p 值。

shapiro(StandardScaler().fit_transform(data))

夏皮罗 - 威尔克检验计算所得的 p 值说明原数据和经标准缩放处理后的数据都不符合正态分布。

不过,某种程度上而言,标准缩放能为离散值提供一些帮助。下面使用 StandarScaler() 方法对离散值进行标准缩放。

data = np.array([1, 1, 0, -1, 2, 1, 2, 3, -2, 4, 100]).reshape(-1, 1).astype(np.float64)
StandardScaler().fit_transform(data)

也可以直接用公式进行标准缩放。

(data - data.mean()) / data.std()

另一个相当流行的选项是极小极大缩放(MinMax Scaling),将所有数据点纳入一个预先规定的区间(通常是 [0,1])。

 

下面用 MinMaxScaler() 方法进行极小极大缩放。

from sklearn.preprocessing import MinMaxScalerMinMaxScaler().fit_transform(data)

也可以直接用公式进行极小极大缩放。

(data - data.min()) / (data.max() - data.min())

标准缩放和极小极大缩放的应用类似,常常可以互相替换。然而,如果算法涉及计算数据点或向量之间的距离,默认的选项是标准缩放。而在可视化时,极小极大缩放很有用,因为它可以将特征纳入 [0,255] 区间。 

如果某些数据并非正态分布,但可以由  对数正态分布 刻画,那么这些数据很容易就能转换为正态分布,下面生成可以用对数正态分布来刻画的数据,并查看其是否符合正态分布。

from scipy.stats import lognormdata = lognorm(s=1).rvs(1000)
shapiro(data)

上面结果表明生成的原数据不符合正态分布。下面将它进行转换,查看转换后的数据是否符合正态分布。

shapiro(np.log(data))

上述结果表明,转换后的数据符合正态分布。

对数正态分布适用于描述薪水、安保费用、城区人口、网络文章评论等信息。然而,底层分布不一定非得是对数正态分布才能应用这一过程,它可以被应用于任何右重尾的分布。此外,还可以尝试使用其他类似的转换,这类转换的例子包括 Box-Cox 转换(对数转换是 Box-Cox 转换的一个特例)和 Yeo-Johnson 转换(将应用范围扩展至负数)。此外,也可以尝试在特征上加上一个常量:np.log (x + const)。 

在上述例子中处理的都是合成数据,并都使用夏皮罗 - 威尔克检验严格地测试正态分布。下面来处理一些真实数据,并使用分位图(Q-Q plot)测试正态分布,正态分布的分位图看起来像一条平滑的对角线,而异常值可以通过这样的方法被直观地理解。但要注意分位图方法不像夏皮罗 - 威尔克检测那么正式。 

从 Renthop 数据集中获取价格特征,并过滤最极端的值,使画出来的图比较清晰。

price = df.price[(df.price <= 20000) & (df.price > 500)]
price_log = np.log(price)
price_mm = MinMaxScaler().fit_transform(price.values.reshape(-1, 1).astype(np.float64)).flatten()
price_z = StandardScaler().fit_transform(price.values.reshape(-1, 1).astype(np.float64)).flatten()

绘制初始特征分位图。

sm.qqplot(price, loc=price.mean(), scale=price.std())

对原数据应用标准缩放,画出标准缩放后的分位图。

sm.qqplot(price_z, loc=price_z.mean(), scale=price_z.std())

上图可见应用标准缩放后分位图形状并未改变。对原数据应用极小极大缩放,画出分位图。

sm.qqplot(price_mm, loc=price_mm.mean(), scale=price_mm.std())

                                 

 

上图可见,极小极大缩放后分位图形状依旧不变。对原数据取对数,画出分位图。

sm.qqplot(price_log, loc=price_log.mean(), scale=price_log.std())

上图可见对原数据取对数后,数据更接近正态分布。(因为log 会对长尾数据起到“压缩”效果)

相互作用

如果前面的转换看起来更像是由数学驱动的,那这一小节更多地牵涉数据的本质。它既可以算特征转换,也可以算特征创建。

看一个出租房屋的问题,使用的依旧是 Renthop 公司的数据集。该数据集的其中两个特征是「房间数」和「价格」。一般「每间房的价格」比「总价格」具有更多的指示信息,下面生成这一特征。

rooms = df["bedrooms"].apply(lambda x: max(x, .5))
df["price_per_bedroom"] = df["price"] / rooms

在此过程中,要添加一些限制条件。因为如果将特征数限定在一定数目以下,就可以生成所有可能的相互作用,然后使用一些技术去除不必要的特征。此外,并非所有特征的相互作用都有实际意义;比如,线性模型中常用的多项式特征  sklearn.preprocessing.PolynomialFeatures 几乎无法被解释。 

缺失值补全

很多算法无法处理缺失值,而真实数据常常都包含缺失值。幸运的是,Pandas 和 sklearn 都提供了易于使用的解决方案:pandas.DataFrame.fillna 和 sklearn.preprocessing.Imputer

这些解决方案处理缺失值的方式很直接:

  • 将缺失值编码为一个单独的空值,比如,类别变量使用 n/a 值;
  • 使用该特征最可能的值(数值变量使用均值或中位数,类别变量使用最常见的值);
  • 或者,反其道而行之,使用某个极端值(比较适合决策树,因为这样使得决策树模型可以在缺失值和未缺失值间分割);
  • 对于有序数据(列如时序数据),使用相邻值。

有时库提供的解决方案会建议使用固定值,比如 df = df.fillna(0),不再为缺失值浪费时间。然而,这并非最佳方案,因为数据预处理比创建模型花去的时间更多,因此简单的使用固定值可能会埋下隐患,损害模型。

特征选择 

为什么要进行特征选择?下面是两个重要的原因:

  • 数据越多,计算复杂度越高。而在真实的环境中,很容易碰上有数百个额外特征的数据。
  • 部分算法会将噪声(不含信息量的特征)视作信号,导致过拟合。
统计学方法

最先考虑移除的特征就是那些值不变的特征,即不包含信息的特征。沿着这一思路,那些方差较低的特征很可能不如方差较高的特征重要。所以,可以考虑移除方差低于特定阈值的特征。

下面实验一下,首先,生成具有 20 个特征的数据 x_data_generated。

from sklearn.feature_selection import VarianceThreshold
from sklearn.datasets import make_classificationx_data_generated, y_data_generated = make_classification()
x_data_generated.shape

(100, 20)

移除方差低于阈值(0.9)的特征。

VarianceThreshold(.9).fit_transform(x_data_generated).shape

 (100, 14)

可以看到,移除了部分特征。下面对比一下原数据 x_data_generated 和移除部分特征后的数据 x_data_varth。首先载入相关库。

from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score

移除方差低于阈值(0.9)的特征,得到 x_data_varth。

x_data_varth = VarianceThreshold(.9).fit_transform(x_data_generated)

建立逻辑回归模型,在这个模型上对比 x_data_generated 和 x_data_varth。

logit = LogisticRegression(solver='lbfgs', random_state=17)

比较结果。

print(cross_val_score(logit, x_data_generated, y_data_generated,scoring='neg_log_loss', cv=5).mean())
cross_val_score(logit, x_data_varth, y_data_generated,scoring='neg_log_loss', cv=5).mean()

上面结果表明,选取特征提高了分类器的表现,虽然这个例子是使用的合成数据,但在真实问题上依旧值得使用特征选择。

-0.4374637227042332

-0.37363631767701583

建模选取

特征选择的另一种方法是使用某个基线模型评估特征,因为模型会表明特征的重要性。常用的两类模型是:随机森林和搭配 Lasso 正则的线性模型。这种方法的逻辑很简单:如果在简单模型中一些特征明显没用,那就没有必要将它们拖入更复杂的模型。下面实验一下这种方法,首先载入相关库。

from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectFromModel
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import make_pipeline

合成一些数据。

x_data_generated, y_data_generated = make_classification()

建立基线模型。

rf = RandomForestClassifier(n_estimators=10, random_state=17)
pipe = make_pipeline(SelectFromModel(estimator=rf), logit)

比较结果。

print(cross_val_score(logit, x_data_generated, y_data_generated,scoring='neg_log_loss', cv=5).mean())
print(cross_val_score(rf, x_data_generated, y_data_generated,scoring='neg_log_loss', cv=5).mean())
print(cross_val_score(pipe, x_data_generated, y_data_generated,scoring='neg_log_loss', cv=5).mean())

-0.5151377659277452

-0.7201604401301568

-0.4321320632757696

上面结果表明此次建模选取特征改善了模型表现。当然,建模选取也有可能导致模型表现下降。 

网格搜索

最后,介绍最可靠但计算复杂度最高的方法:网格搜索。

在特征子集上训练模型,储存结果,在不同子集上重复这一过程,比较模型的质量以识别最佳特征集,这一方法被称为穷尽特征选取  Exhaustive Feature Selection。

搜索所有组合通常会花去太长的时间,因此可以尝试缩减搜索空间。固定一个较小的数字 N,迭代所有 N 特征的组合,选定最佳组合,接着迭代 N+1 特征组合,其中,之前的最佳组合固定不变,仅仅考虑一个新特征。重复这些迭代过程,直到达到特征最大值,或者直到模型的表现停止明显的提升。这一算法被称为循序特征选取  Sequential Feature Selection。

下面代码通过调用 SequentialFeatureSelector() 方法实现了循序特征选择。

!pip install mlxtend

from mlxtend.feature_selection import SequentialFeatureSelectorselector = SequentialFeatureSelector(logit, scoring='neg_log_loss',verbose=2, k_features=3, forward=False, n_jobs=-1)selector.fit(x_data_generated, y_data_generated)

实验总结 

在机器学习领域,数据集的质量好坏直接决定了所建立的模型性能水平,因此学会数据预处理是十分重要的。本文介绍了特征提取、特征转换、特征选择的基本内容和常用方法,熟悉数据预处理的过程。

 

 

 

 

 

 

 

 

                    

 

 

 

相关文章:

机器学习DAY7: 特征工程和特征选择(数据预处理)(完)

本文通过特征提取、特征转换、特征选择三个过程介绍数据预处理方法&#xff0c;特征提取将原始数据转换为适合建模的特征&#xff0c;特征转换将数据进行变换以提高算法的准确性&#xff0c;特征选择用来删除无用的特征。 知识点 特征提取特征转换特征选择 本次实验的一些示…...

uniapp使用ucharts组件

1.ucharts准备 有两种使用方式&#xff1a;一种是在uni的插件市场下载&#xff08;组件化开发&#xff09;。一种是手动引入ucharts包。官方都封装好组件了&#xff0c;我们不用岂不是浪费。 直接去dcloud插件市场&#xff08;DCloud 插件市场&#xff09;找&#xff0c;第一…...

【RabbitMQ高级篇】消息可靠性问题(1)

目录 1.消息可靠性 1.1.生产者消息确认 1.1.1.修改配置 1.1.2.定义Return回调 1.1.3.定义ConfirmCallback 1.2.消息持久化 1.2.1.交换机持久化 1.2.2.队列持久化 1.2.3.消息持久化 1.3.消费者消息确认 1.3.1.演示none模式 1.3.2.演示auto模式 1.4.消费失败重试机制…...

PR视频剪辑的属性

调整运动效果 选中视频或图品素材在效果控件面板可以看到运动效果的各个参数。 在运动效果中可以调整视频素材的位置、缩放、旋转等属性。 位置属性 PR中素材的位置根据图像锚点的位置决定&#xff0c;由x、y轴的参数控制图像位置。一个1920px1080px的视频素材默认位置是960…...

[数据集][图像分类]常见鱼类分类数据集2w张8类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;7554&#xff08;剩余1w多为测试集&#xff09; 分类类别数&#xff1a;…...

Boost之log日志使用

不讲理论&#xff0c;直接上在程序中可用代码&#xff1a; 一、引入Boost模块 开发环境&#xff1a;Visual Studio 2017 Boost库版本&#xff1a;1.68.0 安装方式&#xff1a;Nuget 安装命令&#xff1a; #只安装下面几个即可 Install-package boost -version 1.68.0 Install…...

Spring Cloud LoadBalancer (负载均衡)

目录 什么是负载均衡 服务端负载均衡 客户端负载均衡 Spring Cloud LoadBalancer快速上手 启动多个product-service实例 测试负载均衡 负载均衡策略 自定义负载均衡策略 什么是负载均衡 负载均衡(Load Balance&#xff0c;简称 LB) , 是高并发, 高可用系统必不可少的关…...

ASP.NET Web应用程序出现Maximum request length exceeded报错

一、问题描述 在ASP.NET的web应用中&#xff0c;导出数据时出现500 - Internal server error.Maximum request length exceeded。 二、原因分析 这个错误通常出现在Web应用程序中&#xff0c;表示客户端发送的HTTP请求的长度超过了服务器配置的最大请求长度限制。这可能是因为…...

Modbus

【欢迎关注编码小哥&#xff0c;学习更多实用的编程方法和技巧】 Modbus 是一种广泛使用的通信协议&#xff0c;主要用于工业自动化和控制系统中。它最初由 Modicon&#xff08;现为施耐德电气的一部分&#xff09;在1979年开发&#xff0c;旨在实现不同设备之间的通信。Modbu…...

【AI资讯汇总】2024年12月第四周

目录 OpenAI发布o3&#xff1a;AI 推理能力的重大突破&#xff0c;得分高达 87.5% 阿里通义千问Qwen开源视觉推理模型QVQ-72B-Preview OpenAI推出ChatGPT新记忆功能:能跨对话回忆用户交流 OpenAI发布ChatGPT宕机故障详细报告&#xff1a;只因一个小更改导致 OpenAI发布o3&a…...

Pytorch使用手册-DCGAN 指南(专题十四)

1. Introduction 本教程将通过一个示例介绍 DCGANs(深度卷积生成对抗网络)。我们将训练一个生成对抗网络(GAN),在给它展示大量真实名人照片后,它能够生成新的“名人”图片。这里的大部分代码来源于 PyTorch 官方示例中的 DCGAN 实现,而本文档将对该实现进行详细解释,并…...

c++---------------------------string

从今天开始我们就开始学c的容器了就不需要我们造轮子了 1.为什么学习string类 1.1c语言中的字符串 C 语言中&#xff0c;字符串是以 \0 结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c; C 标准库中提供了一些 str 系列 的库函数&#xff0c;但是这些库函数与字符…...

PTPVT 插值说明

文章目录 PTPVT 插值说明 PTPVT 插值说明PVT Hermite插值PVT 三次多项式插值PT 插值Sin轨迹测试结果PVT Hermite插值结果PVT 三次多项式插值结果PT 插值结果 用户轨迹测试结果PVT Hermite插值结果PT 插值结果 PTPVT 插值说明 PT模式&#xff1a; 位置-时间路径插值算法。 PVT模…...

Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成Log4j1.x 及 原理分析

文章目录 Pre官网集成Log4j1.x步骤POM依赖使用第一步&#xff1a;编写 Log4j 配置文件第二步&#xff1a;代码 原理分析1. 获取对应的 ILoggerFactory2. 根据 ILoggerFactory 获取 Logger 实例3. 日志记录过程 小结 Pre Java - 日志体系_Apache Commons Logging&#xff08;JC…...

集成RabbitMQ+MQ常用操作

文章目录 1.环境搭建1.Docker安装RabbitMQ1.拉取镜像2.安装命令3.开启5672和15672端口4.登录控制台 2.整合Spring AMQP1.sun-common模块下创建新模块2.引入amqp依赖和fastjson 3.新建一个mq-demo的模块1.在sun-frame下创建mq-demo2.然后在mq-demo下创建生产者和消费者子模块3.查…...

Gitlab17.7+Jenkins2.4.91实现Fastapi/Django项目持续发布版本详细操作(亲测可用)

一、gitlab设置&#xff1a; 1、进入gitlab选择主页在左侧菜单的下面点击管理员按钮。 2、选择左侧菜单的设置&#xff0c;选择网络&#xff0c;在右侧选择出站请求后选择允许来自webhooks和集成对本地网络的请求 3、webhook设置 进入你自己的项目选择左侧菜单的设置&#xff…...

Kubernetes 的资源管理方式(二)

Kubernetes 的资源管理方式 命令式对象配置 命令式对象配置就是通过命令配置和配置文件去操作 Kubernetes 的资源。 命令式对象配置的方式操作资源&#xff0c;可以简单的认为&#xff1a;命令 yaml 配置文件&#xff08;里面是命令需要的各种参数&#xff09;。 ① 创建一…...

一种基于动态部分重构的FPGA自修复控制器

1.FPGA动态部分重构技术 动态部分重构技术指在FPGA运行时&#xff0c;通过加载部分位流文件来修改FPGA可重构区域中的逻辑设计&#xff0c;修改过程中其余逻辑功能不受影响整个系统也能够持续运行。 下图为FPGA动态部分重构的基本原理图。通过下载A1.bit、A2.bit、A3.bit 或A4.…...

MarkItDown的使用(将Word、Excel、PDF等转换为Markdown格式)

MarkItDown的使用&#xff08;将Word、Excel、PDF等转换为Markdown格式&#xff09; 本文目录&#xff1a; 零、时光宝盒&#x1f33b; 一、简介 二、安装 三、使用方法 3.1、使用命令行形式 3.2、用 Python 调用 四、总结 五、参考资料 零、时光宝盒&#x1f33b; &a…...

【Vim Masterclass 笔记01】Section 1:Course Overview + Section 2:Vim Quickstart

文章目录 Section 1&#xff1a;Course Introduction 课程概述S01L01 Course Overview 课程简介课程概要 S01L02 Course Download 课程资源下载S01L03 What Vim Is and Why You Should Learn It 何为 Vim&#xff1f;学来干啥&#xff1f;1 何为 Vim2 为何学 Vim Section 2&…...

BLE core 内容整理解释

本文内容比较杂散&#xff0c;只是做记录使用&#xff0c;后续会整理的有条理些 link layer 基本介绍 **Link Layer Control&#xff08;链路层控制&#xff09;**是蓝牙低功耗&#xff08;BLE&#xff09;协议栈的核心部分&#xff0c;负责实现设备间可靠、安全、低功耗的数…...

import org.springframework.data.jpa.repository.JpaRepository<T, ID>;

org.springframework.data.jpa.repository.JpaRepository<T, ID> 接口中的 ID 类型参数。 理解 JpaRepository<T, ID> 中的 T 和 ID&#xff1a; T (Type): T 代表的是你想要操作的 实体类 的类型。例如&#xff0c;如果你有一个名为 User 的实体类&#xff0c;那…...

抽象工厂设计模式的理解和实践

在软件开发中&#xff0c;设计模式是前人通过大量实践总结出的、可复用的、解决特定问题的设计方案。它们为我们提供了一种标准化的解决方案&#xff0c;使得代码更加简洁、灵活和易于维护。在众多设计模式中&#xff0c;抽象工厂模式&#xff08;Abstract Factory Pattern&…...

RuntimeError: CUDA error: initialization

RuntimeError: CUDA error: initialization cuda初始化出问题了&#xff0c;这是因为在python多线程跑gpu代码程序时先对cuda进行操作&#xff0c;然后在跑gpu代码时就没有cuda可用了。 在main的主程序代码加一行代码就可以了&#xff0c;用来获取cuda&#xff0c;在代码中只能…...

可信数据空间建设及应用参考指南(V1.0)

为贯彻国家数据局《可信数据空间发展行动计划&#xff08;2024-2028 年&#xff09;》&#xff0c;促进可信数据空间持续、快速和健康发展&#xff0c;相关行业专家组织编写《可信数据空间建设及应用参考指南&#xff08;V1.0&#xff09;》&#xff08;以下简称《参考指南》&a…...

目标检测文献阅读-YOLO:统一的实时目标检测(12.23-12.29)

目录 摘要 Abstract 1 引言 2 统一的检测 3 网络设计 4 训练 5 YOLOv5训练猫狗识别模型 5.1 项目代码整体结构介绍 5.2 数据集和预训练权重的准备 5.3 训练猫狗识别模型 5.3.1 修改数据配置文件 5.3.2 修改模型配置文件 5.3.3 训练模型 5.3.4 启用tensorbord查看…...

埃斯顿机器人程序案例多个点位使用变量

多个点位使用变量取放...

JVM实战—4.JVM垃圾回收器的原理和调优

大纲 1.JVM的新生代垃圾回收器ParNew如何工作 2.JVM老年代垃圾回收器CMS是如何工作的 3.线上部署系统时如何设置垃圾回收相关参数 4.新生代垃圾回收参数如何优化 5.老年代的垃圾回收参数如何优化 6.问题汇总 1.JVM的新生代垃圾回收器ParNew如何工作 (1)JVM的核心运行原理…...

【项目日记(8)】第三层:页缓存的具体实现(下)

目录 前言1. 地址空间上的内存使用情况2. 页缓存合并内存的代码实现3. 总结以及对代码的拓展 前言 请先看完上一篇文章页缓存的具体实现(上) 1. 地址空间上的内存使用情况 在地址空间中,一共是4GB大小的空间&#xff0c;地址从0000 0000到FFFF FFFF。 第0页的起始地址是0 第…...

算法题(19):多数元素

审题&#xff1a; 数组不为空且一定存在众数。需要返回众数的数值 思路&#xff1a; 方法一&#xff1a;哈希映射 先用哈希映射去存储对应数据出现的次数&#xff0c;然后遍历找到众数并输出 当然也可以在第一次映射的过程中就维护一个出现次数最多的数据&#xff0c;这样子就可…...

==、equals、hashcode

和equals区别 用于基本数据类型&#xff0c;比较的是值&#xff0c;用于引用类型&#xff0c;比较的是对象的内存地址。java中只有值传递&#xff0c;因此对于引用类型&#xff0c;实际比较的引用的内存地址的值。equals不能用来判断基本数据类型&#xff0c;只能判断引用数据…...

《优势谈判》——阅读笔记

投入 思想准备&#xff1a;一个谈判是要双赢的&#xff0c;至少需要让对手这么认为&#xff1b;进行一场谈判&#xff0c;需要看到对面是否真的愿意和你谈判 谈判技巧 永远不要接受首次报份&#xff1b;如果对方临时变更了要求&#xff0c;则可以通过立刻要求对方做补偿等方…...

mybatis-plus 用法总结

MyBatis-Plus&#xff08;简称 MP&#xff09;是 MyBatis 的增强工具&#xff0c;旨在简化开发者的 CRUD 操作。它在 MyBatis 的基础上提供了更多的功能和便利性&#xff0c;如代码生成器、分页插件、性能分析插件等&#xff0c;使开发者能够更高效地进行数据库操作。MyBatis-P…...

华为开源自研AI框架昇思MindSpore应用案例:ICNet用于实时的语义分割

ICNet用于实时的语义分割 ICNet 被广泛应用于实时的语义分割领域。它在处理图像数据时&#xff0c;能够以较高的效率进行语义分割操作&#xff0c;为相关领域的研究和实际应用提供了有力的支持。ICNet 的实时性使其在众多场景中都具有很大的优势&#xff0c;例如在视频处理、自…...

CAN201 Introduction to Networking(计算机网络)Pt.2 传输层

文章目录 3. Transport Layer&#xff08;传输层&#xff09;3.1 Multiplexing and demultiplexing&#xff08;多路复用和多路分解&#xff09;3.2 Connectionless transport&#xff1a;UDP3.3 Principles of reliable data transfer3.4 Pipelined communication3.5 TCP: con…...

HashMap

一、什么是 基于哈希表的数据结构允许以O(1)的时间复杂度进行元素的插入&#xff0c;查询和删除 二、底层结构 1.数据结构 在1.8以后&#xff0c;数组链表红黑树 数组&#xff1a;HashMap底层是一个数组&#xff0c;每个数组元素存放一个链表或红黑树&#xff08;在JDK 1.…...

JavaScript甘特图 dhtmlx-gantt

背景 需求是在后台中&#xff0c;需要用甘特图去展示管理任务相关视图&#xff0c;并且不用依赖vue&#xff0c;兼容JavaScript原生开发。最终使用dhtmlx-gantt&#xff0c;一个半开源的库&#xff0c;基础功能免费&#xff0c;更多功能付费。 甘特图需求如图&#xff1a; 调…...

基于无线传感器网络的无线光照强度采集系统(附详细使用教程+完整代码+原理图+完整课设报告)

&#x1f38a;项目专栏&#xff1a;【Zigbee课程设计系列文章】&#xff08;附详细使用教程完整代码原理图完整课设报告&#xff09; 前言 &#x1f451;由于无线传感器网络&#xff08;也即是Zigbee&#xff09;作为&#x1f310;物联网工程的一门必修专业课&#xff0c;具有…...

单元测试中创建多个线程测试 ThreadLocal

单元测试中创建多个线程测试 ThreadLocal 在单元测试中&#xff0c;可以通过以下方式创建多个线程来测试 ThreadLocal 的行为。 目标 验证 ThreadLocal 在多线程环境下是否能正确隔离每个线程的数据。 实现步骤 定义需要测试的类 包含 ThreadLocal 对象的类&#xff0c;提供…...

【 Sonarqube】可视化Java项目单元测试覆盖率统计框架搭建

一、项目背景&#xff1a; 一个小公司的朋友反应他们那边Java项目单元测试有&#xff0c;但还没有可视化统计覆盖率数据&#xff0c;没法统计就不能直观的看到单测的覆盖率&#xff0c;Java的覆盖率统计框架还是比较成熟&#xff0c;部署起来也不是很难&#xff0c;下面我们逐…...

安装CentOS(新手教程超详细)

安装CentOS 1. 安装虚拟机 1.1下载虚拟机软件 VMware(VMware by Broadcom - Cloud Computing for the Enterprise) 我们使用的是VMware Workstation VirtualBox(Downloads – Oracle VirtualBox) 如果使用的是Windows系统&#xff0c;下载带for Windows hosts的版本 1.2…...

一起来看--红黑树

【欢迎关注编码小哥&#xff0c;学习更多实用的编程方法和技巧】 红黑树是一种自平衡的二叉搜索树&#xff0c;广泛应用于计算机科学中&#xff0c;尤其是在实现关联数组和集合时。它的设计旨在确保在最坏情况下&#xff0c;基本动态集合操作&#xff08;如插入、删除和查找&am…...

【Hackthebox 中英 Write-Up】通过 POST 请求绕过前端限制:基于 Cookie 的认证与数据提取实操指南

Bypassing Frontend Restrictions with POST Requests: A Practical Guide to Cookie-Based Authentication and Data Extraction 通过 POST 请求绕过前端限制 Objective | 目标 The purpose of this exercise is to understand how POST requests work and how to authentica…...

comctl32.dll没有被指定在window运行怎么解决?

一、文件丢失问题&#xff1a;comctl32.dll没有被指定在Windows上运行怎么解决&#xff1f; comctl32.dll是Windows操作系统中的一个重要组件&#xff0c;它负责提供用户界面元素&#xff0c;如按钮、对话框和列表视图等。当系统提示“comctl32.dll没有被指定在Windows上运行”…...

EC-Final 2024游记

长篇流水账预警 Day -&#xff1f; 某天上乒乓课时看到懋神群里了我们队问有时间打ec吗&#xff0c;才知道我们最终还是进ec了&#xff0c;也成为了我们学校唯一一支没有金牌的ec队伍&#xff0c;然而此时整个队伍板子都扔了&#xff0c;一个多月没做过题&#xff0c;我脑子就…...

我的Opencv

1.安装Opencv pip install opencv-python 2.读取图像 3.写图像 4. 显示图像 5.waitKey() 6.读视频并播放视频 7.写视频 8. 获取摄像头视频 9.色彩转换 # BGR to GRAY imgGRAY cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # BGR to RGB imgRGB cv2.cvtColor(img, cv2.COLOR_…...

Pandas-缺失数据处理

文章目录 一. 简介1. 缺失数据简介2. NaN简介① 查看NaN&#xff0c;NAN&#xff0c;nan② 两个NaN也不相等③ isnull/isna方法④ notnull/notna 二. 加载缺失值1. 来源2. 加载数据&#xff0c;不包含默认缺失值3.加载数据&#xff0c;手动指定缺失值 三.处理缺失值1. 加载数据…...

windows编译llama.cpp GPU版本

Build 指南 https://github.com/ggerganov/llama.cpp/blob/master/docs/build.md 一、Prerequire 具体步骤&#xff08;以及遇到的坑&#xff09;&#xff1a; 如果你要使用CUDA&#xff0c;请确保已安装。 1.安装 最新的 cmake, git, anaconda&#xff0c; pip 配置pyt…...

绝美的数据处理图-三坐标轴-散点图-堆叠图-数据可视化图

clc clear close all %% 读取数据 load(MyColor.mat) %读取颜色包for iloop 1:25 %提取工作表数据data0(iloop) {readtable(data.xlsx,sheet,iloop)}; end%% 解析数据 countzeros(23,14); for iloop 1:25index(iloop) { cell2mat(table2array(data0{1,iloop}(1,1)))};data(i…...

计算机网络500题2024-2025学年度第一学期复习题库(选择、判断、填空)

一、单选题 1、&#xff08; &#xff09;是实现两个同种网络互连的设备 A. 网桥 B. 网关 C. 集线器 D. 路由器 2、10M以太网有三种接口标准&#xff0c;其中10BASE-T采用&#xff08; &#xff09; A. 双绞线 B. 粗同轴电缆 C. 细同轴电缆 D. 光纤 3、HDLC是哪…...