网站首页 > 技术文章 正文
本教程的目的是使机器学习数据集可线性分离。本教程分为两部分:
- 特征转换
- 使用Tensorflow训练核分类器
在第一部分中,您将了解核分类器背后的想法,而在第二部分中,您将了解如何使用Tensorflow训练核分类器。您将使用adult 数据集。该数据集的目标是将收入分类为低于和高于50k,了解每家住户的行为。
你为什么需要Kernel?
每个机器学习分类器的目的是正确地预测类。为此,数据集应该是可分的。看看下面的图形; 很容易看出,黑线以上的所有点都属于第一类,其他点属于第二类。然而,人们很少有一个简单的数据集。大多数情况下,数据无法分离。它给像逻辑回归这样的简单分类器带来了困难。
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D x_lin = np.array([1,2,3,4,5,6,7,8,9,10]) y_lin = np.array([2,2,3,2,2,9,6,8,8,9]) label_lin = np.array([0,0,0,0,0,1,1,1,1,1]) fig = plt.figure() ax=fig.add_subplot(111) plt.scatter(x_lin, y_lin, c=label_lin, s=60) plt.plot([-2.5, 10], [12.5, -2.5], 'k-', lw=2) ax.set_xlim([-5,15]) ax.set_ylim([-5,15]) plt.show() <Figure size 640x480 with 1 Axes>
在下图中,我们绘制了一个不可线性分离的数据集。如果我们绘制一条直线,大多数点将不会被归类为正确的类。
解决此问题的一种方法是获取数据集并将数据转换为另一个特征图。
x = np.array([1,1,2,3,3,6,6,6,9,9,10,11,12,13,16,18]) y = np.array([18,13,9,6,15,11,6,3,5,2,10,5,6,1,3,1]) label = np.array([1,1,1,1,0,0,0,1,0,1,0,0,0,1,0,1]) fig = plt.figure() plt.scatter(x, y, c=label, s=60) plt.show()
上图中的数据是二维的,不可分离。您可以尝试以三维方式转换这些数据,这意味着您可以创建一个包含3个轴的图形。
在我们的示例中,我们将应用多项式映射将数据转换为3D维度。转换数据的公式如下。
您可以在Python中定义一个函数来创建新的特征图
您可以使用numpy来编写上面的公式:
### illustration purpose def mapping(x, y): x = np.c_[(x, y)] if len(x) > 2: x_1 = x[:,0]**2 x_2 = np.sqrt(2)*x[:,0]*x[:,1] x_3 = x[:,1]**2 else: x_1 = x[0]**2 x_2 = np.sqrt(2)*x[0]*x[1] x_3 = x[1]**2 trans_x = np.array([x_1, x_2, x_3]) return trans_x
新的映射应该是3维,16点
x_1 = mapping(x, y) x_1.shape (3, 16)
我们分别用3个轴x、y和z绘制一个新图。
# plot fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.scatter(x_1[0], x_1[1], x_1[2], c=label, s=60) ax.view_init(30, 185) ax.set_xlabel('X Label') ax.set_ylabel('Y Label') ax.set_zlabel('Z Label') plt.show()
我们看到了改进,但如果我们改变绘图的方向,很明显数据集现在是可分离的
# plot fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.scatter(x_1[0], x_1[1], x_1[1], c=label, s=60) ax.view_init(0, -180) ax.set_ylim([150,-50]) ax.set_zlim([-10000,10000]) ax.set_xlabel('X Label') ax.set_ylabel('Y Label') ax.set_zlabel('Z Label') plt.show()
要处理大型数据集,您可能必须创建2个以上的维度,使用上述方法将面临一个大问题。实际上,您需要转换所有数据点,这显然是不可行的。这会花费你很长时间,而且你的电脑可能会耗尽内存。
克服此问题的最常见方法是使用kernel 。
什么是kernel ?
这个想法是使用一个高维特征空间的数据几乎线性可分的,如上图所示。
有很多高维空间可以让数据点分离。比如,我们已经证明了多项式映射是个不错的开始。
有大量的数据,这些变换是无效的。相反,您可以使用核函数修改数据,而不需要更改新的特征计划。
kernel 的神奇之处在于找到一种避免高维计算所隐含的所有麻烦的函数。核是一个标量的结果,或者换一种说法我们回到一维空间
找到此函数后,您可以将其插入标准线性分类器。
让我们看一个例子来理解kernel 的概念。你有两个向量,x1和x2 。目标是通过使用多项式映射来创建更高维度。输出等于新特征图的点积。根据上述方法,您需要:
- 将x1和x2变成一个新维度
- 计算点积:所有内核都通用
- 将x1和x2变成一个新维度
您可以使用上面创建的函数来计算更高的维度。
## Kernel x1 = np.array([3,6]) x2 = np.array([10,10]) x_1 = mapping(x1, x2) print(x_1) [[ 9. 100. ] [ 25.45584412 141.42135624] [ 36. 100. ]]
计算点积
你可以用numpy的对象dot来计算在x_1中第一个和第二个向量之间的点积。
print(np.dot(x_1[:,0], x_1[:,1]))
8100.0
输出为8100.您会看到问题,您需要在内存中存储一??个新的特征图来计算点积。如果您有一个包含数百万条记录的数据集,那么它在计算上无效。
相反,你可以用多项式核来计算点积而不用改变矢量。这个函数计算x1和x2的点积,就好像这两个向量被转换成更高的维度。换句话说,核函数从另一个特征空间计算点积的结果。
您可以在Python中编写多项式核函数,如下所示。
def polynomial_kernel(x, y, p=2): return (np.dot(x, y)) ** p
它是两个向量的点积的幂。下面,你返回多项式核的second degree。输出等于另一种方法。这是内核的魔力。
polynomial_kernel(x1, x2, p=2) 8100
核类型
有许多不同的核可用。最简单的是线性核。此函数非常适用于文本分类。另一个核是:
- 多项式内核
- 高斯核
在使用TensorFlow的示例中,我们将使用随机傅立叶。TensorFlow具有用于计算新特征空间的估计器。该函数是高斯核函数的近似值。
该函数计算更高维空间中的数据点之间的相似性。
使用TensorFlow训练核分类器
该算法的目的是对家庭收入大于或小于50k进行分类。
您将评估逻辑回归以获得基准模型。之后,您将训练一个核分类器,看看是否可以获得更好的结果。
您可以使用adult数据集中的以下变量:
- age
- workclass
- fnlwgt
- education
- education_num
- marital
- occupation
- relationship
- race
- sex
- capital_gain
- capital_loss
- hours_week
- native_country
- label
在训练和评估模型之前,您将按照以下步骤操作:
第1步:导入库
你需要导入tensorflow ,pandas和numpy
#import numpy as np from sklearn.model_selection import train_test_split import tensorflow as tf import pandas as pd import numpy as np
第2步:导入数据
您从以下网站下载数据(https://archive.ics.uci.edu/ml/machine-learning-databases/adult/),然后将其作为panda dataframe导入。
## Define path data COLUMNS = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'label'] PATH = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data" PATH_test = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.test" ## Import df_train = pd.read_csv(PATH, skipinitialspace=True, names = COLUMNS, index_col=False) df_test = pd.read_csv(PATH_test,skiprows = 1, skipinitialspace=True, names = COLUMNS, index_col=False)
既然定义了训练和测试集,您可以将标签列从字符串更改为整数。tensorflow不接受标签的字符串值。
label = {'<=50K': 0,'>50K': 1} df_train.label = [label[item] for item in df_train.label] label_t = {'<=50K.': 0,'>50K.': 1} df_test.label = [label_t[item] for item in df_test.label] df_train.shape (32561, 15)
第3步:准备数据
数据集包含连续和分类特征。一个好的做法是标准化连续变量的值。您可以使用sci-kit learn中的StandardScaler 函数。您还可以创建用户定义的函数,以便更轻松地转换训练和测试集。请注意,您将连续变量和分类变量连接到公共数据集,并且数组应该是以下类型:float32
COLUMNS_INT = ['age','fnlwgt','education_num','capital_gain', 'capital_loss', 'hours_week'] CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country'] from sklearn.preprocessing import StandardScaler from sklearn import preprocessing def prep_data_str(df): scaler = StandardScaler() le = preprocessing.LabelEncoder() df_toscale = df[COLUMNS_INT] df_scaled = scaler.fit_transform(df_toscale.astype(np.float64)) X_1 = df[CATE_FEATURES].apply(le.fit_transform) y = df['label'].astype(np.int32) X_conc = np.c_[df_scaled, X_1].astype(np.float32) return X_conc, y
transformer函数准备好了,您可以转换数据集并创建input_fn函数。
X_train, y_train = prep_data_str(df_train) X_test, y_test = prep_data_str(df_test) print(X_train.shape) (32561, 14)
在下一步中,您将训练逻辑回归。它将为您提供基准准确度。目标是使用不同的算法(即核分类器)击败基线。
第4步 :构建逻辑模型:基线模型
使用对象“real_valued_column”构建特征列。它将确保所有变量都是dense 数字数据。
feat_column = tf.contrib.layers.real_valued_column('features', dimension=14)
使用TensorFlow定义估算器Estimator ,指示特征列以及保存图的位置。
estimator = tf.estimator.LinearClassifier(feature_columns=[feat_column], n_classes=2, model_dir = "kernel_log" )
您将使用200的小批量训练logisitc回归。
# Train the model train_input_fn = tf.estimator.inputs.numpy_input_fn( x={"features": X_train}, y=y_train, batch_size=200, num_epochs=None, shuffle=True)
第5步:训练机器学习模型
estimator.train(input_fn=train_input_fn, steps=1000)
第6步:评估机器学习模型
您可以定义numpy估算器来评估模型。您可以使用整个数据集进行评估
# Evaluation test_input_fn = tf.estimator.inputs.numpy_input_fn( x={"features": X_test}, y=y_test, batch_size=16281, num_epochs=1, shuffle=False) estimator.evaluate(input_fn=test_input_fn, steps=1)
您的准确率为82%。在下一节中,您将尝试使用核分类器来击败逻辑分类器
第7步:构造核分类器
核估算器与传统的线性分类器没有太大区别,至少在构造方面如此。背后的想法是使用显式核与线性分类器的强大功能。
您需要在TensorFlow中使用两个预定义的估算器来训练核分类器:
- RandomFourierFeatureMapper
- KernelLinearClassifier
您在第一部分中了解到需要使用内核函数将低维转换为高维。更确切地说,您将使用随机傅立叶,它是高斯函数的近似值。幸运的是,Tensorflow在其库中具有以下函数:RandomFourierFeatureMapper 。可以使用估计器KernelLinearClassifier 训练模型。
要构建机器学习模型,您将按照以下步骤操作:
- A.设置高维核函数
- B.设置L2超参数
- C.建立模型
- D.训练模型
- E.评估模型
步骤A:设置高维核函数
当前数据集包含14个要转换为5维向量的新高维的特征。您可以使用随机傅里叶特征来实现转换。如果您还记得Gaussian Kernel公式,您会注意到要定义的标准差$ \ sigma $参数。该参数控制分类期间采用的相似性度量。
你可以调整RandomFourierFeatureMapper 的所有参数
- input_dim = 14
- output_dim= 5000
- stddev=4
- Prep Kernel
- kernel_mapper = tf.contrib.kernel_methods.RandomFourierFeatureMapper(input_dim = 14,output_dim = 5000,stddev = 4,name ='rffm')
您需要使用之前创建的特征列构建内核映射器: feat_column
### Map Kernel kernel_mappers = {feat_column: [kernel_mapper]}
步骤B:设置L2超参数
为了防止过度拟合,您可以使用L2正则化器来惩罚损失函数。您将L2超参数设置为0.1,将学习速率设置为5
optimizer = tf.train.FtrlOptimizer( learning_rate=5, l2_regularization_strength=0.1)
步骤C:构建模型
下一步类似于线性分类。您使用内置估算器KernelLinearClassifier 。请注意,您添加先前定义的核映射器并更改模型目录。
### Prep estimator estimator_kernel = tf.contrib.kernel_methods.KernelLinearClassifier( n_classes=2, optimizer=optimizer, kernel_mappers=kernel_mappers, model_dir="kernel_train")
步骤D:训练模型
现在构建了内核分类器,您就可以开始训练了
### estimate
estimator_kernel.fit(input_fn=train_input_fn, steps=2000)
步骤E:评估模型
最后,您评估模型的性能。应该能够击败逻辑回归。
# Evaluate and report metrics. eval_metrics = estimator_kernel.evaluate(input_fn=test_input_fn, steps=1)
最终准确度为84%,与逻辑回归相比提高了2%。精度提高和计算成本之间存在权衡。您需要考虑2%的改进是否值得不同分类器消耗的时间,以及它是否会对您的业务产生重大影响。
最后
核是将非线性数据转换为(几乎)线性的一个很好的工具。这种方法的缺点是计算耗时且成本高。
猜你喜欢
- 2024-10-14 Python之Matplotlib数据可视化一:简易线形图
- 2024-10-14 圆:circle-sin-cos动画的matplotlib
- 2024-10-14 python 100天 68 利用Python绘制两个波形正弦sin函数相关性
- 2024-10-14 画直线不简单!python-matplotlib告诉你为什么
- 2024-10-14 用Python下一场流星雨,女生看了都哭了
- 2024-10-14 手把手教你使用Numpy、Matplotlib、Scipy等5个Python库
- 2024-10-14 走进Matplotlib世界(一)(matplotlib.org)
- 2024-10-14 Python 数据分析——matplotlib 坐标变换和注释
- 2024-10-14 利用axe对象绘制地图局部缩放图(下面几种建模对象能通过基本实体工具直接绘制的是)
- 2024-10-14 Python动态绘图的方法(上)(canvas python动态绘图)
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)