Python 使用Matplotlib'绘制分隔2个类的决策边界;s曲线图

Python 使用Matplotlib'绘制分隔2个类的决策边界;s曲线图,python,numpy,matplotlib,Python,Numpy,Matplotlib,我真的可以使用一个技巧来帮助我绘制一个决策边界,以分离到数据类。我通过Python NumPy创建了一些样本数据(来自高斯分布)。在这种情况下,每个数据点都是二维坐标,即由2行组成的1列向量。例如: [ 1 2 ] 假设我有两个类,class1和class2,我通过下面的代码为class1创建了100个数据点,为class2创建了100个数据点(分配给变量x1_samples和x2_samples) 当我绘制每个类的数据点时,它将如下所示: import numpy as np impor

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

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

当我绘制每个类的数据点时,它将如下所示:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression

# read data
data = pd.read_csv('ex2data1.txt', header=None)
X = data[[0,1]].values
y = data[2]


# use LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X, y)

# Coefficient of the features in the decision function. (from theta 1 to theta n)
parameters = log_reg.coef_[0]
# Intercept (a.k.a. bias) added to the decision function. (theta 0)
parameter0 = log_reg.intercept_

# Plotting the decision boundary
fig = plt.figure(figsize=(10,7))
x_values = [np.min(X[:, 1] -5 ), np.max(X[:, 1] +5 )]
# calcul y values
y_values = np.dot((-1./parameters[1]), (np.dot(parameters[0],x_values) + parameter0))
colors=['red' if l==0 else 'blue' for l in y]
plt.scatter(X[:, 0], X[:, 1], label='Logistics regression', color=colors)
plt.plot(x_values, y_values, label='Decision Boundary')
plt.show()

现在,我提出了一个用于区分两个类的决策边界方程,并想将其添加到绘图中。但是,我不确定如何绘制此函数:

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
我真的很感激任何帮助

编辑: 直觉上(如果我的数学计算正确的话),当我绘制函数时,我希望决策边界看起来有点像这条红线


你的问题比简单的绘图更复杂:你需要画一个等高线,它将最大化班级间的距离。幸运的是,这是一个研究得很好的领域,特别是对于支持向量机机器学习

最简单的方法是下载模块,该模块提供了许多绘制边界的酷方法:

代码:

# -*- 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)


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

维基百科文章


不幸的是,对于像您绘制的那样的非线性边界,依赖内核技巧是一个困难的问题,但没有明确的解决方案。

根据您编写的
决策(decision)边界
的方式,您需要使用
轮廓
函数,正如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")
这使得:


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

其中必须找到半径方程的位置
x0
y0
,以及常数
ai
bi
。因此,您有
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.)
使用
n=1

使用
n=2

usng
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


这些都是很好的建议,非常感谢你的帮助!我最终解析地解出了这个方程,这就是我最终得到的解(我只想把它贴出来供将来参考:

   def discr_func(x, y, cov_mat, mu_vec):
        """
        Calculates the value of the discriminant function for a dx1 dimensional
        sample given covariance matrix and mean vector.

        Keyword arguments:
            x_vec: A dx1 dimensional numpy array representing the sample.
            cov_mat: numpy array of the covariance matrix.
            mu_vec: dx1 dimensional numpy array of the sample mean.

        Returns a float value as result of the discriminant function.

        """
        x_vec = np.array([[x],[y]])

        W_i = (-1/2) * np.linalg.inv(cov_mat)
        assert(W_i.shape[0] > 1 and W_i.shape[1] > 1), 'W_i must be a matrix'

        w_i = np.linalg.inv(cov_mat).dot(mu_vec)
        assert(w_i.shape[0] > 1 and w_i.shape[1] == 1), 'w_i must be a column vector'

        omega_i_p1 = (((-1/2) * (mu_vec).T).dot(np.linalg.inv(cov_mat))).dot(mu_vec)
        omega_i_p2 = (-1/2) * np.log(np.linalg.det(cov_mat))
        omega_i = omega_i_p1 - omega_i_p2
        assert(omega_i.shape == (1, 1)), 'omega_i must be a scalar'

        g = ((x_vec.T).dot(W_i)).dot(x_vec) + (w_i.T).dot(x_vec) + omega_i
        return float(g)

    #g1 = discr_func(x, y, cov_mat=cov_mat1, mu_vec=mu_vec_1)
    #g2 = discr_func(x, y, cov_mat=cov_mat2, mu_vec=mu_vec_2)

    x_est50 = list(np.arange(-6, 6, 0.1))
    y_est50 = []
    for i in x_est50:
        y_est50.append(scipy.optimize.bisect(lambda y: discr_func(i, y, cov_mat=cov_est_1, mu_vec=mu_est_1) - \
                          discr_func(i, y, cov_mat=cov_est_2, mu_vec=mu_est_2), -10,10))
    y_est50 = [float(i) for i in y_est50]

#随机2D样本数据的2类分类
#从多元正态分布
将numpy作为np导入
从matplotlib导入pyplot作为plt
def决策_边界(x_1):
“”“计算用于绘制决策边界的x_2值。”“”
返回4-np.sqrt(-x_1**2+4*x_1+6+np.log(16))
#生成高斯数据集:
#从多元正态分布创建随机向量
#给定均值和协方差
mu_vec1=np.数组([0,0])
cov_mat1=np.数组([[2,0],[0,2]])
x1_样本=np.随机多变量正态(mu_vec1,cov_mat1,100)
mu_vec1=mu_vec1.将(1,2).T#重塑为1列向量
mu_vec2=np.数组([1,2])
cov_mat2=np.数组([[1,0],[0,1]])
x2样本=np.随机多变量正态(mu_vec2,cov_mat2,100)
mu_vec2=mu_vec2.将(1,2).T#重塑为1列向量
#主散点图和图注记
f、 ax=plt.子批次(figsize=(7,7))
最大散射(x1_样本[:,0],x1_样本[:,1],标记='o',颜色='green',s=40,alpha=0.5)
最大散射(x2_样本[:,0],x2_样本[:,1],标记='^',颜色='blue',s=40,alpha=0.5)
plt.图例(['Class1(w1)''Class2(w2)',loc='右上角')
plt.title('两个类的密度,每个类有25个二元随机模式')
plt.ylabel('x2')
plt.xlabel('x1')
ftext='p(x | w1)~N(mu1=(0,0)^t,cov1=I)\np(x | w2)~N(mu2=(1,1)^t,cov2=I)'
plt.figtext(.15,.8,ftext,fontsize=11,ha='left')
#向绘图添加决策边界
x_1=np.arange(-5,5,0.1)
边界=决策边界(x_1)
plt.plot(x_1,界'r--',lw=3)
x_vec=np.linspace(*ax.get_xlim())
x_1=np.arange(0,100,0.05)
plt.show()
代码可以找到

编辑:

我还有一个方便的功能,用于为实现
fit
predict
方法的分类器绘制决策区域,例如,scikit learn中的分类器,如果无法通过分析找到解决方案,这一功能非常有用。可以找到其工作原理的更详细描述


刚刚用不同的方法(根查找)解决了一个非常类似的问题,并希望将此备选方案作为答案发布在此处,以供将来参考:

   def discr_func(x, y, cov_mat, mu_vec):
        """
        Calculates the value of the discriminant function for a dx1 dimensional
        sample given covariance matrix and mean vector.

        Keyword arguments:
            x_vec: A dx1 dimensional numpy array representing the sample.
            cov_mat: numpy array of the covariance matrix.
            mu_vec: dx1 dimensional numpy array of the sample mean.

        Returns a float value as result of the discriminant function.

        """
        x_vec = np.array([[x],[y]])

        W_i = (-1/2) * np.linalg.inv(cov_mat)
        assert(W_i.shape[0] > 1 and W_i.shape[1] > 1), 'W_i must be a matrix'

        w_i = np.linalg.inv(cov_mat).dot(mu_vec)
        assert(w_i.shape[0] > 1 and w_i.shape[1] == 1), 'w_i must be a column vector'

        omega_i_p1 = (((-1/2) * (mu_vec).T).dot(np.linalg.inv(cov_mat))).dot(mu_vec)
        omega_i_p2 = (-1/2) * np.log(np.linalg.det(cov_mat))
        omega_i = omega_i_p1 - omega_i_p2
        assert(omega_i.shape == (1, 1)), 'omega_i must be a scalar'

        g = ((x_vec.T).dot(W_i)).dot(x_vec) + (w_i.T).dot(x_vec) + omega_i
        return float(g)

    #g1 = discr_func(x, y, cov_mat=cov_mat1, mu_vec=mu_vec_1)
    #g2 = discr_func(x, y, cov_mat=cov_mat2, mu_vec=mu_vec_2)

    x_est50 = list(np.arange(-6, 6, 0.1))
    y_est50 = []
    for i in x_est50:
        y_est50.append(scipy.optimize.bisect(lambda y: discr_func(i, y, cov_mat=cov_est_1, mu_vec=mu_est_1) - \
                          discr_func(i, y, cov_mat=cov_est_2, mu_vec=mu_est_2), -10,10))
    y_est50 = [float(i) for i in y_est50]
结果如下: (蓝色表示二次型,红色表示线性型(等方差)

我知道这个问题已经得到了非常透彻的分析回答。我只是想分享一个可能的“破解”问题。它很难处理,但可以完成任务

首先构建2d区域的网格,然后基于分类器构建整个空间的类地图。随后检测行决策中的变化,并将边缘点存储在列表中,然后绘制散点图

def disc(x):   # returns the class of the point based on location x = [x,y]
     temp = 0.5  + 0.5*np.sign(disc0(x)-disc1(x)) 
# disc0() and disc1() are the discriminant functions of the respective classes
     return 0*temp + 1*(1-temp) 

num = 200
a = np.linspace(-4,4,num)
b = np.linspace(-6,6,num)
X,Y = np.meshgrid(a,b)

def decColor(x,y):
     temp = np.zeros((num,num))
     print x.shape, np.size(x,axis=0)
     for l in range(num):
         for m in range(num):
             p = np.array([x[l,m],y[l,m]])
             #print p
             temp[l,m] = disc(p)
     return temp
boundColorMap = decColor(X,Y)

group = 0
boundary = []
for x in range(num):
    group = boundColorMap[x,0]
    for y in range(num):
        if boundColorMap[x,y]!=group:
            boundary.append([X[x,y],Y[x,y]])
            group = boundColorMap[x,y]  
boundary = np.array(boundary)

我喜欢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)

如果您想使用scikit学习,您可以这样编写代码:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression

# read data
data = pd.read_csv('ex2data1.txt', header=None)
X = data[[0,1]].values
y = data[2]


# use LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X, y)

# Coefficient of the features in the decision function. (from theta 1 to theta n)
parameters = log_reg.coef_[0]
# Intercept (a.k.a. bias) added to the decision function. (theta 0)
parameter0 = log_reg.intercept_

# Plotting the decision boundary
fig = plt.figure(figsize=(10,7))
x_values = [np.min(X[:, 1] -5 ), np.max(X[:, 1] +5 )]
# calcul y values
y_values = np.dot((-1./parameters[1]), (np.dot(parameters[0],x_values) + parameter0))
colors=['red' if l==0 else 'blue' for l in y]
plt.scatter(X[:, 0], X[:, 1], label='Logistics regression', color=colors)
plt.plot(x_values, y_values, label='Decision Boundary')
plt.show()


请参阅:

给定两个双变量正态分布,您可以使用高斯判别分析(GDA)得出决策边界,作为两个pdf的对数之间的差值

这里有一种使用scipy multivariable_normal(代码不是opt)的方法
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression

# read data
data = pd.read_csv('ex2data1.txt', header=None)
X = data[[0,1]].values
y = data[2]


# use LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X, y)

# Coefficient of the features in the decision function. (from theta 1 to theta n)
parameters = log_reg.coef_[0]
# Intercept (a.k.a. bias) added to the decision function. (theta 0)
parameter0 = log_reg.intercept_

# Plotting the decision boundary
fig = plt.figure(figsize=(10,7))
x_values = [np.min(X[:, 1] -5 ), np.max(X[:, 1] +5 )]
# calcul y values
y_values = np.dot((-1./parameters[1]), (np.dot(parameters[0],x_values) + parameter0))
colors=['red' if l==0 else 'blue' for l in y]
plt.scatter(X[:, 0], X[:, 1], label='Logistics regression', color=colors)
plt.plot(x_values, y_values, label='Decision Boundary')
plt.show()
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
from numpy.linalg import norm
from numpy.linalg import inv
from scipy.spatial.distance import mahalanobis

def normal_scatter(mean, cov, p):

  size = 100
  sigma_x = cov[0,0]
  sigma_y = cov[1,1]
  mu_x = mean[0]
  mu_y = mean[1]

  x_ps, y_ps = np.random.multivariate_normal(mean, cov, size).T


  x,y = np.mgrid[mu_x-3*sigma_x:mu_x+3*sigma_x:1/size, mu_y-3*sigma_y:mu_y+3*sigma_y:1/size]
  grid = np.empty(x.shape + (2,))
  grid[:, :, 0] = x; grid[:, :, 1] = y


  z = p*multivariate_normal.pdf(grid, mean, cov)

  return x_ps, y_ps, x,y,z

# Dist 1
mu_1 = np.array([1, 1])
cov_1 = .5*np.array([[1, 0], [0, 1]])
p_1 = .5
x_ps, y_ps, x,y,z = normal_scatter(mu_1, cov_1, p_1)
plt.plot(x_ps,y_ps,'x')
plt.contour(x, y, z, cmap='Blues', levels=3)

# Dist 2
mu_2 = np.array([2, 1])
#cov_2 = np.array([[2, -1], [-1, 1]])
cov_2 = cov_1
p_2 = .5
x_ps, y_ps, x,y,z = normal_scatter(mu_2, cov_2, p_2)
plt.plot(x_ps,y_ps,'.')
plt.contour(x, y, z, cmap='Oranges', levels=3)

# Decision Boundary
X = np.empty(x.shape + (2,))
X[:, :, 0] = x; X[:, :, 1] = y
g = np.log(p_1*multivariate_normal.pdf(X, mu_1, cov_1)) - np.log(p_2*multivariate_normal.pdf(X, mu_2, cov_2))

plt.contour(x, y, g, [0])

plt.grid()
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.plot([mu_1[0], mu_2[0]], [mu_1[1], mu_2[1]], 'k')
plt.show()
W = inv(cov_1).dot(mu_1-mu_2)


x_0 = 1/2*(mu_1+mu_2) - cov_1.dot(np.log(p_1/p_2)).dot((mu_1-mu_2)/mahalanobis(mu_1, mu_2, cov_1))
X = np.empty(x.shape + (2,))
X[:, :, 0] = x; X[:, :, 1] = y

g = (X-x_0).dot(W)
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt


def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):

    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], 
                    y=X[y == cl, 1],
                    alpha=0.8, 
                    c=colors[idx],
                    marker=markers[idx], 
                    label=cl, 
                    edgecolor='black')

    # highlight test samples
    if test_idx:
        # plot all samples
        X_test, y_test = X[test_idx, :], y[test_idx]

        plt.scatter(X_test[:, 0],
                    X_test[:, 1],
                    c='',
                    edgecolor='black',
                    alpha=1.0,
                    linewidth=1,
                    marker='o',
                    s=100, 
                    label='test set')