使用Matplotlib的pyplot绘制分隔2个类的决策边界

45 python numpy matplotlib

我真的可以使用提示来帮助我绘制决策边界以分离数据类.我通过Python NumPy创建了一些样本数据(来自高斯分布).在这种情况下,每个数据点是2D坐标,即由2行组成的1列向量.例如,

[ 1
  2 ]
Run Code Online (Sandbox Code Playgroud)

假设我有2个类,class1和class2,我通过下面的代码为class1创建了100个数据点,为class2创建了100个数据点(分配给变量x1_samples和x2_samples).

mu_vec1 = np.array([0,0])
cov_mat1 = np.array([[2,0],[0,2]])
x1_samples = np.random.multivariate_normal(mu_vec1, cov_mat1, 100)
mu_vec1 = mu_vec1.reshape(1,2).T # to 1-col vector

mu_vec2 = np.array([1,2])
cov_mat2 = np.array([[1,0],[0,1]])
x2_samples = np.random.multivariate_normal(mu_vec2, cov_mat2, 100)
mu_vec2 = mu_vec2.reshape(1,2).T
Run Code Online (Sandbox Code Playgroud)

当我绘制每个类的数据点时,它看起来像这样:

在此输入图像描述

现在,我想出了一个决策边界的等式来分离两个类,并希望将它添加到图中.但是,我不确定如何绘制此函数:

def decision_boundary(x_vec, mu_vec1, mu_vec2):
    g1 = (x_vec-mu_vec1).T.dot((x_vec-mu_vec1))
    g2 = 2*( (x_vec-mu_vec2).T.dot((x_vec-mu_vec2)) )
    return g1 - g2
Run Code Online (Sandbox Code Playgroud)

我真的很感激任何帮助!

编辑:直觉(如果我的数学正确)我会期望决定边界在我绘制函数时看起来有点像这条红线...

在此输入图像描述

luc*_*asg 36

你的问题比简单的情节更复杂:你需要画出最大化班级间距离的轮廓.幸运的是,这是一个经过充分研究的领域,特别是对于SVM机器学习.

最简单的方法是下载scikit-learn模块,它提供了很多很酷的方法来绘制边界:http://scikit-learn.org/stable/modules/svm.html

代码:

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib
from matplotlib import pyplot as plt
import scipy
from sklearn import svm


mu_vec1 = np.array([0,0])
cov_mat1 = np.array([[2,0],[0,2]])
x1_samples = np.random.multivariate_normal(mu_vec1, cov_mat1, 100)
mu_vec1 = mu_vec1.reshape(1,2).T # to 1-col vector

mu_vec2 = np.array([1,2])
cov_mat2 = np.array([[1,0],[0,1]])
x2_samples = np.random.multivariate_normal(mu_vec2, cov_mat2, 100)
mu_vec2 = mu_vec2.reshape(1,2).T


fig = plt.figure()


plt.scatter(x1_samples[:,0],x1_samples[:,1], marker='+')
plt.scatter(x2_samples[:,0],x2_samples[:,1], c= 'green', marker='o')

X = np.concatenate((x1_samples,x2_samples), axis = 0)
Y = np.array([0]*100 + [1]*100)

C = 1.0  # SVM regularization parameter
clf = svm.SVC(kernel = 'linear',  gamma=0.7, C=C )
clf.fit(X, Y)
Run Code Online (Sandbox Code Playgroud)

线性图(摘自http://scikit-learn.org/stable/auto_examples/svm/plot_svm_margin.html)


w = clf.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (clf.intercept_[0]) / w[1]

plt.plot(xx, yy, 'k-')
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

MultiLinear Plot(取自http://scikit-learn.org/stable/auto_examples/svm/plot_iris.html)


C = 1.0  # SVM regularization parameter
clf = svm.SVC(kernel = 'rbf',  gamma=0.7, C=C )
clf.fit(X, Y)

h = .02  # step size in the mesh
# create a mesh to plot in
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))


# Plot the decision boundary. For that, we will assign a color to each
# point in the mesh [x_min, m_max]x[y_min, y_max].
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.contour(xx, yy, Z, cmap=plt.cm.Paired)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

履行

如果您想自己实现它,您需要解决以下二次方程: 边界方程

维基百科文章

不幸的是,对于像你绘制的那样的非线性边界,这是一个依赖于核心技巧的难题,但是没有一个明确的解决方案.

  • +1以获得彻底的答案.但是,对于OP的要求,SVM可能有点过分.由于数据来自具有不同均值和协方差的两个正态分布,因此决策边界是二次的.QDA分类器可能就足够了(请参阅http://scikit-learn.org/stable/modules/generated/sklearn.qda.QDA.html). (2认同)

mwa*_*kom 19

根据您编写的方式,decision_boundary您将要使用该contour功能,如上所述Joe.如果您只想要边界线,则可以在0级绘制单个轮廓:

f, ax = plt.subplots(figsize=(7, 7))
c1, c2 = "#3366AA", "#AA3333"
ax.scatter(*x1_samples.T, c=c1, s=40)
ax.scatter(*x2_samples.T, c=c2, marker="D", s=40)
x_vec = np.linspace(*ax.get_xlim())
ax.contour(x_vec, x_vec,
           decision_boundary(x_vec, mu_vec1, mu_vec2),
           levels=[0], cmap="Greys_r")
Run Code Online (Sandbox Code Playgroud)

这使得:

在此输入图像描述


Sau*_*tro 9

您可以为边界创建自己的等式:

在此输入图像描述

在那里你必须找到位置x0y0,以及常量aibi为半径公式.所以,你有2*(n+1)+2变量.使用scipy.optimize.leastsq对于此类问题很简单.

下面附带的代码构建了用于leastsq惩罚超出边界的点的残差.您的问题的结果,获得:

x, y = find_boundary(x2_samples[:,0], x2_samples[:,1], n)
ax.plot(x, y, '-k', lw=2.)

x, y = find_boundary(x1_samples[:,0], x1_samples[:,1], n)
ax.plot(x, y, '--k', lw=2.)
Run Code Online (Sandbox Code Playgroud)

使用n=1: 在此输入图像描述

使用n=2:

在此输入图像描述

使用n=5: 在此输入图像描述

使用n=7:

在此输入图像描述

import numpy as np
from numpy import sin, cos, pi
from scipy.optimize import leastsq

def find_boundary(x, y, n, plot_pts=1000):

    def sines(theta):
        ans = np.array([sin(i*theta)  for i in range(n+1)])
        return ans

    def cosines(theta):
        ans = np.array([cos(i*theta)  for i in range(n+1)])
        return ans

    def residual(params, x, y):
        x0 = params[0]
        y0 = params[1]
        c = params[2:]

        r_pts = ((x-x0)**2 + (y-y0)**2)**0.5

        thetas = np.arctan2((y-y0), (x-x0))
        m = np.vstack((sines(thetas), cosines(thetas))).T
        r_bound = m.dot(c)

        delta = r_pts - r_bound
        delta[delta>0] *= 10

        return delta

    # initial guess for x0 and y0
    x0 = x.mean()
    y0 = y.mean()

    params = np.zeros(2 + 2*(n+1))
    params[0] = x0
    params[1] = y0
    params[2:] += 1000

    popt, pcov = leastsq(residual, x0=params, args=(x, y),
                         ftol=1.e-12, xtol=1.e-12)

    thetas = np.linspace(0, 2*pi, plot_pts)
    m = np.vstack((sines(thetas), cosines(thetas))).T
    c = np.array(popt[2:])
    r_bound = m.dot(c)
    x_bound = popt[0] + r_bound*cos(thetas)
    y_bound = popt[1] + r_bound*sin(thetas)

    return x_bound, y_bound
Run Code Online (Sandbox Code Playgroud)


小智 7

这些都是很棒的建议,非常感谢你的帮助!我最终解析了这个等式,这是我最终得到的解决方案(我只是想发布它以备将来参考:

在此输入图像描述

代码可以在这里找到

编辑:

我还有一个便利功能,用于绘制实现a fitpredict方法的分类器的决策区域,例如scikit-learn中的分类器,如果无法通过分析找到解决方案,这将非常有用.可在此处找到更详细的说明.

在此输入图像描述


小智 6

我喜欢 mglearn 库来划定决策边界。以下是 A. Mueller 所著的《Python 机器学习简介》一书中的一个示例:

fig, axes = plt.subplots(1, 3, figsize=(10, 3))
for n_neighbors, ax in zip([1, 3, 9], axes):
    clf = KNeighborsClassifier(n_neighbors=n_neighbors).fit(X, y)
    mglearn.plots.plot_2d_separator(clf, X, fill=True, eps=0.5, ax=ax, alpha=.4)
    mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)
    ax.set_title("{} neighbor(s)".format(n_neighbors))
    ax.set_xlabel("feature 0")
    ax.set_ylabel("feature 1")
axes[0].legend(loc=3)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述