文章目录
前言
入门机器学习,记录学习日常,如有错误请多指正。
参考书目:机器学习及Python应用
一、数据处理
1.数据介绍
案例采用波士顿房价数据, 它包含了波士顿地区1970年房价的中位数与各种影响房价的因素。数据集共有506个数据点,每个数据点包含14个属性,其中13个是数值型特征,如城镇人均犯罪率、住宅用地比例等,以及一个目标变量即房价(MEDV)。
波士顿房价数据集的属性包括:
CRIM:城镇人均犯罪率
ZN:住宅用地超过25000平方英尺的比例
INDUS:城镇非零售商用土地的比例
CHAS:查尔斯河虚拟变量(如果边界是河流,则为1;否则为0)
NOX:一氧化氮浓度
RM:住宅平均房间数
AGE:1940年之前建成的自用房屋比例
DIS:到五个波士顿就业中心的加权距离
RAD:辐射性公路的接近指数
TAX:每10000美元的全值财产税率
PTRATIO:城镇师生比例
B:1000*(Bk - 0.63)^2,其中Bk为城镇中黑人的比例
LSTAT:人口中地位较低人群的百分比
MEDV:自有住房的中位数价值(单位:千美元)
2.导入模块和数据文件
导入所需模块
import pandas as pd
import numpy as np
import statsmodels.formula.api as smf
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error,r2_score
由于sklearn中调用boston数据函数load_boston()已被移除,使用以下方式载入数据(代码繁琐是因为"http://lib.stat.cmu.edu/datasets/boston"中数据排列不整齐)。
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)#skiprows=22表示跳过前22行数据
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])#自变量
'''
data是一个NumPy数组,是通过水平叠加(np.hstack)raw_df 中的数据而创建的。在这个操作中,选择了raw_df 中的
奇数行(raw_df.values[::2, :])和偶数行的前两列(raw_df.values[1::2, :2])并将它们水平叠加在一起.
[::2, :]表示从开始到结束步长为2;[1::2, :2]表示从1开始步长为2
'''
target = raw_df.values[1::2, 2]#引入Boston房价数据
boston = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :3]])
names = ["CRIM", "ZN", "INDUS", "CHAS", "NOX", "RM", "AGE", "DIS", "RAD", "TAX", "PTRATIO", "B", "LSTAT", "MEDV"]
Boston=pd.DataFrame(boston,columns=names)#数据框化,数据与变量名匹配
3.数据概况
1)使用info()考察数据信息
print(Boston.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 506 entries, 0 to 505
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 CRIM 506 non-null float64
1 ZN 506 non-null float64
2 INDUS 506 non-null float64
3 CHAS 506 non-null float64
4 NOX 506 non-null float64
5 RM 506 non-null float64
6 AGE 506 non-null float64
7 DIS 506 non-null float64
8 RAD 506 non-null float64
9 TAX 506 non-null float64
10 PTRATIO 506 non-null float64
11 B 506 non-null float64
12 LSTAT 506 non-null float64
13 MEDV 506 non-null float64
dtypes: float64(14)
memory usage: 55.5 KB
2)考察数据框前5个观测值:
print(Boston.head())
前5行: CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX \
0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0
1 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0
2 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0
3 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0
4 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0
PTRATIO B LSTAT MEDV
0 15.3 396.90 4.98 24.0
1 17.8 396.90 9.14 21.6
2 17.8 392.83 4.03 34.7
3 18.7 394.63 2.94 33.4
4 18.7 396.90 5.33 36.2
3)考察此数据库统计特征:
print(Boston.describe())#统计特征
CRIM ZN INDUS CHAS NOX RM \
count 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000
mean 3.613524 11.363636 11.136779 0.069170 0.554695 6.284634
std 8.601545 23.322453 6.860353 0.253994 0.115878 0.702617
min 0.006320 0.000000 0.460000 0.000000 0.385000 3.561000
25% 0.082045 0.000000 5.190000 0.000000 0.449000 5.885500
50% 0.256510 0.000000 9.690000 0.000000 0.538000 6.208500
75% 3.677083 12.500000 18.100000 0.000000 0.624000 6.623500
max 88.976200 100.000000 27.740000 1.000000 0.871000 8.780000
AGE DIS RAD TAX PTRATIO B \
count 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000
mean 68.574901 3.795043 9.549407 408.237154 18.455534 356.674032
std 28.148861 2.105710 8.707259 168.537116 2.164946 91.294864
min 2.900000 1.129600 1.000000 187.000000 12.600000 0.320000
25% 45.025000 2.100175 4.000000 279.000000 17.400000 375.377500
50% 77.500000 3.207450 5.000000 330.000000 19.050000 391.440000
75% 94.075000 5.188425 24.000000 666.000000 20.200000 396.225000
max 100.000000 12.126500 24.000000 711.000000 22.000000 396.900000
LSTAT MEDV
count 506.000000 506.000000
mean 12.653063 22.532806
std 7.141062 9.197104
min 1.730000 5.000000
25% 6.950000 17.025000
50% 11.360000 21.200000
75% 16.955000 25.000000
max 37.970000 50.000000
二. 线性回归
1.进行一元回归
1)将房价中位数MEDV对房间数RM进行一元回归:
model=smf.ols('MEDV~RM',data=Boston)#一元回归
'''
此命令生成了smf.ols类的一个实例model,并通过公式'MEDV~RM',指定把数据框Boston的MEDV对RM进行回归
'''
results1=model.fit()#使用fit()方法进行估计
print(results1.summary())
OLS Regression Results
==============================================================================
Dep. Variable: MEDV R-squared: 0.484
Model: OLS Adj. R-squared: 0.483
Method: Least Squares F-statistic: 471.8
Date: Wed, 21 Aug 2024 Prob (F-statistic): 2.49e-74
Time: 17:00:03 Log-Likelihood: -1673.1
No. Observations: 506 AIC: 3350.
Df Residuals: 504 BIC: 3359.
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept -34.6706 2.650 -13.084 0.000 -39.877 -29.465
RM 9.1021 0.419 21.722 0.000 8.279 9.925
==============================================================================
Omnibus: 102.585 Durbin-Watson: 0.684
Prob(Omnibus): 0.000 Jarque-Bera (JB): 612.449
Skew: 0.726 Prob(JB): 1.02e-133
Kurtosis: 8.190 Cond. No. 58.4
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
2.多元回归
1)将房价中位数MEDV对RM和AGE进行回归:
results2=smf.ols('MEDV~RM+AGE',data=Boston).fit()#二元回归
print(results2.summary().tables[1])#仅展示中间表格
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept -25.2774 2.857 -8.848 0.000 -30.890 -19.665
RM 8.4016 0.412 20.388 0.000 7.592 9.211
AGE -0.0728 0.010 -7.075 0.000 -0.093 -0.053
==============================================================================
2)将房价中位数MEDV对RM、AGE以及两者交叉项进行回归
results3=smf.ols('MEDV~RM+AGE+RM:AGE',data=Boston).fit()#主效应+交互效应,RM:AGE表示两者相乘
'''
'MEDV~RM+AGE+RM:AGE'可简写为'MEDV~RM*AGE',所得结果相同
'''
print(results3.params)#只展示回归系数
Intercept -59.592862
RM 13.747467
AGE 0.381529
RM:AGE -0.071407
dtype: float64
3)将房价中位数MEDV对RM、AGE、交叉项以及两者平方项进行回归
results4=smf.ols('MEDV~RM*AGE+I(RM**2)+I(AGE**2)',data=Boston).fit()
#加入平方项,I()具有保护作用,使得Python将I(RM**2)视为变量RM^2
print(results4.params)
Intercept 67.847165
RM -24.039817
AGE 0.274171
RM:AGE -0.034858
I(RM ** 2) 2.706836
I(AGE ** 2) -0.001169
dtype: float64
4)将房价中位数MEDV对所以特征变量进行回归
all_columns='CRIM+ZN+INDUS+CHAS+NOX+RM+AGE+DIS+RAD+TAX+PTRATIO+B+LSTAT'
formula='MEDV~'+all_columns#定义回归公式
results5=smf.ols(formula,data=Boston).fit()#对所有特征变量进行回归
print(results5.summary().tables[1])
```python
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept 36.4595 5.103 7.144 0.000 26.432 46.487
CRIM -0.1080 0.033 -3.287 0.001 -0.173 -0.043
ZN 0.0464 0.014 3.382 0.001 0.019 0.073
INDUS 0.0206 0.061 0.334 0.738 -0.100 0.141
CHAS 2.6867 0.862 3.118 0.002 0.994 4.380
NOX -17.7666 3.820 -4.651 0.000 -25.272 -10.262
RM 3.8099 0.418 9.116 0.000 2.989 4.631
AGE 0.0007 0.013 0.052 0.958 -0.025 0.027
DIS -1.4756 0.199 -7.398 0.000 -1.867 -1.084
RAD 0.3060 0.066 4.613 0.000 0.176 0.436
TAX -0.0123 0.004 -3.280 0.001 -0.020 -0.005
PTRATIO -0.9527 0.131 -7.283 0.000 -1.210 -0.696
B 0.0093 0.003 3.467 0.001 0.004 0.015
LSTAT -0.5248 0.051 -10.347 0.000 -0.624 -0.425
==============================================================================
5)由于上图中AGE高度不显著,去掉变量AGE再次进行回归
formula_noAGE=formula+'-AGE'
print(formula_noAGE)
results6=smf.ols(formula_noAGE,data=Boston).fit()#对出AGE外所有特征变量进行回归
print(results6.params)
除AGE外所有特征变量: MEDV~CRIM+ZN+INDUS+CHAS+NOX+RM+AGE+DIS+RAD+TAX+PTRATIO+B+LSTAT-AGE
回归系数: Intercept 36.436927
CRIM -0.108006
ZN 0.046334
INDUS 0.020562
CHAS 2.689026
NOX -17.713540
RM 3.814394
DIS -1.478612
RAD 0.305786
TAX -0.012329
PTRATIO -0.952211
B 0.009321
LSTAT -0.523852
dtype: float64
三. 模型评估的再抽样方法
1.验证集法
使用验证集法时,现将数据一分为二,其中大部分作为训练集(约70%),其余作为验证集或保留集。在估计模型是,仅使用训练集,然后在验证集进行样本外预测,并计算验证集误差,以此估计测试误差。
1)进行样本分类
x_train,x_test,y_train,y_test=train_test_split(data,target,test_size=0.3,random_state=0)
#将样本分为训练集和验证集,test_size=0.3表示测试集占30%
print(x_train.shape,x_test.shape,y_train.shape,y_test.shape)#形状
数组形状如下:
(354, 13) (152, 13) (354,) (152,)
2)使用sklearn模块LinearRegression类进行OLS回归
model=LinearRegression()#生成实例
model.fit(x_train,y_train)#使用fit()估计
print(model.coef_)#回归系数
回归系数: [-1.21310401e-01 4.44664254e-02 1.13416945e-02 2.51124642e+00
-1.62312529e+01 3.85906801e+00 -9.98516565e-03 -1.50026956e+00
2.42143466e-01 -1.10716124e-02 -1.01775264e+00 6.81446545e-03
-4.86738066e-01]
3)评估
print('拟合优度:',model.score(x_test,y_test))#模型在测试集中的拟合优度,R^2
pred=model.predict(x_test)#测试集预测结果
print('均方误差:',mean_squared_error(y_test,pred))#均方误差
拟合优度: 0.6733825506400186
均方误差: 27.195965766883276
2.K折交叉验证
通过将数据集分成K个互不重叠的子集,每次使用K-1个子集作为训练集,剩下的1个子集作为测试集,重复K次,最终取平均误差作为模型的性能指标。
1)导入交叉验证所需模块
from sklearn.model_selection import KFold
from sklearn.model_selection import LeaveOneOut
from sklearn.model_selection import RepeatedKFold
from sklearn.model_selection import cross_val_score
2)进行10折交叉验证
X=data
y=target
model=LinearRegression()
kfold=KFold(n_splits=10,shuffle=True,random_state=1)
#n_splits=10表示将全样本分为10折,shuffle=True表示随机分组
3)评估
以拟合优度作为得分标准
scores=cross_val_score(model,X,y,cv=kfold)
#cv=kfold指定交叉验证的随机分组为kfold
print('拟合优度:',scores)
print('拟合优度平均值',scores.mean())
print('拟合优度标准差',scores.std())
拟合优度: [0.77863866 0.76632537 0.8729179 0.44002779 0.84715141 0.71692423
0.72093063 0.59299064 0.69816152 0.75603868]
拟合优度平均值 0.719010682018947
拟合优度标准差 0.11892348692223256
以均方误差作为得分标准
scores_mse=-cross_val_score(model,X,y,cv=kfold,scoring='neg_mean_squared_error')
print('均方误差',scores_mse)
print('均方误差均值',scores_mse.mean())
均方误差 [20.54427466 24.47650033 9.49619045 48.63290854 12.11906454 18.14673907
17.53359386 38.67822303 34.22829546 13.73556966]
均方误差均值 23.759135960073205
3.将10折交叉验证重复进行10次
1)使用RepeatedKFold类,将10折交叉验证重复进行10次
rkfold=RepeatedKFold(n_splits=10,n_repeats=10,random_state=1)#将10折交叉验证重复10次
scores_mse2=-cross_val_score(model,X,y,cv=rkfold,scoring='neg_mean_squared_error')
print(scores_mse2.shape)
print(scores_mse2.mean())
(100,)#表明scores_mse2对应100个子样本的均方误差
23.962356681713366#均方误差均值
2)画出100个子样本均方误差的直方图与核密度图
sns.displot(pd.DataFrame(scores_mse2))
plt.xlabel('MSE')
plt.title('10-fold CV Repeated 10 Times')
plt.tight_layout()#用于自动调整图形的布局,确保元素如坐标轴标签、刻度和标题不会重叠
plt.show()
4.留一交叉验证
将样本数据等分为n折(n为样本容量),每折只包含一个样本点。由于每次均使用n-1个数据去预测留出的一个数据,故总共需估计n次,估计结果不再具备随机性。
loo=LeaveOneOut()#创建LeaveOneOut()实例,LeaveOneOut()等价于KFold(n_splits=n)
scores_mse4=-cross_val_score(model,X,y,cv=loo,scoring='neg_mean_squared_error')
print(scores_mse4.mean())
均方误差均值: 23.725745519476146