• 机器学习——一元线性回归构造直线,并给出损失函数


    目    录

    Question

    问题分析

    1.概念补充

    2.流程分析

    3.注意

    具体实现

    最终成果

    代码

    思考:


    Question

    在二维平面有n个点,如何画一条直线,使得所有点到该直线距离之和最短

    如果能找到,请给出其损失函数

    问题分析

    1.概念补充

    关于损失函数:

    也即代价函数,是一个量化误差的表达式

    参考链接:线性回归与非线性回归:1.0一元线性回归与代价函数(损失函数)_在一元线性回归中,哪个函数不适用于损失函数(-CSDN博客

    本文中我们采用`观测值与实际值差的平方`作为损失函数

    具体原理参考链接:知乎形象举例——梯度下降算法

    下面是MSE函数,但是我这里就没有除以2了,所以偏导应当有一个2倍

    2.流程分析

    对于此问题,我们应当按如下步骤进行求解

    首先,我们需要对于指定初始的k与b初始化该直线

    然后,对学习率(也即步长)和迭代次数进行适当调整

    最后,在得到满意的结果后终止调整,整理结果,给出最终参数

    3.注意

    我们用的并不是直线距离进行损失计算,而是用的△y进行计算,

    但是结果并没有影响,因为经过推倒后,距离d与△y成正比

    具体实现

    本文参考多方资料,使用python代码手写一元线性回归进行求解

    计算当前参数下的最小二乘法结果:

    1. def calcLoseFunction(k,b,XData,YData):
    2. sum=0
    3. for i in range(0,listSize):
    4. # 使用偏离值的平方进行累和
    5. sum+=(YData[i]-(k*XData[i]+b))**2
    6. return sum

    梯度下降法进行搜索:

    1. #梯度下降法
    2. def calcGradientCorrection(b, k, XData, YData, learningRate, bfsNums):
    3. for i in range(0, bfsNums):
    4. sumk, sumb = 0, 0
    5. for j in range(0, listSize):
    6. # 定义预测值Y'
    7. normalNum = k * XData[j] + b
    8. # 计算逆梯度累和
    9. sumk += -(1 / listSize) * (normalNum - YData[j]) * XData[j]
    10. sumb += -(1 / listSize) * (normalNum - YData[j])
    11. # 在逆梯度的方向上进行下一步搜索
    12. k += learningRate * sumk
    13. b += learningRate * sumb
    14. return k, b

    最终成果

    采用随机来对点进行生成,大部分测试较为稳定,模型较为拟合

    但是由于X,Y都进行随机生成,按照期望来说,在100*100的矩阵范围内数据呈现均匀分布

    于是改造Y数据生成方式为:

    YData=[XData[i]+generateRandomInteger(-10,10) for i in range(listSize) ]

    调整初始斜率k=0.5进行测试,最终结果较为拟合,效果较好

    代码

    1. import numpy #发现直接用List就行了
    2. import random
    3. import matplotlib.pyplot as plt
    4. # random.random()
    5. # random.randint(start,stop)
    6. #################全局数据定义区
    7. # 数组大小
    8. listSize=10
    9. # 定义学习率 取尽量小0.001
    10. learningRate=0.0001
    11. #定义初始直线的 斜率k 和 截距b 45° 1单位距离
    12. # 现在设置 k=0.5 检验程序
    13. k,b=0.5,1
    14. #定义迭代次数
    15. bfsNums=9999
    16. #################全局数据定义区END
    17. # 生成随机数
    18. def generateRandomInteger(start, end):
    19. # [1-100]
    20. return random.randint(start, end)
    21. # 打印本次随机生成的X,Y 便于快速粘贴复现
    22. def printXYArray(XData,YData):
    23. # 打印X
    24. print("[", ",".join([str(i) for i in XData]), "]")
    25. # 打印Y
    26. print("[", ",".join([str(i) for i in YData]), "]")
    27. # 最小二乘法定义损失函数 并计算
    28. #参考链接:https://blog.csdn.net/zy_505775013/article/details/88683460
    29. # 求最小二乘法的最小值 最终结果应当是在learningRate一定情况下 这个最小的sum
    30. def calcLoseFunction(k,b,XData,YData):
    31. sum=0
    32. for i in range(0,listSize):
    33. # 使用偏离值的平方进行累和
    34. sum+=(YData[i]-(k*XData[i]+b))**2
    35. return sum
    36. #梯度下降法
    37. def calcGradientCorrection(b, k, XData, YData, learningRate, bfsNums):
    38. for i in range(0, bfsNums):
    39. sumk, sumb = 0, 0
    40. for j in range(0, listSize):
    41. # 定义预测值Y'
    42. normalNum = k * XData[j] + b
    43. # 计算逆梯度累和 注意这里求偏导应当是两倍 不知道为什么写成1了
    44. # 求MSE的偏导
    45. sumk += -(2 / listSize) * (normalNum - YData[j]) * XData[j]
    46. sumb += -(2 / listSize) * (normalNum - YData[j])
    47. # 在逆梯度的方向上进行下一步搜索
    48. k += learningRate * sumk
    49. b += learningRate * sumb
    50. return k, b
    51. # 随机生成横坐标
    52. XData=[generateRandomInteger(1,100) for i in range(listSize) ]
    53. # 随机生成纵坐标
    54. YData=[XData[i]+generateRandomInteger(-10,10) for i in range(listSize) ]
    55. # 纯随机生成 但是可视化效果不直观
    56. # YData=[generateRandomInteger(1,100) for i in range(listSize) ]
    57. # 死值替换区
    58. # XData=testArrayX
    59. # YData=testArrayY
    60. print("初始选取k={},b={}的情况下的损失函数值为sum={}".format(k,b,calcLoseFunction(k,b,XData,YData)))
    61. # 对k,b进行梯度修正
    62. k,b=calcGradientCorrection(b,k,XData,YData,learningRate,bfsNums)
    63. print("修正后:k={},b={},最小损失sum={}".format(k,b,calcLoseFunction(k,b, XData, YData)))
    64. print("调试数组")
    65. printXYArray(XData,YData)
    66. #画图
    67. plt.plot(XData, YData, 'b.')
    68. plt.plot(XData, k*numpy.array(XData)+b, 'r')
    69. plt.show()
    70. print("END")

    思考:

    如果替换在三维空间会怎么样,如何去求?

    答:在三维空间内,我们就需要对三个变量(K1,K2,b)进行偏导求解,然后同样在逆梯度方向上搜索求解。注意要替换对应的损失函数,将直线方程进行替换即可!

  • 相关阅读:
    什么是springMVC-01
    TVS专业术语解读
    Python 学习 Day34
    国内的软件测试真的这么不受待见吗?
    RabbitMQ 之 死信队列
    优炫数据库获“2022能源企业信息化产品技术创新”案例
    现在性价比高的运动耳机有哪些、性价比最高的蓝牙耳机排行榜
    企业微信接口测试实战(一)
    php实战案例记录(7)可变变量$$str
    ROC-RK3588-PC 八核8K人工智能开源主板
  • 原文地址:https://blog.csdn.net/m0_72678953/article/details/133291795