如何正确使用scikit-learn的高斯过程进行二维输入、一维输出回归?

26
发布前,我进行了大量搜索并找到了这个问题,可能正是我的问题所在。然而,我尝试了答案中提出的方法,但不幸的是,它没有解决我的问题,由于我是一个新成员,无法添加评论以请求进一步解释。
无论如何,我想在Python中使用scikit-learn中的高斯过程,在一个简单但真实的案例中开始(使用scikit-learn文档中提供的示例)。我有一个名为X的2D输入集(8对2个参数),我有8个相应的输出,收集在1D数组y中。
#  Inputs: 8 points 
X = np.array([[p1, q1],[p2, q2],[p3, q3],[p4, q4],[p5, q5],[p6, q6],[p7, q7],[p8, q8]])

# Observations: 8 couples
y = np.array([r1,r2,r3,r4,r5,r6,r7,r8])

我定义了一个输入测试空间x:
# Input space
x1 = np.linspace(x1min, x1max) #p
x2 = np.linspace(x2min, x2max) #q
x = (np.array([x1, x2])).T

然后我实例化了GP模型,将其拟合到我的训练数据(X,y)上,并在我的输入空间x上进行1D预测y_pred:

from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel as C

kernel = C(1.0, (1e-3, 1e3)) * RBF([5,5], (1e-2, 1e2))
gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=15)
gp.fit(X, y)
y_pred, MSE = gp.predict(x, return_std=True)

然后我制作了一个三维图:

fig = pl.figure()
ax = fig.add_subplot(111, projection='3d')
Xp, Yp = np.meshgrid(x1, x2)
Zp = np.reshape(y_pred,50)

surf = ax.plot_surface(Xp, Yp, Zp, rstride=1, cstride=1, cmap=cm.jet,
linewidth=0, antialiased=False)
pl.show()

这是我的结果:

我得到的结果如下:

RBF[5,5]

当我修改内核参数时,我得到了类似于上面提到的海报的结果:

RBF[10,10]

这些图甚至不能与原始训练点的观察结果匹配(下方响应在[65.1,37]处获得,最高在[92.3,54]处获得)。

我对2D GPs还比较新(也不久开始使用Python),所以我认为我在这里遗漏了什么......任何答案都将有帮助并且非常感激,谢谢!


我也尝试使用GPy和pyGPs,但是由于它们的文档比sklearn稍微少一些,所以我在2D中也没有走得太远。但如果您认为其中一个仍然比scikit-learn更适合我的问题,请告诉我原因!谢谢。 - Julie
2个回答

8

您正在使用两个特征来预测第三个特征。与plot_surface不同,通常最好使用能够显示第三维信息的2D图,例如hist2dpcolormesh。以下是一个完整的示例,其中包含类似于问题中的数据/代码:

from itertools import product
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel as C

X = np.array([[0,0],[2,0],[4,0],[6,0],[8,0],[10,0],[12,0],[14,0],[16,0],[0,2],
                    [2,2],[4,2],[6,2],[8,2],[10,2],[12,2],[14,2],[16,2]])

y = np.array([-54,-60,-62,-64,-66,-68,-70,-72,-74,-60,-62,-64,-66,
                    -68,-70,-72,-74,-76])

# Input space
x1 = np.linspace(X[:,0].min(), X[:,0].max()) #p
x2 = np.linspace(X[:,1].min(), X[:,1].max()) #q
x = (np.array([x1, x2])).T

kernel = C(1.0, (1e-3, 1e3)) * RBF([5,5], (1e-2, 1e2))
gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=15)

gp.fit(X, y)

x1x2 = np.array(list(product(x1, x2)))
y_pred, MSE = gp.predict(x1x2, return_std=True)

X0p, X1p = x1x2[:,0].reshape(50,50), x1x2[:,1].reshape(50,50)
Zp = np.reshape(y_pred,(50,50))

# alternative way to generate equivalent X0p, X1p, Zp
# X0p, X1p = np.meshgrid(x1, x2)
# Zp = [gp.predict([(X0p[i, j], X1p[i, j]) for i in range(X0p.shape[0])]) for j in range(X0p.shape[1])]
# Zp = np.array(Zp).T

fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111)
ax.pcolormesh(X0p, X1p, Zp)

plt.show()

输出:

在此输入图片描述

看起来有点单调,但我的示例数据也是如此。一般来说,您不应该期望获得这么少的数据点特别有趣的结果。

另外,如果您确实想要表面图,您可以将 pcolormesh 行替换为最初的行(或者更多):

ax = fig.add_subplot(111, projection='3d')            
surf = ax.plot_surface(X0p, X1p, Zp, rstride=1, cstride=1, cmap='jet', linewidth=0, antialiased=False)

输出:

在此输入图片描述


(注:该段翻译为中文“输出”)

在上述示例中,您使用相同的超参数初始化(即[5,5])和范围(即(1e-2, 1e2))应用了一个RBF内核,但有两个输入特征。是否有一种方法可以指定仅将输入1输入到一个内核中,而仅将输入2输入到第二个具有不同超参数的内核中? - Mathews24
这种二维输入和一维输入的方式是否也适用于此处提供的支持向量机和相关向量机工具包 https://github.com/JamesRitchie/scikit-rvm ? - HarryS

8

我在使用scikit-learn高斯过程方面也比较新。但经过一些努力,我成功地实现了一个3D高斯过程回归。有很多1维回归的例子,但没有关于更高输入维度的内容。

也许你可以展示一下你正在使用的值。

我发现有时候你发送输入的格式可能会产生一些问题。尝试将输入X格式化为:

X = np.array([param1, param2]).T

并将输出格式化为:
gp.fit(X, y.reshape(-1,1))

此外,据我所知,该实现假设均值函数为m=0。如果您尝试回归的输出呈现出与0显著不同的平均值,您应该对其进行归一化(这可能会解决您的问题)。标准化参数空间也将有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接