【机器学习】基于回归分析的大学综合得分预测

实验二:基于回归分析的大学综合得分预测


一、案例简介

大学排名是一个非常重要同时也极富挑战性与争议性的问题,一所大学的综合实力涉及科研、师资、学生等方方面面。目前全球有上百家评估机构会评估大学的综合得分进行排序,而这些机构的打分也往往并不一致。在这些评分机构中,世界大学排名中心(Center for World University Rankings,缩写CWUR)以评估教育质量、校友就业、研究成果和引用,而非依赖于调查和大学所提交的数据著称,是非常有影响力的一个。

本任务中我们将根据 CWUR 所提供的世界各地知名大学各方面的排名(师资、科研等),一方面通过数据可视化的方式观察不同大学的特点,另一方面希望构建机器学习模型(线性回归)预测一所大学的综合得分。

二、作业说明

使用来自 Kaggle 的数据,构建「线性回归」模型,根据大学各项指标的排名预测综合得分。

基本要求:

  • 按照 8:2 随机划分训练集测试集,用 RMSE 作为评价指标,得到测试集上线性回归模型的 RMSE 值;
  • 对线性回归模型的系数进行分析。

扩展要求:

  • 对数据进行观察与可视化,展示数据特点;
  • 尝试其他的回归模型,对比效果;
  • 尝试将离散的地区特征融入线性回归模型,并对结果进行对比。

注意事项:

  • 基本输入特征有 8 个:quality_of_education, alumni_employment, quality_of_faculty, publications, influence, citations, broad_impact, patents
  • 预测目标为score
  • 可以使用 sklearn 等第三方库,不要求自己实现线性回归;
  • 需要保留所有数据集生成、模型训练测试的代码;

三、数据概览

假设数据文件位于当前文件夹,我们用 pandas 读入标准 csv 格式文件的函数read_csv()将数据转换为DataFrame的形式。观察前几条数据记录:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
RANDOM_SEED = 2023

data_df = pd.read_csv('./data/cwurData.csv')  # 读入 csv 文件为 pandas 的 DataFrame
data_df.head(3).T  # 观察前几列并转置方便观察
012
world_rank123
institutionHarvard UniversityMassachusetts Institute of TechnologyStanford University
regionUSAUSAUSA
national_rank123
quality_of_education7917
alumni_employment91711
quality_of_faculty135
publications1124
influence142
citations142
broad_impactNaNNaNNaN
patents5115
score100.091.6789.5
year201220122012

去除其中包含 NaN 的数据,保留 2000 条有效记录。

data_df = data_df.dropna()  # 舍去包含 NaN 的 row
len(data_df)
2000

取出对应自变量以及因变量的列,之后就可以基于此切分训练集和测试集,并进行模型构建与分析。

feature_cols = ['quality_of_faculty', 'publications', 'citations', 'alumni_employment', 
                'influence', 'quality_of_education', 'broad_impact', 'patents']
X = data_df[feature_cols]
Y = data_df['score']
X
quality_of_facultypublicationscitationsalumni_employmentinfluencequality_of_educationbroad_impactpatents
2001111111.02
20145323114.06
202215211232.01
20351012109213.048
2041011111212712.016
...........................
2195218926812567845367969.0816
2196218997645566908236981.0871
2197218830812549823367975.0824
2198218886812567974367975.0651
2199218861812567991367981.0547

2000 rows × 8 columns

四、模型构建

4.1 线性回归分析

  1. 创建数据集
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=RANDOM_SEED)
X.shape, Y.shape, x_train.shape, x_test.shape, y_train.shape, y_test.shape # 输出数据行列信息
((2000, 8), (2000,), (1600, 8), (400, 8), (1600,), (400,))
  1. 调用sklearn库函数,实现对模型的训练及测试
# 创建线性回归模型的实例
model = LinearRegression()
# 在训练集上训练
model.fit(x_train, y_train)
# 在测试集上测试
test_pre = model.predict(x_test)
# 计算RMSE
test_rmse = mean_squared_error(y_test,test_pre,squared = False)
print(f'rmse:{test_rmse}')
rmse:3.2634140694790297
  1. 线性回归输出表达式
intercept = model.intercept_ # 获取模型的截距
coef = model.coef_ # 获取模型的斜率
equation = "y = " # 初始化方程的表达式
equation += f"{intercept:.4f}" # 添加截距,保留两位小数
for i, c in enumerate(coef): # 遍历系数
    if c >= 0: # 如果系数是正数
        equation += f" + {c:.4f} x_{i+1}" # 添加加号和系数,保留两位小数
    else: # 如果系数是负数
        equation += f" - {abs(c):.4f} x_{i+1}" # 添加减号和系数的绝对值,保留两位小数
print(equation)
y = 66.5284 - 0.0657 x_1 + 0.0003 x_2 - 0.0001 x_3 - 0.0075 x_4 + 0.0012 x_5 - 0.0068 x_6 - 0.0026 x_7 - 0.0027 x_8
  1. 对线性回归模型的系数进行分析
import seaborn as sns
# 图形化表示各个特征的系数
sns.set()
sns.barplot(x=model.coef_, y=feature_cols)
plt.show()


png

4.2 对数据进行观察与可视化

for col in feature_cols:
    # 划分训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(X[col].values.reshape(-1, 1), Y, test_size=0.2, random_state=RANDOM_SEED)

    # 创建一个线性回归模型的实例
    model = LinearRegression()
    
    # 使用训练集来拟合模型
    model.fit(x_train, y_train)
    
    # 使用测试集来评估模型的性能
    y_pre=model.predict(x_test)#预测
    rmse = mean_squared_error(y_test,y_pre,squared = False)
    print(f'rmse:{rmse}')
    print()
    
    # 可视化模型的结果
    plt.scatter(x_test, y_test, label='Actual') # 绘制测试集的散点图,表示实际的因变量值
    plt.plot(x_test, y_pre, color='red', label='Predicted') # 绘制测试集的折线图,表示预测的因变量值
    plt.xlabel(col) # 设置 x 轴的标签
    plt.ylabel('score') # 设置 y 轴的标签
    plt.legend() # 显示图例
    plt.show() # 显示图形
rmse:3.479517845901262


png

rmse:4.047968509911168


png

rmse:4.102669954218188


png

rmse:4.472523167437157


png

rmse:4.035630757829832


png

rmse:4.069221954219227


png

rmse:3.971682290643895


png

rmse:4.326078641382164


png

4.3 离散的地区特征

尝试将离散的地区特征融入线性回归模型,并对结果进行对比

选择将离散的地区特征,按其各自的数量作为其值进行数据化

  1. 查看地区的唯一值
data_df['region'].unique()
array(['USA', 'United Kingdom', 'Japan', 'Switzerland', 'Israel',
       'South Korea', 'Canada', 'France', 'Russia', 'China', 'Taiwan',
       'Sweden', 'Singapore', 'Denmark', 'Germany', 'Netherlands',
       'Italy', 'Belgium', 'Australia', 'Finland', 'Norway',
       'South Africa', 'Spain', 'Brazil', 'Hong Kong', 'Ireland',
       'Austria', 'New Zealand', 'Portugal', 'Thailand', 'Czech Republic',
       'Malaysia', 'India', 'Greece', 'Mexico', 'Hungary', 'Argentina',
       'Turkey', 'Poland', 'Saudi Arabia', 'Chile', 'Iceland', 'Slovenia',
       'Estonia', 'Lebanon', 'Croatia', 'Colombia', 'Slovak Republic',
       'Iran', 'Egypt', 'Serbia', 'Bulgaria', 'Lithuania', 'Uganda',
       'United Arab Emirates', 'Uruguay', 'Cyprus', 'Romania',
       'Puerto Rico'], dtype=object)
  1. 根据数据集中地区数量进行赋值
region_counts = data_df['region'].value_counts() # 计算每个地区的数量
print(region_counts) # 打印结果
USA                     458
China                   167
Japan                   148
United Kingdom          129
Germany                 110
France                   99
Italy                    94
Spain                    81
South Korea              70
Canada                   65
Australia                54
Taiwan                   46
Brazil                   36
India                    31
Netherlands              26
Austria                  24
Sweden                   22
Turkey                   20
Belgium                  20
Finland                  18
Poland                   18
Switzerland              18
Iran                     16
Ireland                  16
Greece                   14
Portugal                 14
Israel                   14
Hungary                  12
Hong Kong                12
New Zealand              12
Norway                   10
Czech Republic           10
South Africa             10
Denmark                  10
Egypt                     8
Chile                     8
Saudi Arabia              8
Russia                    8
Argentina                 7
Thailand                  6
Malaysia                  6
Mexico                    4
Colombia                  4
Singapore                 4
Slovenia                  4
Romania                   3
Lebanon                   2
Croatia                   2
Estonia                   2
Slovak Republic           2
Iceland                   2
Serbia                    2
Bulgaria                  2
Lithuania                 2
Uganda                    2
United Arab Emirates      2
Uruguay                   2
Cyprus                    2
Puerto Rico               2
Name: region, dtype: int64
  1. 创建新的数据集

    在原有的X数据集中加入region_count列

X_plus = X.assign(region = data_df.region)
X_plus = X_plus.join(region_counts, on='region', rsuffix='_count')
X_plus.drop('region', axis=1, inplace=True)
X_plus
quality_of_facultypublicationscitationsalumni_employmentinfluencequality_of_educationbroad_impactpatentsregion_count
2001111111.02458
20145323114.06458
202215211232.01458
20351012109213.048129
2041011111212712.016129
..............................
2195218926812567845367969.081614
2196218997645566908236981.08718
2197218830812549823367975.082436
2198218886812567974367975.065181
2199218861812567991367981.0547167

2000 rows × 9 columns

  1. 训练数据集,并进行测试,绘制基于region_count的图像
# 创建数据集
x_train, x_test, y_train, y_test = train_test_split(X_plus, Y, test_size=0.2, random_state=RANDOM_SEED)
X.shape, Y.shape, x_train.shape, x_test.shape, y_train.shape, y_test.shape # 输出数据行列信息

# 创建线性回归模型的实例
model = LinearRegression()
# 在训练集上训练
model.fit(x_train, y_train)
# 在测试集上测试
test_pre = model.predict(x_test)
# 计算RMSE
test_rmse = mean_squared_error(y_test,test_pre,squared = False)
print(f'rmse:{test_rmse}')

# 计算表达式
intercept = model.intercept_ # 获取模型的截距
coef = model.coef_ # 获取模型的斜率
equation = "y = " # 初始化方程的表达式
equation += f"{intercept:.4f}" # 添加截距,保留两位小数
for i, c in enumerate(coef): # 遍历系数
    if c >= 0: # 如果系数是正数
        equation += f" + {c:.4f} x_{i+1}" # 添加加号和系数,保留两位小数
    else: # 如果系数是负数
        equation += f" - {abs(c):.4f} x_{i+1}" # 添加减号和系数的绝对值,保留两位小数
print(equation)

# 绘制region_count图像
sns.regplot(x=X_plus['region_count'], y=Y, marker=".")
plt.show()
rmse:3.2114437773064073
y = 65.9558 - 0.0652 x_1 - 0.0005 x_2 + 0.0001 x_3 - 0.0072 x_4 + 0.0014 x_5 - 0.0069 x_6 - 0.0022 x_7 - 0.0025 x_8 + 0.0017 x_9

png

相比与未加入地区数据集,rmse有所降低,模型更好

4.4 尝试使用多项式回归模型

通过调用sklearn库中preprocessingpipeline函数,实现多项式回归,并进行可视化分析

from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline

# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(X['quality_of_faculty'].values.reshape(-1, 1), Y, test_size=0.2, random_state=RANDOM_SEED)

# 生成多项式特征,这里指定最高次数为 3
poly = PolynomialFeatures(degree=3)

# 创建线性回归模型的实例
model = LinearRegression()

# 创建管道,将多项式特征的转换器和线性回归模型连接起来
pipeline = make_pipeline(poly, model)

# 使用数据拟合管道
pipeline.fit(x_train, y_train)

# 获取模型的系数和截距
coef = pipeline.named_steps['linearregression'].coef_
intercept = pipeline.named_steps['linearregression'].intercept_
print(f'Equation: y = {intercept:.5f} + {coef[1]:.5f}x + {coef[2]:.5f}x^2 + {coef[3]:.5f}x^3') # 打印模型的方程,保留两位小数

# 使用管道预测新的数据
y_pre = pipeline.predict(x_test) # 新的因变量

# 计算RMSE
test_rmse = mean_squared_error(y_test,y_pre,squared = False)
print(f'rmse:{test_rmse:.4f}')
print()

# 使用 matplotlib 库绘制模型的图形
import matplotlib.pyplot as plt
plt.scatter(x_train, y_train, label='Actual') # 绘制原始数据的散点图,表示实际的因变量值
x_new = np.arange(0, 220, 5).reshape((-1, 1)) # 新的自变量
y_new = pipeline.predict(x_new) # 新的因变量
plt.plot(x_new, y_new, color='red', label='Predicted') # 绘制新数据的折线图,表示预测的因变量值
plt.xlabel('quality_of_faculty') # 设置 x 轴的标签
plt.ylabel('score') # 设置 y 轴的标签
plt.legend() # 显示图例
plt.show() # 显示图形
Equation: y = 89.02454 + -0.97067x + 0.00718x^2 + -0.00002x^3
rmse:2.5425


png

通过使用3次方多项式进行回归分析,明显可以看到曲线更加贴合数据,rmse也明显降低

4.5 尝试使用对数回归模型

对输入和输出变量进行对数变换,然后执行多项式回归分析,并最后在图中反变换对数结果以展示原始数据

import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

# 对输入和输出变量进行对数变换,处理非正数值
x_log = np.log(np.maximum(X['quality_of_faculty'].values.reshape(-1, 1), 1e-10))
y_log = np.log(np.maximum(Y, 1e-10))

# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(x_log, y_log, test_size=0.2, random_state=RANDOM_SEED)

# 生成多项式特征,这里指定最高次数为 3
poly = PolynomialFeatures(degree=3)

# 创建线性回归模型的实例
model = LinearRegression()

# 创建管道,将多项式特征的转换器和线性回归模型连接起来
pipeline = make_pipeline(poly, model)

# 使用数据拟合管道
pipeline.fit(x_train, y_train)

# 获取模型的系数和截距
coef = pipeline.named_steps['linearregression'].coef_
intercept = pipeline.named_steps['linearregression'].intercept_
print(f'Equation: log(y) = {intercept:.5f} + {coef[1]:.5f}logx + {coef[2]:.5f}(logx)^2 + {coef[3]:.5f}(logx)^3') # 打印模型的方程,保留两位小数

# 使用管道预测新的数据
y_pre = pipeline.predict(x_test) # 新的对数因变量

# 计算RMSE
test_rmse = np.sqrt(mean_squared_error(y_test, y_pre))
print(f'rmse:{test_rmse:.4f}')
print()

# 使用 matplotlib 库绘制模型的图形
import matplotlib.pyplot as plt
plt.scatter(np.exp(x_train), np.exp(y_train), label='Actual') # 绘制原始数据的散点图,表示实际的因变量值(需要对数反变换)
x_new = np.arange(1, 220, 5).reshape((-1, 1))  # 新的自变量
x_new = np.maximum(x_new, 1e-10)  # 替换零值为一个很小的正数
y_new = np.exp(pipeline.predict(np.log(x_new)))  # 新的对数因变量
plt.plot(x_new, y_new, color='red', label='Predicted') # 绘制新数据的折线图,表示预测的因变量值(需要对数反变换)
plt.xlabel('quality_of_faculty') # 设置 x 轴的标签
plt.ylabel('score') # 设置 y 轴的标签
plt.legend() # 显示图例
plt.show() # 显示图形

Equation: log(y) = 4.65827 + 0.00332logx + -0.07870(logx)^2 + 0.00910(logx)^3
rmse:0.0448


png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

住在天上的云

如果您喜欢我的文章,欢迎打赏哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值