|
|
10 months ago | |
|---|---|---|
| README.md | 10 months ago | |
README.md
使用python实现线性回归预测,通过梯度下降法实现,数据集为波士顿房价数据集。
In [1] import numpy as np import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt /opt/conda/envs/python35-paddle120-env/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject return f(*args, **kwds) 波士顿房价数据集字段说明
CRIM 房屋所在镇的犯罪率 ZN 面积大于25000年平方英尺住宅所占的比例 INDUS 房屋所在镇非零售区域所占比例 CHAS 房屋是否位于河边,如果位于河边,则值为1,否则值为0 NOX 一氧化氮的浓度 RM 平均房间数量 AGE 1940年前建成房屋所占的比例 DIS 房屋距离波士顿五大就业中心的加权距离 RAD 距离房屋最近的公路 TAX 财产税额度 PTRATI0房屋所在镇师生比例 B 计算公式:1000×(房屋所在镇非美籍人口所在比例-0.63)^2 LSTAT 弱势群体人口所占比例 EDV 房屋的平均价格 In [2] data = pd.read_csv('data/data92436/boston.csv')
data
查看数据的基本信息。同时也可以用来查看各个特征列是否存在缺失值。
data.info()
查看是否具有重复值
data.duplicated().any()
False
In [3]
data.head()
crim zn indus chas nox rm age dis rad tax ptratio
0 0.00632 18.0 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3
1 0.02731 0.0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8
2 0.02729 0.0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8
3 0.03237 0.0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18.7
4 0.06905 0.0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18.7
black lstat medv
0 396.90 4.98 24.0
1 396.90 9.14 21.6
2 392.83 4.03 34.7
3 394.63 2.94 33.4
4 396.90 5.33 36.2
In [4]
class LinearRegression:
'''使用python语言实现线性回归算法。(梯度下降)'''
def __init__(self, alpha, times):
'''初始化方法。
Parameters
-----
alpha : float
学习率。用来控制步长。(权重调整的幅度)
times : int
循环迭代的次数。
'''
self.alpha = alpha
self.times = times
def fit(self, X, y):
'''根据提供的训练数据X,对模型进行训练。
Parameters
------
X : 类数组类型。形状:[样本数量,特征数量]
待训练的样本特征属性。(特征矩阵)。
y : 类数组类型,形状: [样本数量]
目标值(标签信息)。
'''
X = np.asarray(X)
y = np.asarray(y)
# 创建权重的矩阵,初始值为0,长度比特征数量多1。(多出的一个值就是截距)
self.w_ = np.zeros(1 + X.shape[1])
# 创建损失列表,用来保存每次迭代后的损失值。损失值计算: (预测值 - 真实值)的平方和,使得损失值不断减小。
self.loss_ = []
for i in range(self.times):
# 计算预测值
y_hat = np.dot(X, self.w_[1:]) + self.w_[0]
# 计算损失值
error = y - y_hat
self.loss_.append(np.sum(error ** 2) / 2)
# 根据差距调整权重w_,根据公式:调整为 权重(j) = 权重(j) + 学习率 * sum((y - y_hat) * x(j))
self.w_[0] += self.alpha * np.sum(error * 1) # 与截距相乘的x0都为1
self.w_[1:] += self.alpha * np.dot(X.T, error)
def predict(self, X):
'''根据参数传递的样本X,对样本数据进行预测。
Parameters
-----
X : 类数组类型。形状:[样本数量,特征数量]
待预测的样本特征(属性)。
Returns
----
result : 数组类型
预测的结果。
'''
X = np.asarray(X)
result = np.dot(X, self.w_[1:]) + self.w_[0]
return result
In [5]
数据未进行标准化
lr = LinearRegression(alpha=0.005,times=20) t = data.sample(len(data), random_state=0) train_X = t.iloc[:400, :-1] train_y = t.iloc[:400, -1] test_X = t.iloc[400:, :-1] test_y = t.iloc[400:, -1]
lr.fit(train_X, train_y) result = lr.predict(test_X) display(np.mean((result - test_y) ** 2)) display(lr.w_) display(lr.loss_) 2.528374379147838e+234 array([-4.91983295e+111, -2.24266008e+112, -4.88602630e+112, -5.87176682e+112, -3.32127982e+110, -2.77955977e+111, -3.06712887e+112, -3.47971590e+113, -1.79076291e+112, -5.41290922e+112, -2.15392269e+114, -9.17751422e+112, -1.75008714e+114, -6.49730426e+112]) [116831.44, 3.5215413268418916e+16, 1.3578663249157683e+28, 5.2389621806716426e+39, 2.0213194925954355e+51, 7.798744151422259e+62, 3.0089459171760135e+74, 1.1609248049051771e+86, 4.479131362749877e+97, 1.7281582476315742e+109, 6.667656487358543e+120, 2.5725446783790347e+132, 9.925505512774358e+143, 3.8295023799621285e+155, 1.4775155239459885e+167, 5.700615659424077e+178, 2.199436714524765e+190, 8.485963885676548e+201, 3.2740920706402907e+213, 1.26322466504051e+225] 从上面结果就可以看出未进行标准化的数据误差是很大的。
In [6]
对数据进行标准化
class StandardScaler: '''该类对数据进行标准化处理。'''
def fit(self, X):
'''根据传递的样本,计算每个特征值的均值与标准差。
ParameterS
-----
X : 类数组类型
训练数据,用来计算均值与标准差。
'''
X = np.asarray(X)
self.mean_ = np.mean(X, axis=0)
self.std_ = np.std(X, axis=0)
def transform(self, X):
'''对给定的数据X,进行标准化处理。(将X的每一列都变成标准正态分布的数据)
Parameters
-----
result : 类数组类型。
参数X转换成标准正态分布的结果。
'''
return (X - self.mean_) / self.std_
def fit_transform(self, X):
'''对数据进行训练,并转换,返回转换之后的结果。
Parameters
-----
X : 类数组类型。
带转换的数据。
Returns
----
result : 类数组类型。
参数X转换成标准正态分布后的结果。
'''
self.fit(X)
return self.transform(X)
In [7]
为了避免每个特征数量级的不同,从而在梯度下降的过程中带来影响
我们现在考虑对每个特征值进行标准化处理
lr = LinearRegression(alpha=0.0005, times=20) t = data.sample(len(data), random_state=0) train_X = t.iloc[:400, :-1] train_y = t.iloc[:400, -1] test_X = t.iloc[400:, :-1] test_y = t.iloc[400:, -1]
对数据进行标准化处理
s = StandardScaler() train_X = s.fit_transform(train_X) test_X = s.transform(test_X)
s2 = StandardScaler() train_y = s2.fit_transform(train_y) test_y = s2.transform(test_y)
lr.fit(train_X, train_y) result = lr.predict(test_X) display(np.mean((result - test_y) ** 2)) display(lr.w_) display(lr.loss_) 0.203353146171921 array([ 1.45661261e-16, -7.82096101e-02, 3.27417218e-02, -4.18423834e-02, 7.23915815e-02, -1.22422484e-01, 3.18709730e-01, -9.44094559e-03, -2.09320117e-01, 1.04023908e-01, -5.20477318e-02, -1.82216410e-01, 9.76133507e-02, -3.94395606e-01]) [200.0, 107.18106695239439, 88.90466866295792, 79.78035025519532, 74.3187880885867, 70.90417512718284, 68.69155318506807, 67.20013197881178, 66.15079837015878, 65.37902020765745, 64.78625525603303, 64.31246996531246, 63.9204121068791, 63.58650021098897, 63.29547926726484, 63.03724485771134, 62.80493063951664, 62.5937408804752, 62.40022787877571, 62.22183840063286] In [ ]
如果想显示中文的话,可以看这一段,默认情况下,matplotlib不支持中文显示,进行以下设置
设置字体为黑体,以支持中文显示
mpl.rcParams['font.family'] = 'SimHei'
设置在中文字体时,能够正常的显示负号(-)
mpl.rcParams['axes.unicode_minus'] = False In [8] plt.figure(figsize=(10, 10))
绘制预测值
plt.plot(result, 'ro-', label='Predictive value')
绘制真实值
plt.plot(test_y.values, 'go--', label='Actual value') plt.title('Linear regression-Gradient descent') plt.xlabel('Number') plt.ylabel('House price') plt.legend() plt.show()
对数据进行标准化处理
s = StandardScaler() train_X = s.fit_transform(train_X) test_X = s.transform(test_X) s2 = StandardScaler() train_y = s2.fit_transform(train_y) test_y = s2.transform(test_y)
lr.fit(train_X, train_y) result = lr.predict(test_X) display(np.mean((result - test_y) ** 2)) 0.46071758937162166 In [12] plt.scatter(train_X['rm'], train_y)
查看方程系数
display(lr.w_)
构建方程y = -2.78221890e-16 + 6.54984608e-01 * x
x = np.arange(-5, 5, 0.1) y = -2.78221890e-16 + 6.54984608e-01 * x
plt.plot(x, y, 'r')
也可以这样做
plt.plot(x, lr.predict(x.reshape(-1, 1)), 'r') plt.show() array([-3.07753822e-16, 6.54984608e-01])