为什么学?
在人文社科研究里,你会经常问:学习时间和成绩有关系吗?收入与幸福感如何相关?
相关性分析回答“变量是否一起变化”,回归分析进一步建立“如何变化”的预测关系。
r ∈ [-1,1] 的含义与解释方式。pandas 计算相关矩阵,并能画散点图 + 回归直线做直观判断。LinearRegression(若不可用则用 numpy.linalg.lstsq 兜底)完成一元/多元回归。r>0 正相关,r<0 负相关,|r| 越大相关越强。 df.corr()(默认皮尔逊);也可用 df.corr(method='spearman') 做等级相关(更稳健)。y = a x + b + ε(a 斜率,b 截距)。from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(X, y) # X 为二维数组
y_pred = model.predict(X_new)
sklearn,可用 numpy.linalg.lstsq 最小二乘求解(本讲已内置兜底)。x 每增加 1 单位,y 平均变化多少。 x=0 的基线水平(需注意是否有解释意义)。 y 的变异。🔎 提示:散点图是理解“相关/回归”的第一视角;先看图,再下结论。
import pandas as pd
data = {
'学习时间': [2, 3, 4, 5, 6],
'期末成绩': [70, 75, 78, 85, 90]
}
df = pd.DataFrame(data)
# 计算相关矩阵(默认皮尔逊)
correlation_matrix = df.corr()
correlation_matrix
C:\Users\Zhouq\AppData\Roaming\Python\Python39\site-packages\pandas\core\computation\expressions.py:21: UserWarning: Pandas requires version '2.8.4' or newer of 'numexpr' (version '2.8.3' currently installed). from pandas.core.computation.check import NUMEXPR_INSTALLED C:\Users\Zhouq\AppData\Roaming\Python\Python39\site-packages\pandas\core\arrays\masked.py:60: UserWarning: Pandas requires version '1.3.6' or newer of 'bottleneck' (version '1.3.5' currently installed). from pandas.core import (
| 学习时间 | 期末成绩 | |
|---|---|---|
| 学习时间 | 1.000000 | 0.993661 |
| 期末成绩 | 0.993661 | 1.000000 |
# 散点图 + 简易回归直线(使用 matplotlib)
import matplotlib.pyplot as plt
import numpy as np
# 显示中文
# 设置支持中文的字体,例如黑体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 或者 'Microsoft YaHei', 'FangSong', 'KaiTi' 等
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
x = df['学习时间'].to_numpy(dtype=float)
y = df['期末成绩'].to_numpy(dtype=float)
# 用 numpy 最小二乘拟合直线 y = a*x + b
X_design = np.column_stack([x, np.ones_like(x)])
a, b = np.linalg.lstsq(X_design, y, rcond=None)[0]
plt.figure()
plt.scatter(x, y) # 散点
x_line = np.linspace(x.min(), x.max(), 100)
y_line = a * x_line + b
plt.plot(x_line, y_line) # 回归线(仅可视化)
plt.xlabel("学习时间")
plt.ylabel("期末成绩")
plt.title("散点图与回归线(可视化相关关系)")
plt.show()
# 优先使用 sklearn;若不可用则自动兜底到 numpy
import numpy as np
X = np.array([2, 3, 4, 5, 6], dtype=float).reshape(-1, 1)
y = np.array([70, 75, 78, 85, 90], dtype=float)
try:
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X, y)
slope = model.coef_[0]
intercept = model.intercept_
r2 = model.score(X, y)
print("回归系数(斜率):", round(slope, 4))
print("截距:", round(intercept, 4))
print("R²:", round(r2, 4))
except Exception as e:
# numpy 最小二乘兜底实现
X_design = np.column_stack([np.ones(len(X)), X.flatten()]) # [1, x]
beta, *_ = np.linalg.lstsq(X_design, y, rcond=None)
intercept, slope = float(beta[0]), float(beta[1])
y_hat = X_design @ beta
rss = float(((y - y_hat)**2).sum())
tss = float(((y - y.mean())**2).sum())
r2 = 1 - rss/tss
print("(使用 numpy 兜底)")
print("回归系数(斜率):", round(slope, 4))
print("截距:", round(intercept, 4))
print("R²:", round(r2, 4))
回归系数(斜率): 5.0 截距: 59.6 R²: 0.9874
# 使用模型预测(比如学习 8 小时的成绩)
X_new = np.array([[8]], dtype=float)
try:
predicted = model.predict(X_new) # 若上方是 sklearn
except NameError:
# 若没有 sklearn 的 model,则使用兜底系数计算
predicted = slope * X_new.flatten() + intercept
print("预测学习 8 小时的成绩:", round(float(predicted[0]), 2))
预测学习 8 小时的成绩: 99.6
import numpy as np
import pandas as pd
np.random.seed(0)
n = 12
learn_hours = np.linspace(1, 6, n)
practice = np.linspace(10, 60, n) + np.random.normal(0, 5, n)
score = 55 + 4.0*learn_hours + 0.05*practice + np.random.normal(0, 2, n)
X_multi = np.column_stack([learn_hours, practice])
y_multi = score
try:
from sklearn.linear_model import LinearRegression
m2 = LinearRegression().fit(X_multi, y_multi)
print("斜率(学习时间, 练习题):", np.round(m2.coef_, 3))
print("截距:", round(m2.intercept_, 3))
print("R²:", round(m2.score(X_multi, y_multi), 4))
except Exception as e:
X_design = np.column_stack([np.ones(len(X_multi)), X_multi])
beta, *_ = np.linalg.lstsq(X_design, y_multi, rcond=None)
intercept, b1, b2 = beta
y_hat = X_design @ beta
rss = float(((y_multi - y_hat)**2).sum())
tss = float(((y_multi - y_multi.mean())**2).sum())
r2 = 1 - rss/tss
print("(numpy 兜底)")
print("斜率(学习时间, 练习题):", [round(float(b1),3), round(float(b2),3)])
print("截距:", round(float(intercept),3))
print("R²:", round(r2,4))
斜率(学习时间, 练习题): [2.044 0.217] 截距: 55.487 R²: 0.9297
corr() 方法对比(皮尔逊 vs 斯皮尔曼)¶df2 = pd.DataFrame({
'学习时间': [1,2,3,4,5,6,7,8],
'满意度_等级': [1,1,2,2,3,3,4,5] # 等级型数据(有序分类)
})
pearson = df2.corr(method='pearson')
spearman = df2.corr(method='spearman')
pearson, spearman
( 学习时间 满意度_等级
学习时间 1.000000 0.973479
满意度_等级 0.973479 1.000000,
学习时间 满意度_等级
学习时间 1.000000 0.981981
满意度_等级 0.981981 1.000000)
| 回归类型 | Python方法 | 常见应用场景 |
|---|---|---|
| 线性回归 | LinearRegression |
简单线性关系预测 |
| 多元回归 | LinearRegression |
多因素联合分析 |
| 岭回归 | Ridge |
多重共线性、系数收缩 |
| 套索回归 | Lasso |
稀疏选择/特征选择 |
| 逻辑回归 | LogisticRegression |
二分类问题(通过/未通过) |
| 多项式回归 | PolynomialFeatures + LinearRegression |
简单非线性趋势 |
| 决策树回归 | DecisionTreeRegressor |
非线性、可解释的分段模型 |
| 随机森林回归 | RandomForestRegressor |
高维、非线性、鲁棒预测 |
| 支持向量回归 | SVR |
小样本、非线性核方法 |
练习 1:相关性
构造数据:学习时间=[1,2,3,4,5,6],成绩=[60,65,68,74,80,85]。
1) 计算皮尔逊相关系数与相关矩阵;2) 画散点图 + 回归直线。
练习 2:一元回归预测
用练习 1 的数据拟合回归,报告斜率、截距、R²;预测 学习时间=7 时的成绩。
练习 3:多元回归
自拟 练习题数量 列,与 学习时间 一起预测 成绩;比较一元与多元模型的 R²。
练习 4:Spearman 等级相关
构造一列等级型满意度(1~5),计算与学习时间的 Spearman 相关并解释。
# === 在此动手做题(你可以多建几个单元格)===
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 练习 1:相关性与散点图
# 练习 2:一元回归(报告 斜率/截距/R² + 预测)
# 练习 3:多元回归(与一元回归比较 R²)
# 练习 4:Spearman 等级相关
说明:若无
sklearn,答案会自动切换为numpy兜底实现。
# 练习 1 参考答案
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df_ex = pd.DataFrame({
'学习时间': [1,2,3,4,5,6],
'成绩': [60,65,68,74,80,85]
})
print("相关矩阵:")
print(df_ex.corr())
x = df_ex['学习时间'].to_numpy(dtype=float)
y = df_ex['成绩'].to_numpy(dtype=float)
X_design = np.column_stack([x, np.ones_like(x)])
a, b = np.linalg.lstsq(X_design, y, rcond=None)[0]
plt.figure()
plt.scatter(x, y)
x_line = np.linspace(x.min(), x.max(), 100)
y_line = a*x_line + b
plt.plot(x_line, y_line)
plt.xlabel("学习时间")
plt.ylabel("成绩")
plt.title("练习1:散点图与回归线")
plt.show()
相关矩阵:
学习时间 成绩
学习时间 1.000000 0.996085
成绩 0.996085 1.000000
# 练习 2 参考答案:一元回归 + 预测
import numpy as np
X = np.array([1,2,3,4,5,6], dtype=float).reshape(-1,1)
y = np.array([60,65,68,74,80,85], dtype=float)
try:
from sklearn.linear_model import LinearRegression
m = LinearRegression().fit(X, y)
slope, intercept = m.coef_[0], m.intercept_
r2 = m.score(X, y)
pred7 = m.predict(np.array([[7]], dtype=float))[0]
except Exception as e:
Xd = np.column_stack([np.ones(len(X)), X.flatten()])
beta, *_ = np.linalg.lstsq(Xd, y, rcond=None)
intercept, slope = float(beta[0]), float(beta[1])
y_hat = Xd @ beta
rss = float(((y - y_hat)**2).sum()); tss = float(((y - y.mean())**2).sum())
r2 = 1 - rss/tss
pred7 = slope*7 + intercept
print("斜率:", round(slope,4), "截距:", round(intercept,4), "R²:", round(r2,4))
print("预测(学习时间=7):", round(float(pred7), 2))
斜率: 5.0286 截距: 54.4 R²: 0.9922 预测(学习时间=7): 89.6
# 练习 3 参考答案:多元回归 vs 一元回归
import numpy as np
from numpy.random import default_rng
rng = default_rng(0)
learn = np.array([1,2,3,4,5,6], dtype=float)
practice = np.array([10,20,30,40,45,55], dtype=float) + rng.normal(0, 2, 6)
score = 55 + 4.0*learn + 0.05*practice + rng.normal(0, 1.5, 6)
X1 = learn.reshape(-1,1)
X2 = np.column_stack([learn, practice])
def fit_ols(X, y):
try:
from sklearn.linear_model import LinearRegression
m = LinearRegression().fit(X, y)
r2 = m.score(X, y)
return r2
except Exception as e:
Xd = np.column_stack([np.ones(len(X)), X])
beta, *_ = np.linalg.lstsq(Xd, y, rcond=None)
y_hat = Xd @ beta
rss = float(((y - y_hat)**2).sum()); tss = float(((y - y.mean())**2).sum())
return 1 - rss/tss
r2_simple = fit_ols(X1, score)
r2_multi = fit_ols(X2, score)
print("一元回归 R²:", round(r2_simple, 4))
print("多元回归 R²:", round(r2_multi, 4))
一元回归 R²: 0.9769 多元回归 R²: 0.9838
# 练习 4 参考答案:Spearman 等级相关
import pandas as pd
df_rank = pd.DataFrame({
'学习时间': [1,2,3,4,5,6,7,8],
'满意度': [1,1,2,2,3,3,4,5] # 有序类别
})
spearman_corr = df_rank.corr(method='spearman')
spearman_corr
| 学习时间 | 满意度 | |
|---|---|---|
| 学习时间 | 1.000000 | 0.981981 |
| 满意度 | 0.981981 | 1.000000 |
下一步建议:学习残差诊断、方差膨胀因子(VIF)、正则化回归(Ridge/Lasso),和非线性模型(树/核方法)。