Python-多元線性迴歸方程比較最小二乘法與梯度下降法

最小二乘法是先將方程自變量與因變量化爲係數矩陣X,再求該矩陣的轉置矩陣(X1),接着求矩陣X與他的轉置矩陣的X1的乘積(X2),然後求X2的逆矩陣。最後整合爲係數矩陣W,求解後分別對應截距b、a1、和a2。可見計算一個矩陣的逆是相當耗費時間且複雜的,而且求逆也會存在數值不穩定的情況。
梯度下降法迭代的次數可能會比較多,但是相對來說計算量並不是很大。且其有收斂性保證。故在大數據量的時候,使用梯度下降法比較好。

梯度下降法

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

data = np.genfromtxt('test.csv',delimiter=',')
x_data = data[:,:-1]
y_data = data[:,2]

#定義學習率、斜率、截據
#設方程爲y=a1x1+a2x2+a0
lr = 0.00001
a0 = 0
a1 = 0
a2 = 0
#定義最大迭代次數,因爲梯度下降法是在不斷迭代更新k與b
epochs = 10000
#定義最小二乘法函數-損失函數(代價函數)
def compute_error(a0,a1,a2,x_data,y_data):
    totalerror = 0
    for i in range(0,len(x_data)):#定義一共有多少樣本點
        totalerror = totalerror+(y_data[i]-(a1*x_data[i,0]+a2*x_data[i,1]+a0))**2
    return totalerror/float(len(x_data))/2
#梯度下降算法求解參數
def gradient_descent_runner(x_data,y_data,a0,a1,a2,lr,epochs):
    m = len(x_data)
    for i in range(epochs):
        a0_grad = 0
        a1_grad = 0
        a2_grad = 0
        for j in range(0,m):
            a0_grad -= (1/m)*(-(a1*x_data[j,0]+a2*x_data[j,1]+a2)+y_data[j])
            a1_grad -= (1/m)*x_data[j,0]*(-(a1*x_data[j,0]+a2*x_data[j,1]+a0)+y_data[j])
            a2_grad -= (1/m)*x_data[j,1]*(-(a1*x_data[j,0]+a2*x_data[j,1]+a0)+y_data[j])
        a0 = a0-lr * a0_grad
        a1 = a1-lr * a1_grad
        a2 = a2-lr * a2_grad
    return a0,a1,a2

#進行迭代求解
a0,a1,a2 = gradient_descent_runner(x_data,y_data,a0,a1,a2,lr,epochs)
print('結果:迭代次數:{0} 學習率:{1}之後 a0={2},a1={3},a2={4},代價函數爲{5}'.format(epochs,lr,a0,a1,a2,compute_error(a0,a1,a2,x_data,y_data)))
print("多元線性迴歸方程爲:y=",a1,"X1",a2,"X2+",a0)

#畫圖
ax = plt.figure().add_subplot(111,projection='3d')
ax.scatter(x_data[:,0],x_data[:,1],y_data,c='r',marker='o')
x0 = x_data[:,0]
x1 = x_data[:,1]

#生成網格矩陣
x0,x1 = np.meshgrid(x0,x1)
z = a0+a1*x0+a2*x1

#畫3d圖
ax.plot_surface(x0,x1,z)
ax.set_xlabel('area')
ax.set_ylabel('distance')
ax.set_zlabel("Monthly turnover")
plt.show()

結果如下:
在這裏插入圖片描述

最小二乘法

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
%matplotlib inline

data = np.genfromtxt("test.csv",delimiter=",") #導入.csv文件數據
X1 = data[0:10,0] #自變量1
X2 = data[0:10,1] #自變量2
Y = data[0:10,2] #因變量銷售量

Y1 = np.array([Y]).T #將因變量賦值給矩陣Y1
X11 = np.array([X1]).T #爲自變量係數矩陣X賦值
X22 = np.array([X2]).T
A = np.array([[1],[1],[1],[1],[1],[1],[1],[1],[1],[1]]) #創建係數矩陣
B = np.hstack((A,X11)) #將矩陣a與矩陣X11合併爲矩陣b
X = np.hstack((B,X22)) #將矩陣b與矩陣X22合併爲矩陣X

X7 = X.T #矩陣X的轉置矩陣
X8 = np.dot(X7,X) #求矩陣X與他的轉置矩陣的X7(X的轉置矩陣)的乘積
X9 = np.linalg.inv(X8) #X8的逆矩陣
W = np.dot(np.dot((X9),(X7)),Y1) #求解係數矩陣W,分別對應截距b、a1、和a2
b = W[0][0]
a1 = W[1][0]
a2 = W[2][0]
print("係數a1=",a1)
print("係數a2=",a2)
print("截距爲=",b)
print("多元線性迴歸方程爲:y=",a1,"X1+",a2,"X2+",b)

#畫出線性迴歸分析圖
data1 = pd.read_excel('test.xlsx') #導入.xlsx文件數據
sns.pairplot(data1, x_vars=['area','distance'], y_vars='Y', height=3, aspect=0.8, kind='reg')  
plt.show() 
#求月銷售量Y的和以及平均值y1
sumy = 0 #因變量的和
y1 = 0 #因變量的平均值
for i in range(0,len(Y)):
    sumy=sumy+Y[i]
y1=sumy/len(Y)
#求月銷售額y-他的平均值的和
y_y1 = 0# y-y1的值的和
for i in range(0,len(Y)):
    y_y1 = y_y1+(Y[i]-y1)
print("銷售量-銷售量平均值的和爲:",y_y1)
#求預測值sales1
sales1 = []
for i in range(0,len(Y)):
    sales1.append(a1*X1[i]+a2*X2[i]+b)
#求預測值的平均值y2
y2 = 0
sumy2 = 0
for i in range(len(sales1)):
    sumy2 = sumy2+sales1[i]
y2 = sumy2/len(sales1)
#求預測值-平均值的和y11_y2
y11_y2=  0
for i in range(0,len(sales1)):
   y11_y2 = y11_y2+(sales1[i]-y2)
print("預測銷售值-預測銷售平均值的和爲:",y11_y2)
#求月銷售額y-他的平均值的平方和
Syy = 0#y-y1的值的平方和
for i in range(0,len(Y)):
    Syy = Syy+((Y[i]-y1)*(Y[i]-y1))
print("Syy=",Syy)
#求y1-y1平均的平方和
Sy1y1 = 0
for i in range(0,len(sales1)):
    Sy1y1=Sy1y1+((sales1[i]-y2)*(sales1[i]-y2))
print("Sy1y1=",Sy1y1)
#(y1-y1平均)*(y-y平均)
Syy1 = 0
for i in range(0,len(sales1)):
    Syy1 = Syy1+((Y[i]-y1)*(sales1[i]-y2))
print("Syy1=",Syy1)
#求R值
R = Syy1/((Syy*Sy1y1)**0.5)
R2 = R*R
print("判定係數R2=",R2)

結果如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章