数据挖掘的五大流程
获取数据
从各种来源收集数据,包括但不限于数据库、数据仓库、互联网、传感器、社交媒体等。获取数据的方式可以通过数据抓取、数据爬取、数据采集工具等方法进行。
数据获取是数据挖掘的第一步,关键在于选择合适的数据源、确定需要的数据特征,并采用适当的技术和方法进行数据的提取和整理。
数据预处理
数据预处理是从数据中检测,纠正或删除损坏,不准确或不适用于模型的记录的过程。
可能面对的问题有:数据类型不同,比如有的是文字,有的是数字,有的含时间序列,有的连续,有的间断。
也可能,数据的质量不行,有噪声,有异常,有缺失,数据出错,量纲不一,有重复,数据是偏态,数据量太 大或太小。
数据预处理的目的:让数据适应模型,匹配模型的需求。
特征工程
特征工程是将原始数据转换为更能代表预测模型的潜在问题的特征的过程,可以通过挑选最相关的特征,提取特征以及创造特征来实现。
其中创造特征又经常以降维算法的方式实现。
可能面对的问题有:特征之间有相关性,特征和标签无关,特征太多或太小,或者干脆就无法表现出应有的数据现象或无法展示数据的真实面貌
特征工程的目的:1) 降低计算成本,2) 提升模型上限
建模,测试模型并预测出结果
根据具体的问题和目标,选择适当的建模方法。常用的建模方法包括回归分析、分类分析、聚类分析、关联规则分析等。针对不同的问题,可以使用单一的建模方法,也可以结合多种方法进行建模。
在选择建模方法后,需要将数据集分为训练集和测试集。训练集用于训练模型,测试集用于验证模型的性能和泛化能力。常用的模型评估指标包括准确率、精确率、召回率、F1值等。
在完成模型训练和评估后,可以使用测试集进行模型的预测。预测方法通常是根据已知的输入数据,通过模型得到相应的输出结果。
上线,验证模型效果
数据挖掘上线是指将训练好的模型应用于实际问题中,并验证模型的效果和性能。
上线模型需要考虑以下几个方面:
-
集成模型:将训练好的模型与应用程序或系统进行集成。这可能需要编写代码来将模型嵌入到实际应用程序中,或者将模型部署到云平台或服务器上。
-
数据流程:在上线模型之前,需要确保数据流程的正常运行。这包括确保实时数据流能够正确地输入到模型中,并确保模型的输出能够正确地传递给相关的系统或应用程序。
-
监测和维护:上线后需要监测模型的性能和准确性,以确保模型的稳定性。如果模型的性能出现下降,可能需要重新训练模型或对数据进行更新。
-
反馈和改进:根据实际应用中的反馈和用户需求,进行模型的改进和优化。这可能涉及数据的更新、模型参数的调整等。
scikit-learn 预处理模块介绍
API Reference — scikit-learn 1.4.0 documentation
下面是一些常用的Scikit-learn预处理模块的介绍:
-
StandardScaler:该模块用于将数据进行标准化处理。标准化通过减去均值并除以标准差来对数据进行缩放,使其具有零均值和单位方差。这对于许多机器学习算法和数据分析方法都是必要的。
-
MinMaxScaler:该模块用于将数据进行最小-最大缩放。最小-最大缩放将数据线性地映射到一个特定的范围(通常是[0, 1]),通过减去最小值并除以范围来实现。这种缩放方法适用于需要将数据限定在特定范围内的情况。
-
RobustScaler:该模块用于通过中位数和四分位数来缩放数据。它对于处理存在异常值的数据更具有鲁棒性,因为它使用了中位数和四分位数这些对异常值不敏感的统计量。
-
Normalizer:该模块用于对数据进行归一化处理。归一化是将每个样本的特征向量缩放到单位范数(默认为L2范数)。归一化可以用于计算特征向量的相似性度量。
-
OneHotEncoder:该模块用于对分类变量进行独热编码(One-Hot Encoding)。独热编码将一个具有n个不同值的分类变量转换为一个n维的二进制向量。每个向量只有一个元素为1,表示相应的类别。
这些是Scikit-learn预处理模块的一些常见例子。通过使用这些模块,可以方便地对数据进行常见的预处理操作,以准备好用于训练机器学习模型。
数据预处理
数据无量纲化
数据无量纲化是指将数据进行缩放或转换,使得不同特征之间具有相同的量纲(单位)或范围。在机器学习和数据分析中,数据无量纲化是一个常见的预处理步骤,可以有效地消除不同特征之间的量纲差异,以提高模型的性能和准确性。
数据的无量纲化可以是线性的,也可以是非线性的。线性的无量纲化包括中心化(Zero-centered或者Mean-subtraction)处理和缩放处理(Scale)。中心化的本质是让所有记录减去一个固定值,即让数据样本数据平移到某个位置。缩放的本质是通过除以一个固定值,将数据固定在某个范围之中,取对数也算是一种缩放处理。
数据无量纲化有两种常见的方法:
-
标准化(Normalization):通过减去均值并除以标准差,将数据线性地映射到均值为0,方差为1的分布。标准化使得数据的分布更接近正态分布,适用于需要对数据进行正态化处理的情况。常用的标准化方法有Z-score标准化和最大最小标准化(即区间缩放)。
-
正则化(Normalization):通过将每个样本的特征向量缩放到单位范数,将数据映射到单位球面上。正则化(归一化)可以用于计算特征向量的相似性度量,常用的方法有L1范数和L2范数。
数据无量纲化可以带来以下几个好处:
-
消除不同特征之间的量纲差异,使得不同特征的权重可以更平衡地参与模型的训练和预测。
-
提高模型的收敛速度和稳定性,避免某些特征对模型训练的过度影响。
-
增强模型的泛化能力,使得模型在新的未见过的数据上具备更好的预测性能。
需要注意的是,选择何种数据无量纲化方法应该根据具体问题和数据的分布情况进行选择,并进行适当的实验和评估来确定最佳的预处理方法。
preprocessing.MinMaxScaler
当数据(x)按照最小值中心化后,再按极差(最大值 - 最小值)缩放,数据移动了最小值个单位,并且会被收敛到 [0,1]之间,而这个过程,就叫做数据归一化(Normalization,又称Min-Max Scaling)。注意,Normalization是归 一化,不是正则化,真正的正则化是regularization,不是数据预处理的一种手段。归一化之后的数据服从正态分 布,公式如下:
在scikit-learn当中,我们使用preprocessing.MinMaxScaler来实现这个功能。MinMaxScaler有一个重要参数, feature_range,控制我们希望把数据压缩到的范围,默认是[0,1]。
sklearn.preprocessing.MinMaxScaler — scikit-learn 1.4.0 documentation
from sklearn.preprocessing import MinMaxScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
#如果换成表是什么样子?
import pandas as pd
pd.DataFrame(data)
#实现归一化
scaler = MinMaxScaler() #实例化
# scaler = scaler.fit(data) #fit,在这里本质是生成min(x)和max(x)
# result = scaler.transform(data) #通过接口导出结果
# print('result:', result)
result = scaler.fit_transform(data) #训练和导出结果一步达成
print('result:', result)
inv_result = scaler.inverse_transform(result) #将归一化后的结果逆转
print('inv_result:', inv_result)
#使用MinMaxScaler的参数feature_range实现将数据归一化到[0,1]以外的范围中
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = MinMaxScaler(feature_range=(5,10)) #依然实例化
result = scaler.fit_transform(data) #fit_transform一步导出结果
print('result:', result)
print('data_min_', scaler.data_min_)
print('data_max_', scaler.data_max_)
print('data_range_', scaler.data_range_)
#当X中的特征数量非常多的时候,fit会报错并表示,数据量太大了我计算不了
#此时使用partial_fit作为训练接口
scaler = scaler.partial_fit(data)
result = scaler.fit_transform(data)
print('result:', result)
preprocessing.StandardScaler
当数据(x)按均值(μ)中心化后,再按标准差(σ)缩放,数据就会服从为均值为0,方差为1的正态分布(即标准正态分布),而这个过程,就叫做数据标准化(Standardization,又称Z-score normalization),公式如下:
from sklearn.preprocessing import StandardScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = StandardScaler() #实例化
scaler.fit(data) #fit,本质是生成均值和方差
print('mean_:', scaler.mean_) #查看均值的属性mean_
print('var_:', scaler.var_) #查看方差的属性var_
x_std = scaler.transform(data) #通过接口导出结果
print('mean:', x_std.mean()) #导出的结果是一个数组,用mean()查看均值
print('std:', x_std.std()) #用std()查看方差
print('x_std:', x_std)
scaler.fit_transform(data) #使用fit_transform(data)一步达成结果
scaler.inverse_transform(x_std) #使用inverse_transform逆转标准化
StandardScaler和MinMaxScaler选哪个?
大多数机器学习算法中,会选择StandardScaler来进行特征缩放,因为MinMaxScaler对异常值非常敏感。在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择。
MinMaxScaler在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler将数据压缩于[0,1]区间之中。
建议先试试看StandardScaler,效果不好换MinMaxScaler。
数据中心化是指通过减去数据集的均值,将数据集的中心移动到原点(0,0)。在数据分析和机器学习中,数据中心化是一个常见的预处理步骤,可以消除数据集的偏移,并使得数据分布更加对称和集中。
数据中心化的步骤如下:
计算数据集的均值,即每个特征的平均值。
减去数据集的均值,使得每个特征的平均值变为0。
通过数据中心化,可以实现以下几个目的:
消除数据的偏移:在某些情况下,数据集可能存在偏移,即数据整体的平均值与期望的中心位置不一致。数据中心化通过减去数据集的均值,将数据集的整体平移到中心位置,使得数据更接近原点。
提取数据的变化信息:在某些应用中,我们只关注数据的变化信息,而不关注数据的绝对值。数据中心化可以使得数据集的平均值为0,更容易提取和分析数据的变化信息。
改善数据的可视化效果:数据中心化可以使得数据集的分布更集中,更对称,更容易进行可视化和分析。
需要注意的是,在进行数据中心化时,应该将训练集和测试集分别进行中心化,确保测试数据集的中心和训练数据集的中心保持一致。
除了StandardScaler和MinMaxScaler之外,sklearn中也提供了各种其他缩放处理(中心化只需要一个pandas广播一下减去某个数就好了,因此sklearn不提供任何中心化功能)。比如,在希望压缩数据,却不影响数据的稀疏性时(不影响矩阵中取值为0的个数时),我们会使用MaxAbsScaler;在异常值多,噪声非常大时,我们可能会选用分位数来无量纲化,此时使用RobustScaler。更多详情请参考以下列表:
缺失值
机器学习和数据挖掘中所使用的数据,永远不可能是完美的。很多特征,对于分析和建模来说意义非凡,但对于实际收集数据的人却不是如此,因此数据挖掘之中,常常会有重要的字段缺失值很多,但又不能舍弃字段的情况。因此,数据预处理中非常重要的一项就是处理缺失值。
通过pandas读取采集的数据
import pandas as pd
data = pd.read_csv('./Narrativedata.csv',index_col=0)
data.head()
data.info()
data.describe()
impute.SimpleImputer
API Reference — scikit-learn 1.4.0 documentation
sklearn.impute.SimpleImputer — scikit-learn 1.4.0 documentation
Age = data.loc[:,"Age"].values.reshape(-1,1) #sklearn当中特征矩阵必须是二维
print('Age:', Age[10:20])
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer() #实例化,默认均值填补
imp_median = SimpleImputer(strategy="median") #用中位数填补
imp_0 = SimpleImputer(strategy="constant",fill_value=0) #用0填补
imp_mean = imp_mean.fit_transform(Age) #fit_transform一步完成调取结果
imp_median = imp_median.fit_transform(Age)
imp_0 = imp_0.fit_transform(Age)
print('mean:', imp_mean[10:20])
print('median:', imp_median[10:20])
print('zero:', imp_0[10:20])
#在这里我们使用中位数填补Age
data.loc[:,"Age"] = imp_median
data.info()
#使用众数填补Embarked
Embarked = data.loc[:,"Embarked"].values.reshape(-1,1)
print('Embarked:', Embarked[0:10])
imp_mode = SimpleImputer(strategy = "most_frequent")
data.loc[:,"Embarked"] = imp_mode.fit_transform(Embarked)
print('Embarked:', Embarked[0:10])
data.info()
处理分类型特征:编码与哑变量
在机器学习中,大多数算法,譬如逻辑回归,支持向量机SVM,k近邻算法等都只能够处理数值型数据,不能处理文字,在sklearn当中,除了专用来处理文字的算法,其他算法在fit的时候全部要求输入数组或矩阵,也不能够导入文字型数据(其实手写决策树和普斯贝叶斯可以处理文字,但是sklearn中规定必须导入数值型)。然而在现实 中,许多标签和特征在数据收集完毕的时候,都不是以数字来表现的。比如说,学历的取值可以是["小学",“初中”,“高中”,"大学"],付费方式可能包含["支付宝",“现金”,“微信”]等等。在这种情况下,为了让数据适应算法和 库,我们必须将数据进行编码,即是说,将文字型数据转换为数值型。
preprocessing.LabelEncoder
标签专用,能够将分类转换为分类数值。
sklearn.preprocessing.LabelEncoder — scikit-learn 1.4.0 documentation
from sklearn.preprocessing import LabelEncoder
y = data.iloc[:,-1] #要输入的是标签,不是特征矩阵,所以允许一维
le = LabelEncoder() #实例化
le = le.fit(y) #导入数据
label = le.transform(y) #transform接口调取结果
print('classes_:', le.classes_) #属性.classes_查看标签中究竟有多少类别
print('label:', label[0:20]) #查看获取的结果label
print(le.fit_transform(y)[0:20]) #也可以直接fit_transform一步到位
print(le.inverse_transform(label)[0:20]) #使用inverse_transform可以逆转
data.iloc[:,-1] = label #让标签等于我们运行出来的结果
data.head()
# #如果不需要教学展示的话我会这么写:
# from sklearn.preprocessing import LabelEncoder
# data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1])
preprocessing.OrdinalEncoder
特征专用,能够将分类特征转换为分类数值。
sklearn.preprocessing.OrdinalEncoder — scikit-learn 1.4.0 documentation
from sklearn.preprocessing import OrdinalEncoder
#接口categories_对应LabelEncoder的接口classes_,一模一样的功能
data_ = data.copy()
data_.head()
print('categories_:', OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_)
data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])
data_.head()
preprocessing.OneHotEncoder
独热编码,创建哑变量。
我们前面已经用OrdinalEncoder把分类变量Sex和Embarked都转换成数字对应的类别了。
在舱门Embarked这一 列中,我们使用[0.0,1.0,2.0]代表了三个不同的舱门,然而这种转换是正确的吗?
我们来思考三种不同性质的分类数据:
1) 舱门(S,C,Q) 三种取值S,C,Q是相互独立的,彼此之间完全没有联系,表达的是S≠C≠Q的概念。这是名义变量。
2) 学历(小学,初中,高中) 三种取值不是完全独立的,我们可以明显看出,在性质上可以有高中>初中>小学这样的联系,学历有高低,但是学 历取值之间却不是可以计算的,我们不能说小学 + 某个取值 = 初中。这是有序变量。
3) 体重(>45kg,>90kg,>135kg) 各个取值之间有联系,且是可以互相计算的,比如120kg - 45kg = 90kg,分类之间可以通过数学计算互相转换。这是有距变量。
然而在对特征进行编码的时候,这三种分类数据都会被我们转换为[0.0,1.0,2.0],这三个数字在算法看来,是连续且可以计算的,这三个数字相互不等,有大小,并且有着可以相加相乘的联系。所以算法会把舱门,学历这样的分类特征,都误会成是体重这样的分类特征。这是说,我们把分类转换成数字的时候,忽略了数字中自带的数学性质,所 以给算法传达了一些不准确的信息,而这会影响我们的建模。 类别OrdinalEncoder可以用来处理有序变量,但对于名义变量,我们只有使用哑变量的方式来处理,才能够尽量向算法传达最准确的信息:
这样的变化,让算法能够彻底领悟,原来三个取值是没有可计算性质的,是“有你就没有我”的不等概念。在我们的 数据中,性别和舱门,都是这样的名义变量。因此我们需要使用独热编码,将两个特征都转换为哑变量。
sklearn.preprocessing.OneHotEncoder — scikit-learn 1.4.0 documentation
data.head()
from sklearn.preprocessing import OneHotEncoder
X = data.iloc[:,1:-1]
enc = OneHotEncoder(categories='auto').fit(X)
result = enc.transform(X).toarray()
print('result:', result)
print('result.shape:', result.shape)
print('categories_:', enc.categories_)
#依然可以直接一步到位,但为了给大家展示模型属性,所以还是写成了三步
# OneHotEncoder(categories='auto').fit_transform(X).toarray()
#依然可以还原
pd.DataFrame(enc.inverse_transform(result))
#axis=1,表示跨行进行合并,也就是将量表左右相连,如果是axis=0,就是将量表上下相连
newdata = pd.concat([data,pd.DataFrame(result)],axis=1)
newdata.head()
newdata.drop(["Sex","Embarked"],axis=1,inplace=True)
newdata.columns = ["Age","Survived","Female","Male","Embarked_C","Embarked_Q","Embarked_S"]
newdata.head()
处理连续型特征:二值化与分段
sklearn.preprocessing.Binarizer
根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈 值的值映射为0。默认阈值为0时,特征中所有的正值都映射到1。二值化是对文本计数数据的常见操作,分析人员 可以决定仅考虑某种现象的存在与否。它还可以用作考虑布尔随机变量的估计器的预处理步骤(例如,使用贝叶斯 设置中的伯努利分布建模)。
sklearn.preprocessing.Binarizer — scikit-learn 1.4.0 documentation
#将年龄二值化
data_2 = data.copy()
from sklearn.preprocessing import Binarizer
X = data_2.iloc[:,0].values.reshape(-1,1) #类为特征专用,所以不能使用一维数组
transformer = Binarizer(threshold=30).fit_transform(X)
transformer[0:10]
preprocessing.KBinsDiscretizer
这是将连续型变量划分为分类变量的类,能够将连续型变量排序后按顺序分箱后编码。总共包含三个重要参数:
sklearn.preprocessing.KBinsDiscretizer — scikit-learn 1.4.0 documentation
from sklearn.preprocessing import KBinsDiscretizer
X = data.iloc[:,0].values.reshape(-1,1) # 对年龄进行分箱
X[0:10]
est = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform', subsample=None)
est.fit_transform(X)[0:10]
#查看转换后分的箱:变成了一列中的三箱
set(est.fit_transform(X).ravel())
est = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform', subsample=None)
#查看转换后分的箱:变成了哑变量
est.fit_transform(X).toarray()[0:10]