#使用sklearn来产生数据并给出线性分类

from sklearn import linear_model

from sklearn import datasets

import sklearn

import numpy as np

import matplotlib.pyplot as plt



#显示医疗数据

np.random.seed(0)

#300个数据点,噪声设定0.25

X,y=datasets.make_moons(300,noise=0.25)

#显示产生的医疗数据

plt.scatter(X[:,0],X[:,1],s=50,c=y,edgecolors="Black")



plt.title('Medical data')

# plt.show()



#绘制分类边界函数

def plot_boundary(pred_func,data,labels):

    #pred_func为python的lambda表达式(预测函数)

    #data为输入的数据

    #labels为分类的结果



    #设置最大值和最小值并增加0.5的边界

    x_min,x_max=data[:,0].min()-0.5,data[:,0].max()+0.5

    y_min,y_max=data[:,1].min()-0.5,data[:,1].max()+0.5

    h=0.01 #点阵间距

    #生成一个点阵网格,点阵间距为h

    xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))

    #计算分类结果z

    z=pred_func(np.c_[xx.ravel(),yy.ravel()])

    z=z.reshape(xx.shape)

    #绘制轮廓和训练样本,轮廓颜色Blues,透明度0.2

    plt.contourf(xx,yy,z,cmap=plt.cm.Blues,alpha=0.2)

    plt.scatter(data[:,0],data[:,1],s=40,c=labels,edgecolors="Black")



#对球菌数据进行线性二分类

#使用scikit-learn的线性回归分类器

logistic_fun=sklearn.linear_model.LogisticRegressionCV()

clf=logistic_fun.fit(X,y)

plot_boundary(lambda x:clf.predict(x),X,y)

plt.title('Logistic Regression')

# plt.show()



#建立人工神经网络模型

#定义参数

input_dim=2 #输入的维度

output_dim=2 #输出的维度,分类数

epsilon=0.01 #梯度下降算法的学习率

reg_lambda=0.01 #正则化强度



#损失函数

def calculate_loss(model,X,y):

    num_examples=len(X) #训练集大小

    W1,b1,W2,b2=model['W1'],model['b1'],model['W2'],model['b2']



    #使用正向传播计算预测值

    z1=X.dot(W1)+b1

    a1=np.tanh(z1)

    z2=a1.dot(W2)+b2

    exp_scores=np.exp(z2)

    probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)



    #计算损失值

    correct_logprobs=-np.log(probs[range(num_examples),y])

    data_loss=np.sum(correct_logprobs)



    #对损失值进行归一化

    data_loss+=reg_lambda/2*(np.sum(np.square(W1))+np.sum(np.square(W2)))

    return 1./num_examples*data_loss



def predict(model,x):



    W1,b1,W2,b2=model['W1'],model['b1'],model['W2'],model['b2']



    #向前传播

    z1=x.dot(W1)+b1

    a1=np.tanh(z1)

    z2=a1.dot(W2)+b2

    exp_scores=np.exp(z2)

    probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)

    return np.argmax(probs,axis=1)



def ANN_model(X,y,nn_dim):



    num_indim=len(X) #训练数据集

    model={}



    np.random.seed(0)



    W1=np.random.randn(input_dim,nn_dim)/np.sqrt(input_dim)

    b1=np.zeros((1,nn_dim))

    W2=np.random.randn(nn_dim,output_dim)/np.sqrt(nn_dim)

    b2=np.zeros((1,output_dim))



    #批量梯度下降算法BSGD

    num_passes=20000 #梯度下降迭代次数

    for I in range(0,num_passes):

        #向前传播

        z1=X.dot(W1)+b1

        a1=np.tanh(z1)

        z2=a1.dot(W2)+b2

        exp_scores=np.exp(z2)

        probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)



        #向后传播算法

        delta3=probs

        delta3[range(num_indim),y] -= 1

        delta2=delta3.dot(W2.T)*(1-np.power(a1,2))

        dW2=(a1.T).dot(delta3)

        db2=np.sum(delta3,axis=0,keepdims=True)

        dW1=np.dot(X.T,delta2)

        db1=np.sum(delta2,axis=0)



        dW1 += reg_lambda * W1

        dW2 += reg_lambda * W2



        #更新权重

        W1 += -epsilon * dW1

        b1 += -epsilon * db1

        W2 += -epsilon * dW2

        b2 += -epsilon * db2



        model={'W1':W1,'b1':b1,'W2':W2,'b2':b2}



        if I%1000==0:

            print("Loss after iteration %I:%f",i,calculate_loss(model,X,y))



    return model



hidden_3_model=ANN_model(X,y,3)

plot_boundary(lambda x:predict(hidden_3_model,x),X,y)

plt.title("Hidden Layer size 3")

# plt.show()



#不同隐藏节点数对人工神经网络模型的影响

#定义输出图像的大小

plt.figure(figsize=(16,32))

#待输入的隐藏节点数list

hidden_layer_dimensions=[1,2,3,4,30,50,100,1000]

for I,nn_hdim in enumerate(hidden_layer_dimensions):

    plt.subplot(5,2,i+1)

    plt.title('Hidden Layer size %d'% nn_hdim)

    model=ANN_model(X,y,nn_hdim)

    plot_boundary(lambda x:predict(hidden_3_model,x),X,y)

plt.show()