【集成学习(上)】机器学习基础_02
# 引入相关科学计算包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use("ggplot")
import seaborn as sns
2. 使用sklearn构建完整的机器学习项目流程
一般来说,一个完整的机器学习项目分为以下步骤:
- 明确项目任务:回归/分类
- 收集数据集并选择合适的特征。
- 选择度量模型性能的指标。
- 选择具体的模型并进行训练以优化模型。
- 评估模型的性能并调参。
2.1 使用sklearn构建完整的回归项目(任务已明确)
(1) 收集数据集并选择合适的特征:
在数据集上我们使用我们比较熟悉的Boston房价数据集(数据集以明确)【实际应用中数据预处理也是一项繁重的工作】,原因是:
- 第一个,我们通过这些简单的数据集快速让我们上手sklearn,以及掌握sklearn的相关操作。
- 第二个,我们用简单的数据集能更加清晰地介绍机器学习的相关模型,避免在处理数据上花费较大的精力。
如果您对具体的项目感兴趣,我们会在第六章给出三个大型的案例让大家体验。
from sklearn import datasets
boston = datasets.load_boston() # 返回一个类似于字典的类X = boston.data
y = boston.target
features = boston.feature_names# 又用到 pandas 的内容
boston_data = pd.DataFrame(X, columns=features)
boston_data["Price"] = y
boston_data
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | Price | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 |
1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 |
2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 |
3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 |
4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
501 | 0.06263 | 0.0 | 11.93 | 0.0 | 0.573 | 6.593 | 69.1 | 2.4786 | 1.0 | 273.0 | 21.0 | 391.99 | 9.67 | 22.4 |
502 | 0.04527 | 0.0 | 11.93 | 0.0 | 0.573 | 6.120 | 76.7 | 2.2875 | 1.0 | 273.0 | 21.0 | 396.90 | 9.08 | 20.6 |
503 | 0.06076 | 0.0 | 11.93 | 0.0 | 0.573 | 6.976 | 91.0 | 2.1675 | 1.0 | 273.0 | 21.0 | 396.90 | 5.64 | 23.9 |
504 | 0.10959 | 0.0 | 11.93 | 0.0 | 0.573 | 6.794 | 89.3 | 2.3889 | 1.0 | 273.0 | 21.0 | 393.45 | 6.48 | 22.0 |
505 | 0.04741 | 0.0 | 11.93 | 0.0 | 0.573 | 6.030 | 80.8 | 2.5050 | 1.0 | 273.0 | 21.0 | 396.90 | 7.88 | 11.9 |
506 rows × 14 columns
各个特征的相关解释:
- CRIM:各城镇的人均犯罪率
- ZN:规划地段超过25,000平方英尺的住宅用地比例
- INDUS:城镇非零售商业用地比例
- CHAS:是否在查尔斯河边(=1是)
- NOX:一氧化氮浓度(/千万分之一)
- RM:每个住宅的平均房间数
- AGE:1940年以前建造的自住房屋的比例
- DIS:到波士顿五个就业中心的加权距离
- RAD:放射状公路的可达性指数
- TAX:全部价值的房产税率(每1万美元)
- PTRATIO:按城镇分配的学生与教师比例
- B:1000(Bk - 0.63)^2其中Bk是每个城镇的黑人比例
- LSTAT:较低地位人口
- Price:房价
(2) [选择度量模型性能的指标]
Theory Material
Experiment Material
- TP, FN, FP, TN 混淆矩阵
- 错误率,精准率,精确率,召回率
- F1 score
- P-R 图
- ROC, AUC
- 代价敏感错误率,代价曲线
- 多分类性能指标
- 聚类性能指标
- 回归性能指标(如下)
- MSE均方误差:MSE(y,y^)=1nsamples∑i=0nsamples−1(yi−y^i)2.\text{MSE}(y, \hat{y}) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples} - 1} (y_i - \hat{y}_i)^2.MSE(y,y^)=nsamples1∑i=0nsamples−1(yi−y^i)2.
- MAE平均绝对误差:MAE(y,y^)=1nsamples∑i=0nsamples−1∣yi−y^i∣\text{MAE}(y, \hat{y}) = \frac{1}{n_{\text{samples}}} \sum_{i=0}^{n_{\text{samples}}-1} \left| y_i - \hat{y}_i \right|MAE(y,y^)=nsamples1∑i=0nsamples−1∣yi−y^i∣
- R2R^2R2决定系数:R2(y,y^)=1−∑i=1n(yi−y^i)2∑i=1n(yi−yˉ)2R^2(y, \hat{y}) = 1 - \frac{\sum_{i=1}^{n} (y_i - \hat{y}_i)^2}{\sum_{i=1}^{n} (y_i - \bar{y})^2}R2(y,y^)=1−∑i=1n(yi−yˉ)2∑i=1n(yi−y^i)2
- 解释方差得分:explained_variance(y,y^)=1−Var{y−y^}Var{y}explained\_{}variance(y, \hat{y}) = 1 - \frac{Var\{ y - \hat{y}\}}{Var\{y\}}explained_variance(y,y^)=1−Var{y}Var{y−y^}
https://scikit-learn.org/stable/modules/model_evaluation.html#regression-metrics
在这个案例中,我们使用MSE均方误差为模型的性能度量指标。
(3) 选择具体的模型并进行训练
2.1.1 线性回归模型
李宏毅线性回归理论
李宏毅线性回归实验
回归这个概念是19世纪80年代由英国统计学家郎西斯.高尔顿在研究父子身高关系提出来的,他发现:在同一族群中,子代的平均身高介于父代的身高以及族群的平均身高之间。具体而言,高个子父亲的儿子的身高有低于其父亲身高的趋势,而矮个子父亲的儿子身高则有高于父亲的身高的趋势。也就是说,子代的身高有向族群平均身高"平均"的趋势,这就是统计学上"回归"的最初含义。回归分析是一种预测性的建模技术,它研究的是因变量(目标)和自变量(特征)之间的关系。这种技术通常用于预测分析,时间序列模型以及发现变量之间的因果关系。通常使用曲线/线来拟合数据点,目标是使曲线到数据点的距离差异最小。而线性回归就是回归问题中的一种,线性回归假设目标值与特征之间线性相关,即满足一个多元一次方程。通过构建损失函数,来求解损失函数最小时的参数w :
假设:数据集D={(x1,y1),...,(xN,yN)}D = \{(x_1,y_1),...,(x_N,y_N) \}D={(x1,y1),...,(xN,yN)},xi∈Rp,yi∈R,i=1,2,...,Nx_i \in R^p,y_i \in R,i = 1,2,...,Nxi∈Rp,yi∈R,i=1,2,...,N,X=(x1,x2,...,xN)T,Y=(y1,y2,...,yN)TX = (x_1,x_2,...,x_N)^T,Y=(y_1,y_2,...,y_N)^TX=(x1,x2,...,xN)T,Y=(y1,y2,...,yN)T
假设X和Y之间存在线性关系,模型的具体形式为y^=f(w)=wTx\hat{y}=f(w) =w^Txy^=f(w)=wTx
(a) 最小二乘估计:
我们需要衡量真实值yiy_iyi与线性回归模型的预测值wTxiw^Tx_iwTxi之间的差距,在这里我们和使用二范数的平方和L(w)来描述这种差距,即:
L(w)=∑i=1N∣∣wTxi−yi∣∣22=∑i=1N(wTxi−yi)2=(wTXT−YT)(wTXT−YT)T=wTXTXw−2wTXTY+YYT(wTXT−YT)(wTXT−YT)T:((1⋅p∗(N⋅p)T−1⋅N)∗(1⋅p∗(N⋅p)T−1⋅N)T因此,我们需要找到使得L(w)最小时对应的参数w,即:w^=argminL(w)为了达到求解最小化L(w)问题,我们应用高等数学的知识,使用求导来解决这个问题:∂L(w)∂w=2XTXw−2XTY=0,因此:w^=(XTX)−1XTYL(w) = \sum\limits_{i=1}^{N}||w^Tx_i-y_i||_2^2=\sum\limits_{i=1}^{N}(w^Tx_i-y_i)^2 = (w^TX^T-Y^T)(w^TX^T-Y^T)^T = w^TX^TXw - 2w^TX^TY+YY^T\\ (w^TX^T-Y^T)(w^TX^T-Y^T)^T: \\ ((1\cdot p * (N \cdot p)^T - 1 \cdot N) * (1\cdot p * (N \cdot p)^T - 1 \cdot N)^T\\ 因此,我们需要找到使得L(w)最小时对应的参数w,即:\\ \hat{w} = argmin\;L(w)\\ 为了达到求解最小化L(w)问题,我们应用高等数学的知识,使用求导来解决这个问题: \\ \frac{\partial L(w)}{\partial w} = 2X^TXw-2X^TY = 0,因此: \\ \hat{w} = (X^TX)^{-1}X^TY L(w)=i=1∑N∣∣wTxi−yi∣∣22=i=1∑N(wTxi−yi)2=(wTXT−YT)(wTXT−YT)T=wTXTXw−2wTXTY+YYT(wTXT−YT)(wTXT−YT)T:((1⋅p∗(N⋅p)T−1⋅N)∗(1⋅p∗(N⋅p)T−1⋅N)T因此,我们需要找到使得L(w)最小时对应的参数w,即:w^=argminL(w)为了达到求解最小化L(w)问题,我们应用高等数学的知识,使用求导来解决这个问题:∂w∂L(w)=2XTXw−2XTY=0,因此:w^=(XTX)−1XTY
(b) 几何解释:
在线性代数中,我们知道两个向量a和b相互垂直可以得出:<a,b>=a.b=aTb=0<a,b> = a.b = a^Tb = 0<a,b>=a.b=aTb=0,而平面X的法向量为Y-Xw,与平面X互相垂直,因此:XT(Y−Xw)=0X^T(Y-Xw) = 0XT(Y−Xw)=0,即:w=(XTX)−1XTYw = (X^TX)^{-1}X^TYw=(XTX)−1XTY
© 概率视角:
假设噪声ϵ∽N(0,σ2),y=f(w)+ϵ=wTx+ϵ\epsilon \backsim N(0,\sigma^2),y=f(w)+\epsilon=w^Tx+\epsilonϵ∽N(0,σ2),y=f(w)+ϵ=wTx+ϵ,因此:y∣xi,wN(wTx,σ2)y|x_i,w ~ N(w^Tx,\sigma^2)y∣xi,w N(wTx,σ2)
我们使用极大似然估计MLE对参数w进行估计:
L(w)=logP(Y∣X;w)=log∏i=1NP(yi∣xi;w)=∑i=1NlogP(yi∣xi;w)=∑i=1Nlog(12πσexp(−(yi−wTxi)22σ2))=∑i=1N[log(12πσ)−12σ2(yi−wTxi)2]argmaxwL(w)=argminw[l(w)=∑i=1N(yi−wTxi)2]因此:线性回归的最小二乘估计<==>噪声ϵ∽N(0,σ2)的极大似然估计L(w) = log\;P(Y|X;w) = log\;\prod_{i=1}^N P(y_i|x_i;w) = \sum\limits_{i=1}^{N} log\; P(y_i|x_i;w)\\ = \sum\limits_{i=1}^{N}log(\frac{1}{\sqrt{2\pi \sigma}}exp(-\frac{(y_i-w^Tx_i)^2}{2\sigma^2})) = \sum\limits_{i=1}^{N}[log(\frac{1}{\sqrt{2\pi}\sigma})-\frac{1}{2\sigma^2}(y_i-w^Tx_i)^2] \\ argmax_w L(w) = argmin_w[l(w) = \sum\limits_{i = 1}^{N}(y_i-w^Tx_i)^2]\\ 因此:线性回归的最小二乘估计<==>噪声\epsilon\backsim N(0,\sigma^2)的极大似然估计 L(w)=logP(Y∣X;w)=logi=1∏NP(yi∣xi;w)=i=1∑NlogP(yi∣xi;w)=i=1∑Nlog(2πσ1exp(−2σ2(yi−wTxi)2))=i=1∑N[log(2πσ1)−2σ21(yi−wTxi)2]argmaxwL(w)=argminw[l(w)=i=1∑N(yi−wTxi)2]因此:线性回归的最小二乘估计<==>噪声ϵ∽N(0,σ2)的极大似然估计
下面,我们使用sklearn的线性回归实例来演示:
https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html#sklearn.linear_model.LinearRegression
【机器学习一览】
from sklearn import linear_model # 引入线性回归方法
lin_reg = linear_model.LinearRegression() # 创建线性回归的类
lin_reg.fit(X,y) # 输入特征X和因变量y进行训练
print("模型系数:",lin_reg.coef_) # 输出模型的系数
print("模型得分:",lin_reg.score(X,y)) # 输出模型的决定系数 R^2
模型系数: [-1.08011358e-01 4.64204584e-02 2.05586264e-02 2.68673382e+00-1.77666112e+01 3.80986521e+00 6.92224640e-04 -1.47556685e+003.06049479e-01 -1.23345939e-02 -9.52747232e-01 9.31168327e-03-5.24758378e-01]
模型得分: 0.7406426641094095
2.1.2 线性回归的推广
[【相关研读】7种线性模型及其选择](https://zhuanlan.zhihu.com/p/40141010)
- 线性回归: 最小二乘法, R-square
- 多元回归:多重共线性,自相关性,异方差性
- 对异常值敏感
- …- 逻辑回归
- 分类问题
- 多类型关系,预测输出进行了非线性log- 多项式回归
- 避免过拟合- 逐步回归
- 处理多个独立变量
- 最少的自变量在得到最大的预测能力
- 处理高维数据集- 岭回归
- 缩小系数的值
- 正则化方法:L2正则化- 套索回归
- 惩罚的是回归系数的绝对值, L1 正则化
- 减少变异性和提高线性回归模型的准确性
- 如果一组自变量高度相关,那么套索回归只会选择其中一个- 弹性回归
- 弹性回归是岭回归和套索回归的混合技术,它同时使用 L2 和 L1 正则化。
- 支持群体效应
- 变量数目无限制
- 两个收缩因子
如何选择
数据挖掘是建立预测模型不可缺少的环节。这应该是选择正确的模型的第一步,比如确定各变量的关系和影响。
比较适合于不同模型的拟合程度,我们可以分析它们不同的指标参数,例如统计意义的参数,R-square,Adjusted R-square,AIC,BIC 以及误差项,另一个是 Mallows’ Cp 准则。通过将模型与所有可能的子模型进行对比(或小心地选择他们),检查模型可能的偏差。
交叉验证是评价预测模型的最佳方法。你可以将数据集分成两组(训练集和验证集)。通过衡量观测值和预测值之间简单的均方差就能给出预测精度的度量。
如果数据集有多个混合变量,则不应使用自动模型选择方法,因为不希望同时将这些混合变量放入模型中。
这也取决于你的目标。与高度统计学意义的模型相比,简单的模型更容易实现。
回归正则化方法(LasSo、Ridge 和 ElasticNet)在数据集是高维和自变量是多重共线性的情况下工作良好。
两种回归模型(的推广)
在线性回归中,我们假设因变量与特征之间的关系是线性关系,这样的假设使得模型很简单,但是缺点也是显然的,那就是当数据存在非线性关系时,我们使用线性回归模型进行预测会导致预测性能极其低下,因为模型的形式本身是线性的,无法表达数据中的非线性关系。我们一个很自然的想法就是去推广线性回归模型,使得推广后的模型更能表达非线性的关系。
(a) 多项式回归:
为了体现因变量和特征的非线性关系,一个很自然而然的想法就是将标准的线性回归模型:
yi=w0+w1xi+ϵiy_i = w_0 + w_1x_i + \epsilon_i yi=w0+w1xi+ϵi
换成一个多项式函数:
yi=w0+w1xi+w2xi2+...+wdxid+ϵy_i = w_0 + w_1x_i + w_2x_i^2 + ...+w_dx_i^d + \epsilon yi=w0+w1xi+w2xi2+...+wdxid+ϵ
对于多项式的阶数d不能取过大,一般不大于3或者4,因为d越大,多项式曲线就会越光滑,在X的边界处有异常的波动。(图中的边界处的4阶多项式拟合曲线的置信区间(虚线表示置信区间)明显增大,预测效果的稳定性下降。)
(a) 多项式回归实例介绍:
https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html?highlight=poly#sklearn.preprocessing.PolynomialFeatures
sklearn.preprocessing.PolynomialFeatures(degree=2, *, interaction_only=False, include_bias=True, order=‘C’):
- 参数:
degree:特征转换的阶数。
interaction_onlyboolean:是否只包含交互项,默认False 。
include_bias:是否包含截距项,默认True。
order:str in {‘C’, ‘F’}, default ‘C’,输出数组的顺序。
# 通过求解新构造的 X ,达到将普通的线性回归模型,转换为了多项式线性回归问题
from sklearn.preprocessing import PolynomialFeatures
X_arr = np.arange(6).reshape(3, 2)
print("原始X为:\n",X_arr)poly = PolynomialFeatures(2)
print("3*2 2次转化X:\n",poly.fit_transform(X_arr))
# 3 × 2 --> 3 × (1 + 2 + 3)X_arr = np.arange(9).reshape(3, 3)
print("原始X为:\n",X_arr)poly = PolynomialFeatures(2)
print("3*3 2次转化X:\n",poly.fit_transform(X_arr))
# 3 × 2 --> 3 × (1 + 3 + 6)poly = PolynomialFeatures(interaction_only=True)
print("3*2 interaction only 2次转化X:\n",poly.fit_transform(X_arr))
原始X为:[[0 1][2 3][4 5]]
3*2 2次转化X:[[ 1. 0. 1. 0. 0. 1.][ 1. 2. 3. 4. 6. 9.][ 1. 4. 5. 16. 20. 25.]]
原始X为:[[0 1 2][3 4 5][6 7 8]]
3*3 2次转化X:[[ 1. 0. 1. 2. 0. 0. 0. 1. 2. 4.][ 1. 3. 4. 5. 9. 12. 15. 16. 20. 25.][ 1. 6. 7. 8. 36. 42. 48. 49. 56. 64.]]
3*2 interaction only 2次转化X:[[ 1. 0. 1. 2. 0. 0. 2.][ 1. 3. 4. 5. 12. 15. 20.][ 1. 6. 7. 8. 42. 48. 56.]]
"""
使用 PolynomialFeatures 自动生成特征矩阵
"""
from sklearn.preprocessing import PolynomialFeatures# 拟合数据集
x = [4, 8, 12, 25, 32, 43, 58, 63, 69, 79]
y = [20, 33, 50, 56, 42, 31, 33, 46, 65, 75]x = np.array(x).reshape(len(x), 1) # 转换为列向量
y = np.array(y).reshape(len(y), 1)poly_features = PolynomialFeatures(degree=2, include_bias=False)
# 特征矩阵模型构建用来多项式的特征矩阵
poly_x = poly_features.fit_transform(x)
# 通过模型转换x数据poly_features2 = PolynomialFeatures(degree=3, include_bias=False)
poly_x2 = poly_features2.fit_transform(x)"""用线性回归拟合上面转换后的数据
"""
from sklearn.linear_model import LinearRegressionmodel = LinearRegression()
model.fit(poly_x,y) # 这里使用转换后的特征矩阵相当于将一元2次转换为二元一次
# print(model.intercept_,model.coef_)model2 = LinearRegression()
model2.fit(poly_x2, y)"""绘制拟合图像
"""
x_temp = np.linspace(0, 80, 10000)
x_temp = np.array(x_temp).reshape(len(x_temp),1)
poly_x_temp = poly_features.fit_transform(x_temp)
poly_x_temp2 = poly_features2.fit_transform(x_temp)
plt.plot(x_temp, model.predict(poly_x_temp), 'r', label = 'degree = 2')
plt.plot(x_temp, model2.predict(poly_x_temp2), 'b', label = 'degree = 3')
plt.scatter(x, y)
plt.show() # 得到的结果与上面用leastsq的二次项结果一致
(b) 广义可加模型(GAM):
广义可加模型GAM实际上是线性模型推广至非线性模型的一个框架,在这个框架中,每一个变量都用一个非线性函数来代替,但是模型本身保持整体可加性。GAM模型不仅仅可以用在线性回归的推广,还可以将线性分类模型进行推广。具体的推广形式是:
标准的线性回归模型:
yi=w0+w1xi1+...+wpxip+ϵiy_i = w_0 + w_1x_{i1} +...+w_px_{ip} + \epsilon_i yi=w0+w1xi1+...+wpxip+ϵi
GAM模型框架:
yi=w0+∑j=1pfj(xij)+ϵiy_i = w_0 + \sum\limits_{j=1}^{p}f_{j}(x_{ij}) + \epsilon_i yi=w0+j=1∑pfj(xij)+ϵi
GAM模型的优点与不足:
- 优点:简单容易操作,能够很自然地推广线性回归模型至非线性模型,使得模型的预测精度有所上升;由于模型本身是可加的,因此GAM还是能像线性回归模型一样把其他因素控制不变的情况下单独对某个变量进行推断,极大地保留了线性回归的易于推断的性质。
- 缺点:GAM模型会经常忽略一些有意义的交互作用,比如某两个特征共同影响因变量,不过GAM还是能像线性回归一样加入交互项x(i)×x(j)x^{(i)} \times x^{(j)}x(i)×x(j)的形式进行建模;但是GAM模型本质上还是一个可加模型,如果我们能摆脱可加性模型形式,可能还会提升模型预测精度,详情请看后面的算法。
(b) GAM模型实例介绍:
GAM 详细分析解释
安装pygam:pip install pygam
https://github.com/dswah/pyGAM/blob/master/doc/source/notebooks/quick_start.ipynb
from pygam import LinearGAM
gam = LinearGAM().fit(boston_data[boston.feature_names], y)
gam.summary()
LinearGAM
=============================================== ==========================================================
Distribution: NormalDist Effective DoF: 103.2423
Link Function: IdentityLink Log Likelihood: -1589.7653
Number of Samples: 506 AIC: 3388.0152AICc: 3442.7649GCV: 13.7683Scale: 8.8269Pseudo R-Squared: 0.9168
==========================================================================================================
Feature Function Lambda Rank EDoF P > x Sig. Code
================================= ==================== ============ ============ ============ ============
s(0) [0.6] 20 11.1 2.20e-11 ***
s(1) [0.6] 20 12.8 8.15e-02 .
s(2) [0.6] 20 13.5 2.59e-03 **
s(3) [0.6] 20 3.8 2.76e-01
s(4) [0.6] 20 11.4 1.11e-16 ***
s(5) [0.6] 20 10.1 1.11e-16 ***
s(6) [0.6] 20 10.4 8.22e-01
s(7) [0.6] 20 8.5 4.44e-16 ***
s(8) [0.6] 20 3.5 5.96e-03 **
s(9) [0.6] 20 3.4 1.33e-09 ***
s(10) [0.6] 20 1.8 3.26e-03 **
s(11) [0.6] 20 6.4 6.25e-02 .
s(12) [0.6] 20 6.5 1.11e-16 ***
intercept 1 0.0 2.23e-13 ***
==========================================================================================================
Significance codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1WARNING: Fitting splines and a linear function to a feature introduces a model identifiability problemwhich can cause p-values to appear significant when they are not.WARNING: p-values calculated in this manner behave correctly for un-penalized models or models withknown smoothing parameters, but when smoothing parameters have been estimated, the p-valuesare typically lower than they should be, meaning that the tests reject the null too readily./home/lance/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:3: UserWarning: KNOWN BUG: p-values computed in this summary are likely much smaller than they should be. Please do not make inferences based on these values! Collaborate on a solution, and stay up to date at:
github.com/dswah/pyGAM/issues/163 This is separate from the ipykernel package so we can avoid doing imports until
2.1.3回归树:
基于树的回归方法主要是依据分层和分割的方式将特征空间划分为一系列简单的区域。对某个给定的待预测的自变量,用他所属区域中训练集的平均数或者众数对其进行预测。由于划分特征空间的分裂规则可以用树的形式进行概括,因此这类方法称为决策树方法。决策树由结点(node)和有向边(diredcted edge)组成。结点有两种类型:内部结点(internal node)和叶结点(leaf node)。内部结点表示一个特征或属性,叶结点表示一个类别或者某个值。区域R1,R2R_1,R_2R1,R2等称为叶节点,将特征空间分开的点为内部节点。
建立回归树的过程大致可以分为以下两步:
- 将自变量的特征空间(即x(1),x(2),x(3),...,x(p)x^{(1)},x^{(2)},x^{(3)},...,x^{(p)}x(1),x(2),x(3),...,x(p))的可能取值构成的集合分割成J个互不重叠的区域R1,R2,...,RjR_1,R_2,...,R_jR1,R2,...,Rj。
- 对落入区域RjR_jRj的每个观测值作相同的预测,预测值等于RjR_jRj上训练集的因变量的简单算术平均。
具体来说,就是:
a. 选择最优切分特征j以及该特征上的最优点s:
遍历特征j以及固定j后遍历切分点s,选择使得下式最小的(j,s) minj,s[minc1∑xi∈R1(j,s)(yi−c1)2+minc2∑xi∈R2(j,s)(yi−c2)2]min_{j,s}[min_{c_1}\sum\limits_{x_i\in R_1(j,s)}(y_i-c_1)^2 + min_{c_2}\sum\limits_{x_i\in R_2(j,s)}(y_i-c_2)^2 ]minj,s[minc1xi∈R1(j,s)∑(yi−c1)2+minc2xi∈R2(j,s)∑(yi−c2)2]
b. 按照(j,s)分裂特征空间:R1(j,s)={x∣xj≤s}和R2(j,s)={x∣xj>s},c^m=1Nm∑x∈Rm(j,s)yi,m=1,2R_1(j,s) = \{x|x^{j} \le s \}和R_2(j,s) = \{x|x^{j} > s \},\hat{c}_m = \frac{1}{N_m}\sum\limits_{x \in R_m(j,s)}y_i,\;m=1,2R1(j,s)={x∣xj≤s}和R2(j,s)={x∣xj>s},c^m=Nm1x∈Rm(j,s)∑yi,m=1,2
c. 继续调用步骤1,2直到满足停止条件,就是每个区域的样本数小于等于5。
d. 将特征空间划分为J个不同的区域,生成回归树:f(x)=∑m=1Jc^mI(x∈Rm)f(x) = \sum\limits_{m=1}^{J}\hat{c}_mI(x \in R_m)f(x)=m=1∑Jc^mI(x∈Rm)
如以下生成的关于运动员在棒球大联盟数据的回归树:
回归树与线性模型的比较:
线性模型的模型形式与树模型的模型形式有着本质的区别,具体而言,线性回归对模型形式做了如下假定:
f(x)=w0+∑j=1pwjx(j)f(x) = w_0 + \sum\limits_{j=1}^{p}w_jx^{(j)}f(x)=w0+j=1∑pwjx(j)
,
而回归树则是:
f(x)=∑m=1Jc^mI(x∈Rm)f(x) = \sum \limits_{m=1}^{J}\hat{c}_mI(x \in R_m)f(x)=m=1∑Jc^mI(x∈Rm)
。那问题来了,哪种模型更优呢?这个要视具体情况而言,如果特征变量与因变量的关系能很好的用线性关系来表达,那么线性回归通常有着不错的预测效果,拟合效果则优于不能揭示线性结构的回归树。反之,如果特征变量与因变量的关系呈现高度复杂的非线性,那么树方法比传统方法更优。
树模型的优缺点:
- 树模型的解释性强,在解释性方面可能比线性回归还要方便。
- 树模型更接近人的决策方式。
- 树模型可以用图来表示,非专业人士也可以轻松解读。
- 树模型可以直接做定性的特征而不需要像线性回归一样哑元化。
- 树模型能很好处理缺失值和异常值,对异常值不敏感,但是这个对线性模型来说却是致命的。
- 树模型的预测准确性一般无法达到其他回归模型的水平,但是改进的方法很多。
sklearn使用回归树的实例:
https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeRegressor.html?highlight=tree#sklearn.tree.DecisionTreeRegressor
sklearn.tree.DecisionTreeRegressor(*, criterion=‘mse’, splitter=‘best’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, presort=‘deprecated’, ccp_alpha=0.0)
- 参数:(列举几个重要的,常用的,详情请看上面的官网)
criterion:{“ mse”,“ friedman_mse”,“ mae”},默认=“ mse”。衡量分割标准的函数 。
splitter:{“best”, “random”}, default=”best”。分割方式。
max_depth:树的最大深度。
min_samples_split:拆分内部节点所需的最少样本数,默认是2。
min_samples_leaf:在叶节点处需要的最小样本数。默认是1。
min_weight_fraction_leaf:在所有叶节点处(所有输入样本)的权重总和中的最小加权分数。如果未提供sample_weight,则样本的权重相等。默认是0。
from sklearn.tree import DecisionTreeRegressor
reg_tree = DecisionTreeRegressor(criterion = "mse",min_samples_leaf = 5)
reg_tree.fit(X,y)
reg_tree.score(X,y)
0.9376307599929274
【参考资料】
【理论】CART决策树算法
【实验】CART回归树分析与python实现(非掉实现包)
2.1.4 支持向量机回归(SVR)
**【参考资料】统计学习方法 **
【视频】白板推导svm
在介绍支持向量回归SVR之前,我们先来了解下约束优化的相关知识:
约束优化问题§:
minf(x)s.t.gi(x)≤0,i=1,2,...,mhj(x)=0,j=1,2,...,lmin f(x) \\ s.t.\;\;\;g_i(x) \le 0,\; i=1,2,...,m\\ \;\;\;\;\; h_j(x) = 0,\; j=1,2,...,l minf(x)s.t.gi(x)≤0,i=1,2,...,mhj(x)=0,j=1,2,...,l
我们假设x∗x^*x∗为满足以上条件的局部最优解,p∗=f(x∗)p^* = f(x^*)p∗=f(x∗),我们的目的就是要找到x∗x^*x∗与p∗p^*p∗,满足不等式和等式约束的x集合称为可行域,记作S。KKT条件(最优解的一阶必要条件)
因为KKT条件是最优化的相关内容,在本次开源学习中并不是重点,因此在这里我用一个更加简单的例子说明KKT条件,严格的证明请参见凸优化相关书籍。
在这个例子中,我们考虑:(x∗x^*x∗为我们的最优解)
minf(x)s.t.g1(x)≤0,x∈Rng2(x)≤0g3(x)≤0minf(x)\\ s.t.\;g_1(x) \le 0,\;x \in R^n\\ \;\;\;g_2(x) \le 0\\ \;\;\;g_3(x) \le 0 minf(x)s.t.g1(x)≤0,x∈Rng2(x)≤0g3(x)≤0
我们可以看到:−∇f(x∗)-\nabla f(x^*)−∇f(x∗)可以由∇g1(x∗)\nabla g_1(x^*)∇g1(x∗)与∇g2(x∗)\nabla g_2(x^*)∇g2(x∗)线性表出,因此有:−∇f(x∗)=λ1∇g1(x∗)+λ2∇g2(x∗)-\nabla f(x^*) = \lambda_1 \nabla g_1(x^*) + \lambda_2 \nabla g_2(x^*)−∇f(x∗)=λ1∇g1(x∗)+λ2∇g2(x∗),其中λ1,λ2≥0\lambda_1,\lambda_2 \ge 0λ1,λ2≥0,即:
∇f(x∗)+λ1∇g1(x∗)+λ2∇g2(x∗)=0,其中λ1,λ2≥0\nabla f(x^*) + \lambda_1 \nabla g_1(x^*) + \lambda_2 \nabla g_2(x^*) = 0,\;\;\;其中\lambda_1,\lambda_2 \ge 0 ∇f(x∗)+λ1∇g1(x∗)+λ2∇g2(x∗)=0,其中λ1,λ2≥0
我们把没有起作用的约束g3(x)g_3(x)g3(x)也放到式子里面去,目的也就是为了书写方便,即要求:
∇f(x∗)+λ1∇g1(x∗)+λ2∇g2(x∗)+λ3∇g3(x∗)=0,其中λ1,λ2≥0,λ3=0\nabla f(x^*) + \lambda_1 \nabla g_1(x^*) + \lambda_2 \nabla g_2(x^*) + \lambda_3 \nabla g_3(x^*)= 0,\;\;\;其中\lambda_1,\lambda_2 \ge 0,\lambda_3 = 0 ∇f(x∗)+λ1∇g1(x∗)+λ2∇g2(x∗)+λ3∇g3(x∗)=0,其中λ1,λ2≥0,λ3=0
由于点x∗x^*x∗位于方程g1(x)=0g_1(x)=0g1(x)=0与g2(x)=0g_2(x)=0g2(x)=0上,因此:λ1g1(x∗)=0,λ2g2(x∗)=0,λ3g3(x∗)=0\lambda_1 g_1(x^*) = 0,\lambda_2 g_2(x^*) = 0 , \lambda_3 g_3(x^*)= 0λ1g1(x∗)=0,λ2g2(x∗)=0,λ3g3(x∗)=0
因此,KKT条件就是:假设x∗x^*x∗为最优化问题§的局部最优解,且x∗x^*x∗ 在某个适当的条件下 ,有:
∇f(x∗)+∑i=1mλi∇g(x∗)+∑j=1lμj∇hj(x∗)=0(对偶条件)λi≥0,i=1,2,...,m(对偶条件)gi(x∗)≤0(原问题条件)hj(x∗)=0(原问题条件)λig(x∗)=0(互补松弛定理)\nabla f(x^*) + \sum\limits_{i=1}^{m}\lambda_i \nabla g(x^*) + \sum\limits_{j=1}^{l}\mu_j \nabla h_j(x^*) = 0(对偶条件)\\ \lambda_i \ge 0,\;i = 1,2,...,m(对偶条件)\\ g_i(x^*) \le 0(原问题条件)\\ h_j(x^*) = 0(原问题条件)\\ \lambda_i g(x^*) = 0(互补松弛定理) ∇f(x∗)+i=1∑mλi∇g(x∗)+j=1∑lμj∇hj(x∗)=0(对偶条件)λi≥0,i=1,2,...,m(对偶条件)gi(x∗)≤0(原问题条件)hj(x∗)=0(原问题条件)λig(x∗)=0(互补松弛定理)
对偶理论:
为什么要引入对偶问题呢?是因为原问题与对偶问题就像是一个问题两个角度去看,如利润最大与成本最低等。有时侯原问题上难以解决,但是在对偶问题上就会变得很简单。再者,任何一个原问题在变成对偶问题后都会变成一个凸优化的问题,这点我们后面会有介绍。下面我们来引入对偶问题:
首先,我们的原问题§是:
minf(x)s.t.gi(x)≤0,i=1,2,...,mhj(x)=0,j=1,2,...,lmin f(x) \\ s.t.\;\;\;g_i(x) \le 0,\; i=1,2,...,m\\ \;\;\;\;\; h_j(x) = 0,\; j=1,2,...,l minf(x)s.t.gi(x)≤0,i=1,2,...,mhj(x)=0,j=1,2,...,l
引入拉格朗日函数:L(x,λ,μ)=f(x)+∑i=1mλigi(x)+∑j=1lμjhj(x)L(x,\lambda,\mu) = f(x) + \sum\limits_{i=1}^{m}\lambda_i g_i(x) + \sum\limits_{j=1}^{l}\mu_j h_j(x)L(x,λ,μ)=f(x)+i=1∑mλigi(x)+j=1∑lμjhj(x)
拉格朗日对偶函数:
d(λ,μ)=minx∈X{f(x)+∑i=1mλigi(x)+∑j=1lμjhj(x)},其中X为满足条件的x变量≤minx∈S{f(x)+∑i=1mλigi(x)+∑j=1lμjhj(x)}由于gi(x)≤0,hj(x)=0,λi≥0,其中S为可行域≤minx∈S{f(x)}d(\lambda,\mu) = min_{x\in X}\{ f(x) + \sum\limits_{i=1}^{m}\lambda_i g_i(x) + \sum\limits_{j=1}^{l}\mu_j h_j(x)\} ,其中X为满足条件的x变量\\ \le min_{x\in S}\{ f(x) + \sum\limits_{i=1}^{m}\lambda_i g_i(x) + \sum\limits_{j=1}^{l}\mu_j h_j(x) \}\\ 由于g_i(x) \le 0,h_j(x) = 0,\lambda_i \ge 0 ,其中S为可行域\\ \le min_{x\in S}\{f(x) \} d(λ,μ)=minx∈X{f(x)+i=1∑mλigi(x)+j=1∑lμjhj(x)},其中X为满足条件的x变量≤minx∈S{f(x)+i=1∑mλigi(x)+j=1∑lμjhj(x)}由于gi(x)≤0,hj(x)=0,λi≥0,其中S为可行域≤minx∈S{f(x)}
因此:拉格朗日对偶函数d(λ,μ)d(\lambda,\mu)d(λ,μ)是原问题最优解的函数值p∗p^*p∗的下界,即每个不同的λ\lambdaλ与μ\muμ确定的d(λ,μ)d(\lambda,\mu)d(λ,μ)都是p∗p^*p∗的下界,但是我们希望下界越大越好,因为越大就更能接近真实的p∗p^*p∗。因此:
拉格朗日对偶问题(D)转化为:
maxλ,μd(λ,μ)s.t.λi≥0,i=1,2,...,m也就是:maxλ≥0,μminx∈SL(x,λ,μ)max_{\lambda,\mu}d(\lambda,\mu)\\ s.t. \lambda_i \ge 0,i = 1,2,...,m\\ 也就是:\\ max_{\lambda \ge 0,\mu}\;min_{x \in S} L(x,\lambda,\mu) maxλ,μd(λ,μ)s.t.λi≥0,i=1,2,...,m也就是:maxλ≥0,μminx∈SL(x,λ,μ)
我们可以观察到,对偶问题是关于λ\lambdaλ和μ\muμ的线性函数,因此对偶问题是一个凸优化问题,凸优化问题在最优化理论较为简单。
弱对偶定理:对偶问题(D)的最优解D∗D^*D∗一定小于原问题最优解P∗P^*P∗,这点在刚刚的讨论得到了充分的证明,一定成立。
强对偶定理:对偶问题(D)的最优解D∗D^*D∗在一定的条件下等于原问题最优解P∗P^*P∗,条件非常多样化且不是唯一的,也就是说这是个开放性的问题,在这里我给出一个最简单的条件,即:f(x)f(x)f(x)与gi(x)g_i(x)gi(x)为凸函数,hj(x)h_j(x)hj(x)为线性函数,X是凸集,x∗x^*x∗满足KKT条件,那么D∗=P∗D^* = P^*D∗=P∗。支持向量回归SVR
在介绍完了相关的优化知识以后,我们开始正式学习支持向量回归SVR。
在线性回归的理论中,每个样本点都要计算平方损失,但是SVR却是不一样的。SVR认为:落在f(x)f(x)f(x)的ϵ\epsilonϵ邻域空间中的样本点不需要计算损失,这些都是预测正确的,其余的落在ϵ\epsilonϵ邻域空间以外的样本才需要计算损失,因此:
minw,b,ξi,ξ^i12∣∣w∣∣2+C∑i=1N(ξi,ξ^i)s.t.f(xi)−yi≤ϵ+ξiyi−f(xi)≤ϵ+ξ^iξi,ξ^i≤0,i=1,2,...,Nmin_{w,b,\xi_i,\hat{\xi}_i} \frac{1}{2}||w||^2 +C \sum\limits_{i=1}^{N}(\xi_i,\hat{\xi}_i)\\ s.t.\;\;\; f(x_i) - y_i \le \epsilon + \xi_i\\ \;\;\;\;\;y_i - f(x_i) \le \epsilon +\hat{\xi}_i\\ \;\;\;\;\; \xi_i,\hat{\xi}_i \le 0,i = 1,2,...,N minw,b,ξi,ξ^i21∣∣w∣∣2+Ci=1∑N(ξi,ξ^i)s.t.f(xi)−yi≤ϵ+ξiyi−f(xi)≤ϵ+ξ^iξi,ξ^i≤0,i=1,2,...,N
引入拉格朗日函数:
L(w,b,α,α^,ξ,ξ,μ,μ^)=12∥w∥2+C∑i=1N(ξi+ξ^i)−∑i=1Nξiμi−∑i=1Nξ^iμ^i+∑i=1Nαi(f(xi)−yi−ϵ−ξi)+∑i=1Nα^i(yi−f(xi)−ϵ−ξ^i)\begin{array}{l} L(w, b, \alpha, \hat{\alpha}, \xi, \xi, \mu, \hat{\mu}) \\ \quad=\frac{1}{2}\|w\|^{2}+C \sum_{i=1}^{N}\left(\xi_{i}+\widehat{\xi}_{i}\right)-\sum_{i=1}^{N} \xi_{i} \mu_{i}-\sum_{i=1}^{N} \widehat{\xi}_{i} \widehat{\mu}_{i} \\ \quad+\sum_{i=1}^{N} \alpha_{i}\left(f\left(x_{i}\right)-y_{i}-\epsilon-\xi_{i}\right)+\sum_{i=1}^{N} \widehat{\alpha}_{i}\left(y_{i}-f\left(x_{i}\right)-\epsilon-\widehat{\xi}_{i}\right) \end{array} L(w,b,α,α^,ξ,ξ,μ,μ^)=21∥w∥2+C∑i=1N(ξi+ξi)−∑i=1Nξiμi−∑i=1Nξiμi+∑i=1Nαi(f(xi)−yi−ϵ−ξi)+∑i=1Nαi(yi−f(xi)−ϵ−ξi)
再令L(w,b,α,α^,ξ,ξ,μ,μ^)L(w, b, \alpha, \hat{\alpha}, \xi, \xi, \mu, \hat{\mu})L(w,b,α,α^,ξ,ξ,μ,μ^)对w,b,ξ,ξ^w,b,\xi,\hat{\xi}w,b,ξ,ξ^求偏导等于0,得: w=∑i=1N(α^i−αi)xiw=\sum_{i=1}^{N}\left(\widehat{\alpha}_{i}-\alpha_{i}\right) x_{i}w=∑i=1N(αi−αi)xi。
上述过程中需满足KKT条件,即要求:
{αi(f(xi)−yi−ϵ−ξi)=0αi^(yi−f(xi)−ϵ−ξ^i)=0αiα^i=0,ξiξ^i=0(C−αi)ξi=0,(C−α^i)ξ^i=0\left\{\begin{array}{c} \alpha_{i}\left(f\left(x_{i}\right)-y_{i}-\epsilon-\xi_{i}\right)=0 \\ \hat{\alpha_{i}}\left(y_{i}-f\left(x_{i}\right)-\epsilon-\hat{\xi}_{i}\right)=0 \\ \alpha_{i} \widehat{\alpha}_{i}=0, \xi_{i} \hat{\xi}_{i}=0 \\ \left(C-\alpha_{i}\right) \xi_{i}=0,\left(C-\widehat{\alpha}_{i}\right) \hat{\xi}_{i}=0 \end{array}\right. ⎩⎪⎪⎪⎨⎪⎪⎪⎧αi(f(xi)−yi−ϵ−ξi)=0αi^(yi−f(xi)−ϵ−ξ^i)=0αiαi=0,ξiξ^i=0(C−αi)ξi=0,(C−αi)ξ^i=0
SVR的解形如:f(x)=∑i=1N(α^i−αi)xiTx+bf(x)=\sum_{i=1}^{N}\left(\widehat{\alpha}_{i}-\alpha_{i}\right) x_{i}^{T} x+bf(x)=∑i=1N(αi−αi)xiTx+b
sklearn中使用SVR实例:
sklearn.svm.SVR(*, kernel=‘rbf’, degree=3, gamma=‘scale’, coef0=0.0, tol=0.001, C=1.0, epsilon=0.1, shrinking=True, cache_size=200, verbose=False, max_iter=-1)
https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVR.html?highlight=svr#sklearn.svm.SVR
- 参数:
kernel:核函数,{‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’}, 默认=’rbf’。(后面会详细介绍)
degree:多项式核函数的阶数。默认 = 3。
C:正则化参数,默认=1.0。(后面会详细介绍)
epsilon:SVR模型允许的不计算误差的邻域大小。默认0.1。
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler # 标准化数据
from sklearn.pipeline import make_pipeline # 使用管道,把预处理和模型形成一个流程reg_svr = make_pipeline(StandardScaler(), SVR(C=1.0, epsilon=0.2))
reg_svr.fit(X, y)
reg_svr.score(X,y)
0.7024525421955277
【集成学习(上)】机器学习基础_02相关推荐
- (三)集成学习上——偏差与方差
参考:DataWhale教程链接 集成学习(上)所有Task: (一)集成学习上--机器学习三大任务 (二)集成学习上--回归模型 (三)集成学习上--偏差与方差 (四)集成学习上--回归模型评估与超 ...
- 20210317_23期_集成学习(上)_Task02_sklearn构建完整机器学习模型
二.Sklearn构建完整机器学习模型 目录 二.Sklearn构建完整机器学习模型 来源 2.1 机器学习项目通常步骤 2.2 用Sklearn对机器学习项目的构建 2.2.1 导入数据集及特征选择 ...
- Python深度学习之机器学习基础
Python深度学习之机器学习基础 一.前言 本文记录 弗朗索瓦·肖莱的<Python深度学习>第四章 机器学习基础有关笔记. 二.笔记 2.1机器学习的四个分支 监督学习 序列生成(se ...
- 集成学习(上):机器学习基础task1-熟悉机器学习的三大主要任务
机器学习基础task1-熟悉机器学习的三大主要任务 1.导论 1.1 回归 1.2 分类 1.3 无监督学习 学习内容来源链接 1.导论 什么是机器学习?机器学习的一个重要的目标就是利用数学模型来理解 ...
- 水很深的深度学习-Task02机器学习基础
机器学习基础 目录 机器学习基础 一.什么是机器学习? 如何寻找这个函数? 机器学习三板斧 学习路线 二.机器学习算法的类型 1. 有监督学习 2. 无监督学习 3. 强化学习 4.机器学习算法的系统 ...
- 集成学习:机器学习兵器谱的“屠龙刀”
转载地址:http://www.csdn.net/article/2015-03-02/2824069 编者按:目前机器学习领域诞生的多种算法并不见得都有很好的实战效果.本文作者认为,集成学习是一种立 ...
- 使用集成学习提升机器学习算法性能
译者注:这篇文章是对 PythonWeekly 推荐的一篇讲集成模型的文章的翻译,原文为 Ensemble Learning to Improve Machine Learning Results,由 ...
- 深度学习-2.机器学习基础
机器学习基础 机器学习问题举例 性能度量P 容量.过拟合和欠拟合 定义 性质 相关理论 奥卡姆剃刀原理 没有免费的午餐定理 监督学习算法 概率监督学习--逻辑回归(Logistic Regressio ...
- 神经网络与深度学习(一)——机器学习基础
神经网络与深度学习 (一)--机器学习基础 1.人工智能基础概念 2. 机器学习 2.1 基本概念 2.2 机器学习的三个基本要素 2.2.1 模型 2.2.2 学习准则 2.2.2.1 损失函数 L ...
- 集成学习(上)——Task3 考试前千万不要背书
机器学习专题 机器学习三要素 模式识别 贝叶斯推导 机器学习训练的套路 考试前千万不要背书 机器学习专题 进度条 考试前千万不要背书! 我们要怎么学习?[^1] 世界上难的不是无路可走,而是选择太多 ...
最新文章
- ibatis报错:There is no READABLE property named
- Ruby的资源站点和开发工具列表
- [Python爬虫] Selenium实现自动登录163邮箱和Locating Elements介绍
- CanvasRenderingContext2D(渲染上下文对象)
- 系统架构师复习-操作系统
- 日历的java包_java11教程--包java.time.chrono介绍
- xgboost4j jar包下载
- 塞规公差带图_螺纹塞规公差及尺寸表
- 1.3 可移植性和标准
- java socket 卡住_Java socket通讯实现过程及问题解决
- Java中instanceof关键字的用法
- PhpSpreadsheet实现Excel操作
- 解决vps上的ssh掉线------tmux
- 螺旋传动设计系统lisp_螺旋传动设计
- pycharm关联git
- php7.1.6验证码错误,steam输入验证码不正确怎么办
- java 管道设计_设计模式——管道模式
- PostgreSQL函数——数值函数
- Vue知识点(未完待续)
- 美团面试题:Hashmap的结构,1.7和1.8有哪些区别,史上最深入的分析
热门文章
- 在html中让图片旋转180度,gif图片旋转教程:怎么把gif旋转90度/180度 附gif图片旋转软件...
- FIR滤波器窗口设计法和频率采样设计法
- python求圆锥体的表面积_使用matplotlib绘制圆锥的三维图形
- 在线教育报告上线,助力职业与成人教育行业高效运营
- Java后端程序员未来职业规划路线,超用心整理,建议收藏
- 激光切割dxf图案下载
- Ansible-playbook 运维笔记
- MATLAB算法实战应用案例精讲-【深度学习】扩散模型(DM)(补充篇)
- python画八角星_Goc-N角星的绘制
- ccsa安学网小程序_CCSA安学网安全题库完整