最简单的例子可能是学习异或运算,这是一个在实数平面上嵌入的最小非线性数据集(4个点)。如何设计一个自然(且非平凡)的核函数来线性分离这些数据?
作为一个更复杂的例子(见Cristianini,《SVM入门》第6.2节),如何设计一个核函数来学习棋盘图案?Cristianini称这张图片是“使用高斯核导出的”,但他使用了多个核函数,并以未指定的方式进行组合和修改。
如果这个问题过于宽泛,无法在此处回答,那么我希望得到一个构建这样一个核函数的参考资料,尽管我更喜欢这个例子相对简单。
问: "如何为学习问题设计核函数?"
答: "非常小心地"
对于想要获得最准确的预测模型的人来说,尝试使用通常的嫌疑人(线性、多项式、RBF)并使用最有效的一个确实是明智的建议。值得一提的是,SVMs经常被批评为似乎有许多需要根据经验调整的参数。所以至少你不是孤单的。
如果你真的想为一个特定的问题设计一个核函数,那么你是对的,这本身就是一个机器学习问题。它被称为“模型选择问题”。我自己在这方面并不是专家,但对我来说,关于核方法最好的洞察力来源是Rasumussen和Williams的书“高斯过程”(它可以在网上免费获取),特别是第4章和第5章。很抱歉我不能说更多,只能说“阅读这本数学丰富的大书”,但这是一个复杂的问题,他们做了一个非常好的解释。
def RBF():
return NP.exp(-gamma * NP.abs(x - y)**2)
在其中,gamma是1 /特征数量(数据集中的列数),而x、y是笛卡尔对。
(径向基函数模块也在scipy.interpolate.Rbf中)
第二,如果你想要构建自己的核函数来解决分类/回归问题,而不仅仅使用现有的核函数,我建议先研究如何选择核函数以及这些函数内部的参数如何影响分类器性能。与SVM/SVC一起常用的小组核函数是最好的起点。该组包括以下内容(除了RBF):
线性核函数
多项式
sigmoid
Z = np.sqrt(np.square(X + Y))
将很好地分离这两组。
顺便提一句,如果你考虑到在这种情况下np.sqrt(np.square(X + Y))
本质上与np.abs(X + Y)
相同,那么Z
与doug的rbf的表述并没有太大的差异。
我无法获取Crisitanini的论文,但我会以类似的方式解决这个问题,从一个玩具版本开始(顺便说一句,棋盘代码要感谢doug):
这里可能的直觉是黑色方块的行和列索引之和始终为偶数,而白色方块的行和列索引之和始终为奇数,因此在这个简单版本中添加类似于(row_index + col_index) % 2
的第三维即可解决问题。在更大、更复杂的棋盘数据集中,比如我在网上找到的这个:
事情并不那么简单,但也许可以级联聚类来找到16个聚类的平均X和Y位置(或许使用medoids clustering),然后应用“模数核技巧”的一个版本?
免责声明,我没有处理过大量分类问题,到目前为止,我发现在制作复杂问题的玩具版本时,通常会获得关于可能有效解决方案的“数字”直觉。
最后,正如在doug的答案评论中发布的那样,我并不认为像他那样采用经验方法研究所有可能内核的性能有任何问题,通过将它们传递给嵌套交叉验证中的网格搜索,并仅更改内核。您可以通过在转换后的特征空间中绘制相应的边距来增加该方法的可靠性:例如,对于rbf,使用Doug提出的方程式(以及Sebastian Raschka的例程这里的cell 13)。
更新于2017年10月27日 在我的slack频道上的一次交谈中,另一位地球物理学家问我,如果XOR门设计为0和1而不是-1和1(后者类似于勘探地球物理学中的经典问题),这种情况会怎样。
如果我要处理XOR门并且没有rbf核的知识,那么在这种情况下,我会将问题转化为这些问题的坐标,并尝试找到一种变换方法。我最初的观察是,O位于x=y
线上,X位于x=-y
线上,因此差异x-y
在一个情况下为0(或略微带有噪声),在另一个情况下为+/-1。绝对值可处理符号,因此Z = np.abs(X-Y)
可以工作。顺便提一下,这非常类似于doug's的rbf = np.exp(-gamma * np.abs(x - y)**2)
(另一个支持他回答的原因);实际上,他的rbf是更通用的解决方案,在所有异或情况下都有效。
我正在寻找一些多项式核函数的实例,偶然发现了这篇文章。如果你还在寻找的话,有几件事情可能会对你有所帮助,比如这个工具包(http://www2.fml.tuebingen.mpg.de/raetsch/projects/shogun),它使用多核学习,你可以选择各种核方法,然后学习将为问题选择最佳方法,因此你不必自己去尝试。
另外一个更简单传统的方法是使用交叉验证和不同的核方法来找到最佳方法。
希望这能对你或其他阅读核方法相关内容的人有所帮助。
XOR问题不是线性可分的,因此例如使用SVM - 使用多项式核函数:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import sklearn
from sklearn.metrics import classification_report
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
# generate the XOR data
## excluding OR
## input_data = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], int)
## output_data = np.array([[0], [1], [1], [0]], int)
##Using the following code, we will create a simple dataset that has the form of an XOR gate using the logical_xor function from NumPy, where 100 samples will be assigned the class label 1 and 100 samples will be assigned the class label -1, respectively:
np.random.seed(0)
X_xor = np.random.randn(200, 2)
y_xor = np.logical_xor(X_xor[:, 0] > 0, X_xor[:, 1] > 0)
y_xor = np.where(y_xor, 1, -1)
plt.scatter(X_xor[y_xor==1, 0], X_xor[y_xor==1, 1],
c='b', marker='x', label='1')
plt.scatter(X_xor[y_xor==-1, 0], X_xor[y_xor==-1, 1],
c='r', marker='x', label='1')
plt.show()
# construct the training and testing split by taking 75% of the data for training
# and 25% for testing
(trainData, testData, trainLabels, testLabels) = train_test_split(X_xor, y_xor, test_size=0.25,
random_state=42)
# train the linear SVM model, evaluate it, and show the results
##print("[RESULTS] SVM w/ Linear Kernel")
##model = SVC(kernel="linear")
##model.fit(trainData, trainLabels)
##print(classification_report(testLabels, model.predict(testData)))
##print("")
# train the SVM + poly. kernel model, evaluate it, and show the results
print("[RESULTS] SVM w/ Polynomial Kernel")
model = SVC(kernel="poly", degree=2, coef0=1)
model.fit(trainData, trainLabels)
print(classification_report(testLabels, model.predict(testData)))
这里注释了线性核 - 可以取消注释以查看错误核使用的结果... 或者可以使用rbf_Kernel(例如这里)- 使用Kernel Trick(在链接中概述为拉格朗日对偶问题)... 还有这里是SVM的几个限制(除了SVM无法在实时数据流中通过新点获得新知识之外 - 与感知器相比 - SVM需要重新学习)
P.S. sklearn仍然似乎是更方便的多类和多标签分类库