甜心很棒 發表於 2025-8-18 10:15:00

彩笔运维勇闯机器学习--多元线性回归

<h2 id="前言">前言</h2>
<p>之前讨论了一元线性回归,主要是qps与cpu的关系,但是现实中cpu只是系统指标的一部分,还有内存、io、网络等等,本小节就来讨论一下,通过多个系统参数对于qps的影响</p>
<h2 id="算法">算法</h2>
<p>多元线性回归,就是讨论多个自变量对结果造成的影响</p>
<h2 id="开始探索">开始探索</h2>
<p>老规矩,先来看一看怎么快速使用多元线性回归</p>
<h4 id="1-scikit-learn包的使用">1. scikit-learn包的使用</h4>
<p>先不管什么鸡r原理,我目前也不想懂,我就需要看到效果,怎么进行多元回归分析。好的,请出老朋友,scikit-learn包,帮助我们快速上手</p>
<p>安装</p>
<pre><code>pip3 install -U scikit-learn
</code></pre>
<p>使用</p>
<pre><code>from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import pandas as pd
import numpy as np


data = {
    'result': ,
    'feature1': ,
    'feature2': ,
}

df = pd.DataFrame(data)

X = df[[
    'feature1',
    'feature2',
]]
y = df['result']

model = LinearRegression()
model.fit(X, y)

# 输出各自变量的系数
print("回归系数:", model.coef_)

y_pred = model.predict(X)
print("R²:", r2_score(y, y_pred))
print("MSE:", mean_squared_error(y, y_pred))

</code></pre>
<p>三个特征,分别为<code>feature1</code> <code>feature2</code> <code>feature3</code>,它们共同作用于<code>result</code></p>
<p>脚本!启动:<br>
<img alt="watermarked-multi_regression_1_1" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202508/1416773-20250818100031304-779641334.png" class="lazyload"></p>
<h4 id="2-报告解读">2. 报告解读</h4>
<p>与一元线性回归类似</p>
<ul>
<li>MSE:均方误差,用于衡量模型预测值与真实值之间的差异,越趋于0越好</li>
<li>R²:决定系数,用于评估线性回归模型拟合优度的重要指标,其取值范围为</li>
<li>回归系数:每个自变量的权重,表示自变量对结果的影响程度,<code>+</code>表示正相关,<code>-</code>表示负相关</li>
</ul>
<h2 id="深入理解多元线性回归">深入理解多元线性回归</h2>
<p>多元线性回归就是探索多个自变量对于结果的影响,相比于一元线性回归,它更加复杂,变化更多,但是适用性更广</p>
<h4 id="1-数学模型">1. 数学模型</h4>
<p></p><div class="math display">\[y = β_0 + β_1x_1 + β_2x_2 + \dots + β_nx_n + ϵ
\]</div><p></p><ul>
<li><span class="math inline">\(β_0\)</span> 叫做截距,在模型中起到了“基准值”的作用,就是当自变量为0的时候,因变量的基准值</li>
<li><span class="math inline">\(β_1\)</span> <span class="math inline">\(β_2\)</span> <span class="math inline">\(\dots\)</span> <span class="math inline">\(β_n\)</span> 叫做自变量系数或者回归系数,描述了自变量对结果的影响方向和大小
<ul>
<li>多元回归中,依然使用最小二乘法,是<code>scikit-learn</code>包的默认算法</li>
</ul>
</li>
<li>ϵ是误差项,代表了模型未能解释的部分</li>
</ul>
<h4 id="2-损失函数">2. 损失函数</h4>
<p>线性回归通常使用均方误差(MSE)来作为损失函数,衡量测试值与真实值之间的差异</p>
<p></p><div class="math display">\[\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2
\]</div><p></p><p>其中<span class="math inline">\(y_i\)</span>是真实值,<span class="math inline">\(\hat{y}_i\)</span>是预测值</p>
<p>正如前文提到,MSE中真实值与预测值,有平方计算,那就会放大误差,所以MSE可以非常有效的检测误差项</p>
<h4 id="3-最小二乘法">3. 最小二乘法</h4>
<p>与一元回归同理,常见的方法是最小二乘法,只不过推导方式要比一元回归更加复杂</p>
<h4 id="4-决定系数">4. 决定系数</h4>
<p>用于评估线性回归模型拟合优度的重要指标,其取值范围为 </p>
<p></p><div class="math display">\[R^2 = 1 - \frac{\sum_{i=1}^{n} (y_i - \hat{y}_i)^2}{\sum_{i=1}^{n} (y_i - \bar{y})^2}
\]</div><p></p><p>其中<span class="math inline">\(y_i\)</span>是真实值,<span class="math inline">\(\hat{y}_i\)</span>是预测值,<span class="math inline">\(\bar{y}\)</span>是均值</p>
<h4 id="5-调整决定系数">5. 调整决定系数</h4>
<p>先来看下决定系数的公式</p>
<p></p><div class="math display">\[R^2 = 1 - \frac{\sum_{i=1}^{n} (y_i - \hat{y}_i)^2}{\sum_{i=1}^{n} (y_i - \bar{y})^2}=1 - \frac{\sum_{i=1}^{n} (y_i - (β_0 + β_1x_1 + β_2x_2 + \dots + β_nx_n + ϵ))^2}{\sum_{i=1}^{n} (y_i - \bar{y})^2}
\]</div><p></p><p>随着自变量 <span class="math inline">\(x\)</span> 的增加,<span class="math inline">\(y_i - (β_0 + β_1x_1 + β_2x_2 + \dots + β_nx_n + ϵ)\)</span> 会越来越大,作为分子,导致R²也会越来越大。</p>
<p>在多元回归当中,只要增加自变量个数,就有可能让R²提升,所以单纯看R²是不真实的,需要额外的指标来判断</p>
<pre><code>import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

def adjusted_r2(r2, n, p):
    return 1 - (1 - r2) * (n - 1) / (n - p - 1)

np.random.seed(0)
n_samples = 1000

feature1 = np.random.rand(n_samples, 1)
result = 5 * feature1[:, 0] + np.random.normal(0, 10, n_samples)

data1 = {
    'result': list(result),
    'feature1': list(feature1),
}

df = pd.DataFrame(data1)

X1 = df[[
    'feature1',
]]
y1 = df['result']

model1 = LinearRegression().fit(X1, y1)
y_pred = model1.predict(X1)
r2_1 = r2_score(y1, y_pred)
print("\n模型1(feature1):")
print(f"R² = {r2_1:.4f}")

features = {
    'feature1': list(feature1),
    'feature2': list(np.random.rand(n_samples, 1)),
    'feature3': list(np.random.rand(n_samples, 1)),
    'feature4': list(np.random.rand(n_samples, 1)),
    'feature5': list(np.random.rand(n_samples, 1)),
    'feature6': list(np.random.rand(n_samples, 1)),
    'feature7': list(np.random.rand(n_samples, 1)),
    'feature8': list(np.random.rand(n_samples, 1)),
    'feature9': list(np.random.rand(n_samples, 1)),
}
data2 = {
    'result': list(result),
}
data2.update(features)
df2 = pd.DataFrame(data2)
y2 = df2['result']

X2 = df2[[
    'feature1',
    'feature2',
    'feature3',
    'feature4',
    'feature5',
    'feature6',
    'feature7',
    'feature9',
]]

model2 = LinearRegression().fit(X2, y2)
y_pred = model2.predict(X2)
r2_2 = r2_score(y2, y_pred)
print("\n模型2(feature1 ~ 9):")
print(f"R² = {r2_2:.4f}")

</code></pre>
<p>脚本!启动:<br>
<img alt="watermarked-multi_regression_1_2" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202508/1416773-20250818100050060-529961629.png" class="lazyload"></p>
<p>从1个特征,上升到9个特征,R²上升了一个百分点,0.0145 --&gt; 0.0213,理论上模型的泛化能力上升了,但正如之前分析的,随着参数的增多,有概率让R²提升,但是模型没有得到优化。所以需要有额外的指标来判断</p>
<p>调整决定系数:</p>
<p></p><div class="math display">\[R^2_{\text{adj}} = 1 - \left( \frac{(1 - R^2) (n - 1)}{n - k - 1} \right)
\]</div><p></p><ul>
<li>R²:决定系数</li>
<li>n:样本数</li>
<li>k:自变量(特征)数量</li>
</ul>
<p>调整决定系数的特点:</p>
<ul>
<li>惩罚不必要的变量:在计算时考虑了变量的个数,避免了无意义变量的加入带来的虚假提升。</li>
<li>更公平地比较不同的模型:当模型的自变量个数不同,直接比较决定系数可能会产生误导,而调整决定系数提供了更公平的衡量标准</li>
<li>在特征选择时更有参考价值:如果加入新变量后,调整决定系数下降,则说明这个变量可能是不必要的;如果调整决定系数上升,说明新变量有助于提升模型的解释能力。</li>
</ul>
<pre><code>import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

def adjusted_r2(r2, n, p):
    return 1 - (1 - r2) * (n - 1) / (n - p - 1)

np.random.seed(0)
n_samples = 1000

feature1 = np.random.rand(n_samples, 1)
result = 5 * feature1[:, 0] + np.random.normal(0, 10, n_samples)

data1 = {
    'result': list(result),
    'feature1': list(feature1),
}

df = pd.DataFrame(data1)

X1 = df[[
    'feature1',
]]
y1 = df['result']

model1 = LinearRegression().fit(X1, y1)
y_pred = model1.predict(X1)
r2_1 = r2_score(y1, y_pred)
r2_adj_1 = adjusted_r2(r2_1, n_samples, 1)
print("\n模型1(feature1):")
print(f"R² = {r2_1:.4f}, Adjusted R² = {r2_adj_1:.4f}")

features = {
    'feature1': list(feature1),
    'feature2': list(np.random.rand(n_samples, 1)),
    'feature3': list(np.random.rand(n_samples, 1)),
    'feature4': list(np.random.rand(n_samples, 1)),
    'feature5': list(np.random.rand(n_samples, 1)),
    'feature6': list(np.random.rand(n_samples, 1)),
    'feature7': list(np.random.rand(n_samples, 1)),
    'feature8': list(np.random.rand(n_samples, 1)),
    'feature9': list(np.random.rand(n_samples, 1)),
}
data2 = {
    'result': list(result),
}
data2.update(features)
df2 = pd.DataFrame(data2)
y2 = df2['result']

X2 = df2[[
    'feature1',
    'feature2',
    'feature3',
    'feature4',
    'feature5',
    'feature6',
    'feature7',
    'feature8',
    'feature9',
]]

model2 = LinearRegression().fit(X2, y2)
y_pred = model2.predict(X2)
r2_2 = r2_score(y2, y_pred)
r2_adj_2 = adjusted_r2(r2_2, n_samples, len(features.keys()))
print("\n模型2(feature1 ~ 9):")
print(f"R² = {r2_2:.4f}, Adjusted R² = {r2_adj_2:.4f}")
</code></pre>
<p><img alt="watermarked-multi_regression_1_3" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202508/1416773-20250818100102958-546909221.png" class="lazyload"></p>
<p>我们看到,虽然决定系数R²上升了,但是调整决定系数却下降了,这就表示虽然添加了额外的8个特征,并没有使得模型解释度上升,反而下降了</p>
<p>最后说下调整决定系数的取值范围</p>
<p></p><div class="math display">\[-\infty &lt; R^2_{\text{adj}} \leq 1
\]</div><p></p><ul>
<li>接近1:模型拟合非常好,自变量对因变量解释力强</li>
<li>接近0:模型几乎没有解释力,拟合效果很差</li>
<li>小于0:模型比用常数(均值)预测还差,严重不合理。可能过拟合或选错变量了</li>
</ul>
<p>没错,调整决定系数是可以小于0的</p>
<h2 id="lasso回归">Lasso回归</h2>
<p>简单概括就是可以自动筛选“无用特征”,并且放弃,然后重新训练模型。而筛选特征的方式是,经过lasso模型训练之后,无用特征的系数(注意这里不是线性回归系数,是lasso训练之后的回归系数)被标记为0</p>
<h4 id="1-数学模型-1">1. 数学模型</h4>
<p></p><div class="math display">\[\mathcal{L} = \frac{1}{2n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 + \lambda \sum_{j=1}^{p} |β_j|
\]</div><p></p><h4 id="2-实践">2. 实践</h4>
<p>继续上文的例子,新加了8个特征,但是造成的结果却是调整R²反而下降了,这就说明了有无用的特征加入了进来,这时我们用lasso进行特征筛选</p>
<pre><code>from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X2)

from sklearn.linear_model import Lasso
lasso = Lasso(alpha=0.1)

lasso.fit(X_scaled, y2)

for i, coef in enumerate(lasso.coef_, 1):
    print(f'x{i} 的系数:{coef:.4f}')

</code></pre>
<p><img alt="watermarked-multi_regression_1_4" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202508/1416773-20250818100115903-1079147821.png" class="lazyload"></p>
<p>找到了2个特征的系数为0,x4与x7,将这两个特征踢掉</p>
<pre><code>features = {
    'feature1': list(feature1),
    'feature2': list(np.random.rand(n_samples, 1)),
    'feature3': list(np.random.rand(n_samples, 1)),
    # 'feature4': list(np.random.rand(n_samples, 1)),
    'feature5': list(np.random.rand(n_samples, 1)),
    'feature6': list(np.random.rand(n_samples, 1)),
    # 'feature7': list(np.random.rand(n_samples, 1)),
    'feature8': list(np.random.rand(n_samples, 1)),
    'feature9': list(np.random.rand(n_samples, 1)),
}
</code></pre>
<pre><code>X2 = df2[[
    'feature1',
    'feature2',
    'feature3',
    # 'feature4',
    'feature5',
    'feature6',
    # 'feature7',
    'feature8',
    'feature9',
]]

</code></pre>
<p>再运行一遍</p>
<p><img alt="watermarked-multi_regression_1_5" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202508/1416773-20250818100126579-641439138.png" class="lazyload"></p>
<p>去掉了2个无用的特征,带来的就是模型R²的上升,并且调整R²也跟着上升了,说明了这些新加入的特征是真的有效果</p>
<p>lasso回归可以自动帮我们筛选特征,而刚才我们是先通过lasso回归将无用特征筛选出来,并且手动去掉,而这一切lasso回归可以自动帮我们完成</p>
<p>记住这个值,加入新的特征,模型R²<code>0.0211</code>,调整R²<code>0.0142</code></p>
<p>下面通过lasso自动筛选来完成,没有去掉特征,直接将下面代码加入</p>
<pre><code>from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X2)

from sklearn.linear_model import Lasso
lasso = Lasso(alpha=0.1)
lasso.fit(X_scaled, y2)

y_lasso = lasso.predict(X_scaled)
r2_lasso = r2_score(y2, y_lasso)
r2_adj_lasso = adjusted_r2(r2_lasso, n_samples, 7)
print("\nlasso模型:")
print(f"R² = {r2_lasso:.4f}, Adjusted R² = {r2_adj_lasso:.4f}")
</code></pre>
<p>脚本!启动:</p>
<p><img alt="watermarked-multi_regression_1_6" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202508/1416773-20250818100136778-411622711.png" class="lazyload"></p>
<p>不解释了!</p>
<h2 id="联系我">联系我</h2>
<ul>
<li>联系我,做深入的交流</li>
</ul>
<p><img alt="" width="500" height="200" loading="lazy" src="https://img2024.cnblogs.com/blog/1416773/202411/1416773-20241121135740959-1907948957.png#" class="lazyload"></p>
<hr>
<p>至此,本文结束<br>
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:it排球君,转载请注明原文链接:https://www.cnblogs.com/MrVolleyball/p/19044148</p>
<div>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。 </div><br><br>
来源:https://www.cnblogs.com/MrVolleyball/p/19044148
頁: [1]
查看完整版本: 彩笔运维勇闯机器学习--多元线性回归