基于回归分析的大学得分预测

1 简介

1.1 背景简介

大学排名的问题具有显著的重要性,同时也充满了挑战和争议。一所大学的全方位能力包括科研、师资和学生等多个因素。在本项目中,我们将依据CWUR提供的全球知名大学的各项排名(包括师资和科研等)来进行工作。一方面,我们将通过数据可视化来探究各个大学的独特性。另一方面,我们希望利用机器学习模型(例如线性回归)来预测大学的综合得分。

源地址:https://gitlab.diantouedu.cn/QY/test1/tree/master/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E7%B3%BB%E7%BB%9F%E5%AE%9E%E6%88%98%E7%AC%AC%E4%B8%89%E6%9C%9F/%E5%AE%9E%E6%88%98%E4%BB%A3%E7%A0%81/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%9F%BA%E4%BA%8E%E5%9B%9E%E5%BD%92%E5%88%86%E6%9E%90%E7%9A%84%E5%A4%A7%E5%AD%A6%E7%BB%BC%E5%90%88%E5%BE%97%E5%88%86%E9%A2%84%E6%B5%8B

本文在原基础上,修改了缺失数据的处理方式,增加了岭回归、pca降维和tsne的降维效果。

所有可运行的代码,在我的仓库中,https://github.com/Guoxn1/ai。按照博客中文章的分类,可找到代码所在分支。

如果给到您帮助,请给我的仓库个star,这将助推我持续创作。

1.2 任务简介

基础任务(80分): - 1.观察和可视化数据,揭示数据的特性。 - 2.训练集和测试集应按照7:3的比例随机划分,采用RMSE(均方根误差)作为模型的评估标准,计算并获取测试集上的线性回归模型的RMSE值。 - 3.对线性回归模型中的系数进行分析。 - 4.尝试使用其他类型的回归模型,并比较其效果。

进阶任务(20分): - 1.尝试将地区的离散特征融入到线性回归模型中,然后比较并分析结果。 - 2.利用R2指标和VIF指标进行模型评价和特征筛选, 尝试是否可以增加模型精度。

1.3 数据简介

image-20231015213356426

这个数据,最左侧是大学的排名及大学的名称,最右侧是大学的得分数,并且从数据来看是从2012-2015年的数据。

2 数据预处理

2.1 去除异常数据和填充缺失数据

异常数据暂时没有看见,其实真没有。

缺失数据确实看到,在2012年和2013年的broad_impact是空的,我们试图用2014和2015年的数据对其填充,如果不存在,就设置为中值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
data = pd.read_csv("cwurData1.csv")
# 处理空值数据
board_2012 = data[(data["year"] == 2012)][["institution", "broad_impact"]]
board_2013 = data[(data["year"] == 2013)][["institution", "broad_impact"]]
board_2014_2015 = data[(data["year"].isin([2014, 2015]))][["institution", "broad_impact"]]

for index1, row1 in board_2012.iterrows():
if pd.isnull(row1["broad_impact"]):
for index2, row2 in board_2014_2015.iterrows():
if row2["institution"] == row1["institution"]:
board_2012.at[index1,"broad_impact"] = row2["broad_impact"]
break
else:
pass
if pd.isnull(board_2012.at[index1,"broad_impact"]):
median_value = np.median(board_2012["broad_impact"].dropna())
board_2012.at[index1,"broad_impact"] = median_value

for index1, row1 in board_2013.iterrows():
if pd.isnull(row1["broad_impact"]):
for index2, row2 in board_2014_2015.iterrows():
if row2["institution"] == row1["institution"]:
board_2013.at[index1,"broad_impact"] = row2["broad_impact"]
break
else:
pass
if pd.isnull(board_2013.at[index1,"broad_impact"]):
median_value = np.median(board_2013["broad_impact"].dropna())
board_2013.at[index1,"broad_impact"] = median_value
data.update(board_2012)
data.update(board_2013)
data.head()

2.2 划分训测集和标准化数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.rcParams['font.sans-serif'] = ['SimHei']

score = data["score"]
features = data[['quality_of_faculty', 'publications', 'citations', 'alumni_employment','influence', 'quality_of_education', 'broad_impact', 'patents']]

x = features.values
y = score.values

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, shuffle=True)

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.fit_transform(X_test)

2.3 可视化展示数据

主要是计算变量之间的线性关系,为我们之后选择lasso线性回归提供依据。因为部分变量之间存在一些关系,所以之后考虑的时候就可以选择删除这些数据或者采用更优的办法。

1
2
3
4
5
6
7
8
9
10
11
# 观察变量之间的关系
# 主要是计算变量之间的线性关系,相关系数,皮尔逊系数
corrs = data[['quality_of_faculty', 'publications', 'citations', 'alumni_employment','influence', 'quality_of_education', 'broad_impact', 'patents',"score"]].corr()

# 从相关系数矩阵 corrs 中选择了与 'quality_of_faculty' 变量相关性最高的前 9 个变量,并获取它们的列名。
cols = corrs.nlargest(9,"quality_of_faculty")['quality_of_faculty'].index
cm = np.corrcoef(data[cols].values.T)
# 这里cm和coors是一样的,因为总共就9个,如果想提取最大的8个,那还是用这种。
hm = sns.heatmap(cm,cbar=True,annot=True,square=True,fmt=".2f",annot_kws={"size":10},yticklabels=cols.values,xticklabels=cols.values)
plt.show()

image-20231015222749797

3 使用线性回归预测得分

这里我们使用评价指标rmse和r2指标,即平方根误差和决定系数。尝试使用不同的回归模型对数据进行分析。其中rmse越小越好,r2越接近1越好。

简单来讲,lasso回归适用于变量之间存在较少关系的,而岭回归偏向于变量之间存在共线性关系的。

3.1 线性回归

1
2
3
4
5
6
7
8
9
10
11
12
13
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score

line1 = LinearRegression()
line1.fit(x_train,y_train)

y_pred = line1.predict(x_test)
rmse = mean_squared_error(y_test, y_pred, squared=False)
r2 = r2_score(y_test, y_pred)
print(rmse)
print(r2)
print(line1.coef_)

输出如下:

6.062507041517643

0.5242305139015173

[-3.50585305 0.34820841 0.05744021 -1.02184516 0.42170002 -0.38606471 -1.41763572 -0.40082597]

3.2 lasso回归

1
2
3
4
5
6
7
8
9
10
from sklearn.linear_model import Lasso


lasso1 = Lasso(alpha=1)
lasso1.fit(x_train,y_train)
y_lao_pred = lasso1.predict(x_test)
la_rmse = mean_squared_error(y_test,y_lao_pred,squared=False)
lao_r2 = r2_score(y_test,y_lao_pred)
print(la_rmse)
print(lao_r2)

6.407601693598727

0.4685246976674987

模型的效果好像更差了,因为lasso回归更擅长解决非共线性问题,常用于找到更具代表性的特征。

3.3 岭回归

1
2
3
4
5
6
7
8
9
from sklearn.linear_model import Ridge

ridge1 = Ridge(alpha=1)
ridge1.fit(x_train,y_train)
y_lin_pred = ridge1.predict(x_test)
lin_rmse = mean_squared_error(y_test,y_lin_pred,squared=False)
lin_r2 = r2_score(y_test,y_lin_pred)
print(lin_rmse)
print(r2)

输出:

6.063214490232219

0.5242305139015173

回比最初始的好一点,但是好不了太多,尝试提高模型质量。

4 提高模型预测质量

4.1 加入地区特征

从表里可以看出,usa地区的学校明显更偏向于排在前面,而亚洲地区的和其它地区的学校更偏向于被排到后面,所以考虑将地区因素加入进来。这里将计算每个地区学校排名的平均数,划分为三个等级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
features = data[['quality_of_faculty', 'publications', 'citations', 'alumni_employment', 
'influence', 'quality_of_education', 'broad_impact', 'patents', 'region']]
places = features["region"].unique()

for place in places:
idxs = features[features["region"]==place].index
avg = np.mean(score.loc[idxs])
if avg > 50 :
tmp = 1
elif avg > 45:
tmp = 2
else:
tmp = 3


features = features.replace(place,tmp)
display(features.head(15))

x_train1, x_test1, y_train1, y_test1 = train_test_split(features, score, test_size=0.3, shuffle=True)
x_train1 = scaler.fit_transform(x_train1)
x_test1 =scaler.fit_transform(x_test1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
line2 = LinearRegression()
lasso2 = Lasso(alpha=1)
ridge2 = Ridge(alpha=1)

line2.fit(x_train1,y_train1)
lasso2.fit(x_train1,y_train1)
ridge2.fit(x_train1,y_train1)

lin2_pred = line2.predict(x_test1)
lasso2_pred = lasso2.predict(x_test1)
ridge2_pred = ridge2.predict(x_test1)

line2_rmse = mean_squared_error(y_test1,lin2_pred,squared=False)
line2_r2 = r2_score(y_test1,lin2_pred)

lasso2_rmse = mean_squared_error(y_test1,lasso2_pred,squared=False)
lasso_r2 = r2_score(y_test1,lasso2_pred)

ridge2_rmse = mean_squared_error(y_test1,ridge2_pred,squared=False)
ridge2_r2 = r2_score(y_test1,ridge2_pred)

print("------ line ------")
print(line2_rmse)
print(line2_r2)
print("-------lasso --------")
print(lasso2_rmse)
print(lasso_r2)
print("--------- ridge ------")
print(ridge2_rmse)
print(ridge2_r2)

输出:

1
2
3
4
5
6
7
8
9
------ line ------
4.986640851737833
0.5433247669141961
-------lasso --------
5.087845899481954
0.5246000016444884
--------- ridge ------
4.986456775995352
0.5433584815062685

显然,加入地区因素是有所提升的。

4.2 使用VIF指标剔除共线性变量

1
2
3
4
5
6
7
8
9
VIF(Variance Inflation Factor)是用于评估线性回归模型中自变量之间多重共线性(multicollinearity)程度的统计指标。多重共线性指的是自变量之间存在高度相关性,可能导致模型的解释能力下降或不可靠的参数估计。

特征筛选:根据VIF值进行特征筛选。可以选择以下策略之一:

1.删除VIF值较高的自变量:如果某个自变量的VIF值超过阈值,可以将其从模型中剔除。这样可以消除多重共线性的影响,提高模型的稳定性和解释能力。然后重新构建线性回归模型。

2.保留一个相关性较强的自变量:如果多个自变量之间存在高度相关性,可以选择保留其中一个,并将其他相关的自变量剔除。这样可以减少共线性问题,同时保留对因变量解释能力较强的特征。

3.进行变量转换:如果某些自变量之间存在共线性,但它们对于模型的解释能力都很重要,可以考虑对这些自变量进行变量转换,例如通过主成分分析(PCA)降维或者使用其他线性变换方法。

我们的数据存在共线性问题,即一个变量对另一个变量有影响。

本质上,解决方法1和2相似,都是删除一个留下另一个,建议就是删除vif高的值。

VIF(方差膨胀因子)是用于评估自变量之间共线性程度的指标。它可以通过以下数学表达式计算:

对于线性回归模型中的每个自变量(特征)X_i,VIF 的计算方式如下:

VIF(X_i) = 1 / (1 - R_i^2)

其中,R_i^2 是通过将 X_i 作为因变量,使用其他自变量来拟合回归模型得到的决定系数(R^2)。

4.2.1 删除vif高的值

常见的阈值为 5 或 10,当 VIF 值超过这个阈值时,可以认为存在较高的共线性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 阈值设置为10
drop_data = features.drop(columns=[ 'broad_impact', 'publications'])

calVIF(drop_data)

x_train2, x_test2, y_train2, y_test2 = train_test_split(drop_data, score, test_size=0.3, shuffle=True)
x_train2 = scaler.fit_transform(x_train2)
x_test2 = scaler.fit_transform(x_test2)


line2.fit(x_train2,y_train2)
lasso2.fit(x_train2,y_train2)
ridge2.fit(x_train2,y_train2)

lin2_pred = line2.predict(x_test2)
lasso2_pred = lasso2.predict(x_test2)
ridge2_pred = ridge2.predict(x_test2)

line2_rmse = mean_squared_error(y_test2,lin2_pred,squared=False)
line2_r2 = r2_score(y_test2,lin2_pred)

lasso2_rmse = mean_squared_error(y_test2,lasso2_pred,squared=False)
lasso_r2 = r2_score(y_test2,lasso2_pred)

ridge2_rmse = mean_squared_error(y_test2,ridge2_pred,squared=False)
ridge2_r2 = r2_score(y_test2,ridge2_pred)

print("------ line ------")
print(line2_rmse)
print(line2_r2)
print("-------lasso --------")
print(lasso2_rmse)
print(lasso_r2)
print("--------- ridge ------")
print(ridge2_rmse)
print(ridge2_r2)

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
               features        VIF
0 const 13.581113
1 quality_of_faculty 3.041690
2 citations 3.892509
3 alumni_employment 1.823623
4 influence 4.174677
5 quality_of_education 3.072823
6 patents 1.842416
7 region 1.392715
------ line ------
4.858928372892254
0.5051567529916083
-------lasso --------
4.829505022080995
0.5111316763889303
--------- ridge ------
4.858693844150307
0.5052045216164693

4.2.2 pca降维

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from sklearn.decomposition import PCA

pca = PCA(n_components=0.98)
reduced = pca.fit_transform(features)
print(reduced.shape)

x_train3, x_test3, y_train3, y_test3 = train_test_split(reduced, score, test_size=0.3, shuffle=True)

x_train3 = scaler.fit_transform(x_train3)
x_test3 = scaler.fit_transform(x_test3)

line2.fit(x_train3,y_train3)
lasso2.fit(x_train3,y_train3)
ridge2.fit(x_train3,y_train3)

lin2_pred = line2.predict(x_test3)
lasso2_pred = lasso2.predict(x_test3)
ridge2_pred = ridge2.predict(x_test3)

line2_rmse = mean_squared_error(y_test3,lin2_pred,squared=False)
line2_r2 = r2_score(y_test3,lin2_pred)

lasso2_rmse = mean_squared_error(y_test3,lasso2_pred,squared=False)
lasso_r2 = r2_score(y_test3,lasso2_pred)

ridge2_rmse = mean_squared_error(y_test3,ridge2_pred,squared=False)
ridge2_r2 = r2_score(y_test3,ridge2_pred)

print("------ line ------")
print(line2_rmse)
print(line2_r2)
print("-------lasso --------")
print(lasso2_rmse)
print(lasso_r2)
print("--------- ridge ------")
print(ridge2_rmse)
print(ridge2_r2)

输出:

1
2
3
4
5
6
7
8
9
10
(2200, 6)
------ line ------
4.8823157878149175
0.45271279262238207
-------lasso --------
5.0973879270658635
0.40343339763507935
--------- ridge ------
4.881904035006545
0.4528051002698318

有概率变成4.9多的,降维也可以提高一点点性能。

4.2.3 tsne降维

​ 再看一下tsne的降维效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from sklearn.manifold import TSNE

tsne = TSNE(n_components=3)
reduced1 = tsne.fit_transform(features)
print(reduced1.shape)

x_train3, x_test3, y_train3, y_test3 = train_test_split(reduced1, score, test_size=0.3, shuffle=True)
x_train3 = scaler.fit_transform(x_train3)
x_test3 = scaler.fit_transform(x_test3)

line2.fit(x_train3,y_train3)
lasso2.fit(x_train3,y_train3)
ridge2.fit(x_train3,y_train3)

lin2_pred = line2.predict(x_test3)
lasso2_pred = lasso2.predict(x_test3)
ridge2_pred = ridge2.predict(x_test3)

line2_rmse = mean_squared_error(y_test3,lin2_pred,squared=False)
line2_r2 = r2_score(y_test3,lin2_pred)

lasso2_rmse = mean_squared_error(y_test3,lasso2_pred,squared=False)
lasso_r2 = r2_score(y_test3,lasso2_pred)

ridge2_rmse = mean_squared_error(y_test3,ridge2_pred,squared=False)
ridge2_r2 = r2_score(y_test3,ridge2_pred)

print("------ line ------")
print(line2_rmse)
print(line2_r2)
print("-------lasso --------")
print(lasso2_rmse)
print(lasso_r2)
print("--------- ridge ------")
print(ridge2_rmse)
print(ridge2_r2)

输出:

1
2
3
4
5
6
7
8
9
10
(2200, 3)
------ line ------
6.8153223765950885
0.3983354125880342
-------lasso --------
7.011434373048135
0.3632112380169754
--------- ridge ------
6.815726390060208
0.3982640769163529

并不理想,猜测可能是变量之间更偏向于存在线性关系。所以这种情况下降维还是用pca。

如果这篇博客给到您帮助,我希望您能给我的仓库点一个star,这将是我继续创作下去的动力。

我的仓库地址,https://github.com/Guoxn1?tab=repositories

like

基于回归分析的大学得分预测
http://example.com/2023/10/15/基于回归分析的大学得分预测/
作者
Guoxin
发布于
2023年10月15日
许可协议