程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

第九节,线性逻辑回归

一般来说,回归不用在分类问题上,因为回归是连续型模型,而且受噪声影响比较大。如果非要应用进入,可以使用logistic回归。logistic回归本质上是线性回归,只是在特征到结果的映射中加入了一层函数映射,即先把特征线性求和,然后使用函数g(z)函数来预测。

下面介绍一个线性逻辑回归的案例,这里被用来处理二分类和多分类问题。

一 实例描述

假设某肿瘤医院想用神经网络对已有的病例数据进行分类,数据的样本特征包括病人的年龄和肿瘤的大小,对应的标签为病例是良性肿瘤还是恶性肿瘤。

二 二分类问题

1.生成样本集

因为这里没有医院的病例数据,为了方便演示,使用python生成一些模拟数据来替代样本,它应该是二维的数组"年龄,肿瘤大小",generate()函数为生成模拟样本的函数,意思是按照指定的均值和方差生成固定数量的样本。

复制代码
def get_one_hot(labels,num_classes):
    '''
    one_hot编码
    
    args:
        labels : 输如类标签
        num_classes:类别个数
    '''    
    m = np.zeros([labels.shape[0],num_classes])
    for i in range(labels.shape[0]):  
        m[i][labels[i]] = 1
    return m
        
    

def  generate(sample_size,mean,cov,diff,num_classes=2,one_hot = False):
    '''
    因为没有医院的病例数据,所以模拟生成一些样本
    按照指定的均值和方差生成固定数量的样本
    
    args:
        sample_size:样本个数
        mean: 长度为 M 的 一维ndarray或者list  对应每个特征的均值
        cov: N X N的ndarray或者list  协方差  对称矩阵
        diff:长度为 类别-1 的list    每i元素为第i个类别和第0个类别均值的差值 [特征1差,特征2差....]  如果长度不够,后面每个元素值取diff最后一个元素
        num_classes:分类数
        one_hot : one_hot编码
    '''
        
    #每一类的样本数 假设有1000个样本 分两类,每类500个样本    
    sample_per_class = int(sample_size/num_classes)
    
    
    '''
    多变量正态分布
    mean : 1-D array_like, of length N . Mean of the N-dimensional distribution.    数组类型,每一个元素对应一维的平均值
    cov : 2-D array_like, of shape (N, N) .Covariance matrix of the distribution. It must be symmetric and positive-semidefinite 
        for proper sampling.
    size:shape. Given a shape of, for example, (m,n,k), m*n*k samples are generated, and packed in an m-by-n-by-k arrangement.
        Because each sample is N-dimensional, the output shape is (m,n,k,N). If no shape is specified, a single (N-D) sample is 
        returned.
    '''
    #生成均值为mean,协方差为cov sample_per_class x len(mean)个样本 类别为0
    X0 = np.random.multivariate_normal(mean,cov,sample_per_class)    
    Y0 = np.zeros(sample_per_class,dtype=np.int32)
    
    
    #对于diff长度不够进行处理
    if len(diff) != num_classes-1:
        tmp = np.zeros(num_classes-1)
        tmp[0:len(diff)] = diff  
        tmp[len(diff):] = diff[-1]
    else:
        tmp = diff
    
    
    for ci,d  in enumerate(tmp):
        '''
        把list变成 索引-元素树,同时迭代索引和元素本身
        '''
        
        #生成均值为mean+d,协方差为cov sample_per_class x len(mean)个样本 类别为ci+1
        X1 = np.random.multivariate_normal(mean+d,cov,sample_per_class)                
        Y1 = (ci+1)*np.ones(sample_per_class,dtype=np.int32)
                
        #合并X0,X1  按列拼接
        X0 = np.concatenate((X0,X1))
        Y0 = np.concatenate((Y0,Y1))
        
        
    if one_hot:           
        Y0 = get_one_hot(Y0,num_classes)
        
    #打乱顺序
    X,Y  =  shuffle(X0,Y0)
    
    return X,Y
复制代码

下面代码是调用该函数生成100个样本,并将它们可视化

  • 定义水机数的种子值,这样每次运行代码时生成的随机值都是一样的。
  • generate()函数中传入的[3.0]表示两类数据x,y差距是3.0。传入最后一个参数one_hot=False表示不使用one_hot编码。
复制代码
    '''
    生成随机数据
    '''
    np.random.seed(10)
    #特征个数
    num_features = 2
    #样本个数
    num_samples = 100
    #n返回长度为特征的数组 正太分布
    mean = np.random.randn(num_features)
    print('mean',mean)
    cov = np.eye(num_features)
    print('cov',cov)
    X,Y = generate(num_samples,mean,cov,[3.0],num_classes=2)
    #print('X',X)
    #print('Y',Y)
    colors = ['r' if l == 0 else 'b'  for l in Y[:]]
    plt.scatter(X[:,0],X[:,1],c=colors)
    plt.xlabel('Scaled age (in yrs)')
    plt.ylabel('Tumor size (in cm)')
    
    
    #输出维度
    lab_dim = 1
复制代码

 2 构建网络结构

  • 构建网络结构,使用一个神经元,先定义输入、输出两个占位符,然后是w和b的值。
  • 使用sigmoid激活函数。
  • 定义sigmoid交叉熵代价函数。
  • 使用AdamOptimizer优化器。
复制代码
 构建网络结构
    '''

    #构建输入占位符
    input_x = tf.placeholder(dtype = tf.float32,shape = [None,num_features])
    input_y = tf.placeholder(dtype = tf.float32,shape = [None,lab_dim])
    
    #定义学习参数
    W = tf.Variable(tf.truncated_normal(shape=[num_features,lab_dim]),name = 'weight')
    b = tf.Variable(tf.zeros([lab_dim]),name='bias')
    
    
    #定义输出
    output = tf.nn.sigmoid(tf.matmul(input_x,W) + b)
    print(output.get_shape().as_list())
    
    '''
    #定义了两个不同的代价函数
    '''
    #定义sigmoid交叉熵
    cost = tf.reduce_mean( -(input_y*tf.log(output) + (1-input_y)*tf.log(1-output)))
    #最二次代价函数
    loss = tf.reduce_mean(tf.square(input_y - output))
    
    #尽量用这个 收敛速度更快 
    train = tf.train.AdamOptimizer(0.04).minimize(cost)
复制代码

3 训练并可视化显示

复制代码
 #设置参数进行训练
    training_epochs = 50
    batch_size = 32
    
    with tf.Session() as sess:
        #初始化变量
        sess.run(tf.global_variables_initializer())
    
        training_data = list(zip(X,Y))   
        #开始迭代
        for epoch in range(training_epochs):    
            random.shuffle(training_data)    
            mini_batchs = [training_data[k:k+batch_size] for k in range(0,num_samples,batch_size)]
            
            #总的代价
            cost_list = []
            for mini_batch in mini_batchs:
                x_batch = np.asarray([x  for x,y in mini_batch ] ,dtype=np.float32).reshape(-1,num_features)                                                  
                y_batch = np.asarray([y  for x,y in mini_batch ] ,dtype=np.float32).reshape(-1,lab_dim)                                   
                _,lossval = sess.run([train,loss],feed_dict={input_x:x_batch,input_y:y_batch})
                cost_list.append(lossval)
                
        
            print('Epoch {0}  cost  {1}'.format(epoch,np.mean(cost_list)))
            
            
        #绘制z= w1x1 + w2x2 + b = 0的分界线
        x = np.linspace(-1,8,200)
        y = -x*( sess.run(W)[0] / sess.run(W)[1]) - sess.run(b)/sess.run(W)[1]
        plt.plot(x,y,label='Filtted line')
        plt.legend()
        plt.show()
复制代码

由于输入特征个数为两个,所以模型生成的z用公式可以表示成z=w1x1 + w2x2 +b。如果将x1和x2映射映射到直角坐标系中的x和y坐标,那么z就可以被分为大于0和小于0两部分。当z=0时,就代表直线本身。令z=0,就可以将模型转换为如下直线方程:

x2 = -x1*w1/w2 - b/w2   即: y= -x*(w1/w2) - b/w2

线性可分:如上图所示,可以用直线分割的方式解决问题,则可以说这个问题是线性可分的。

三 多分类问题

还是接着上面的例子,这次在数据集中再添加一类样本,可以使用多条直线将数据分成多类。

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(1154)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示