【机器学习】阿里云天池竞赛——工业蒸汽量预测(4)

【机器学习】阿里云天池竞赛——工业蒸汽量预测(3) 利用这个方法,LightGBM可以在构造一个叶子的直方图后,可以用非常微小的代价得到它兄弟叶子的直方图,在速度上可以提升一倍。首先,最明显就是内存消耗的降低,直方图算法不仅不需要额外存储预排序的结果,而且可以只保存特征离散化后的值,而这个值一般用 8 位整型存储就足够了,内存消耗可以降低为原来的1/8。在遍历数据的时候,根据离散化的值作为索引在直方图中累积统计量,当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。将待预测的数据集输入到训练好的模型中,得到预测结果。 阅读详情

机器学习经典赛题:工业蒸汽量预测(4):模型验证(模型评估与调参)

5.1 模型评估的概念和方法

5.1.1 欠拟合与过拟合

数据关系是样本的分布规律,或者是特征与对应样本之间的关系。当一个模型恰到好处地表达了数据关系时,认为这个模型拟合效果好。欠拟合(underfitting)也叫高偏差(bias),是指算法所训练的模型不能完整地表达数据关系。在这种情况下,一般可通过增加额外的特征、增加多项式特征、减少 λ \lambda λ的值等方法来优化模型。过拟合(overfitting)也叫高方差(variance),指的是算法所训练的模型过多地表达了数据关系,此时很有可能表达的是数据间的噪声关系。在这种情况下,一般可通过收集更多的数据、使用更少的特征、增加 λ \lambda λ的值等方法来优化模型。
举例:

# 首先生成一个数据集并可视化
np.random.seed(2012)
x = np.random.uniform(-3.0, 3.0, size=100)
X = x.reshape(-1, 1)
y = 0.5 * x ** 2 + x + np.random.normal(0, 1, size=100)

plt.scatter(x, y)
plt.show()

模拟数据集
首先,使用线性回归模型对数据进行拟合

from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X, y)
lin_reg.score(X,y)
# 0.5632635759258182

显然,直线拟合数据程度比较低。考虑使用均方误差作为指标来评价拟合程度,代码如下:

from sklearn.metrics import mean_squared_error
y_predict = lin_reg.predict(X)
mean_squared_error(y, y_predict)
# 2.6840905248259093

绘制拟合结果,观察拟合情况:

y_predict = lin_reg.predict(X)
plt.scatter(x, y)
plt.plot(np.sort(x),y_predict[np.argsort(x)],color='r')
plt.show()

拟合结果
下面使用多项式回归拟合,首先封装Pipeline管道,便于下一步灵活调整多项式回归模型参数。代码如下:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler

def PolynomialRegression(degree):
    return Pipeline([('poly',PolynomialFeatures(degree=degree)),
                     ('std_scaler',StandardScaler()),
                     ('lin_reg',LinearRegression())])
#%%
poly2_reg = PolynomialRegression(degree=3)
poly2_reg.fit(X, y=y)
y2_predict = poly2_reg.predict(X)
# 比较真实值和预测值的均方误差
mean_squared_error(y, y2_predict)
# 1.116721965068975

讲模型拟合结果可视化显示,如下所示:

plt.scatter(x, y)
plt.plot(np.sort(x), y2_predict[np.argsort(x)],color='r')
plt.show()

多项式回归模型拟合结果
调整多项式参数为degree=10,进行预测:
degree为10的拟合结果
调整多项式参数为degree=100,进行预测:
degree为100的拟合结果
显然,在训练数据集上,随着degree的增加,拟合效果越来越好,MSE的值越来越小,因为样本点是一定的,总能找到一条曲线将所有的样本点拟合;但是曲线并不是所计算出的拟合曲线,只是原有的数据点对应的y的预测值连接出来的结果,而且有的地方没有数据点,因此连接的结果和原来的曲线不一致。在待预测数据的预测过程中,过度拟合训练集会造成泛化能力的降低,预测偏差增大。

5.1.2 模型的泛化与正则化

  1. 泛化和正则化的概念

泛化是指机器学习模型学习到的概念在处理训练过程中未遇到的样本的表现,即模型处理新样本的能力。

正则化(Regularization是给需要训练的目标函数加上一些规则(限制),目的是为了防止过拟合。(在统计领域中,正则化也称作压缩估计),正则化的主要目的是通过特征选择即对回归函数的系数进行约束,显著降低模型方差,最终降低测试误差。具体说,就是将回归系数往零的方向压缩,这也就是为什么叫压缩估计的原因。

正则化的种类:
L 1 L1 L1, L 2 L2 L2正则化(L1,L2Regularization)使用的正则化项分别是L1范数、L2范数,其中:
- L 1 L1 L1范数,公式为 ∣ ∣ x ∣ ∣ 1 = ∑ i = 1 n ∣ x i ∣ ||x||_1 = \sum^n_{i=1}{|x_i|} ∣∣x∣∣1​=∑i=1n​∣xi​∣,即向量元素的绝对值之和。
- L 2 L2 L2范数,公式为 ∣ ∣ x 2 ∣ ∣ = ( ∑ i = 1 n ∣ x i ∣ 2 ) 1 2 ||x_2||=(\sum^n_{i=1}{|x_i|^2})^\frac{1}{2} ∣∣x2​∣∣=(∑i=1n​∣xi​∣2)21​,又称为欧几里得(Euclid)范数,即向量元素绝对值平方和再进行开方。
- L − q L-q L−q范数,公式为 ∣ ∣ x ∣ ∣ q = ( ∑ i = 1 n ∣ x i ∣ q ) 1 q ||x||_q = (\sum_{i=1}^n{|x_i|}^q)^\frac{1}{q} ∣∣x∣∣q​=(∑i=1n​∣xi​∣q)q1​,即向量元素绝对值的 q q q次幂的累加和再 1 q \frac{1}{q} q1​次幂。

上述公式中, n n n为模型的阶次,即模型有几个变量(对应数据有几个维度)
下图为二维优化变量范围, q q q的值越小,曲线越贴近坐标轴,反之, q q q的值越大,曲线越远离坐标轴。
二维优化变量范围
**加入正则化项后的代价函数(cost function)**为:
J ( w ) = 1 2 ∑ j = 1 N { y i − w T σ ( x j ) } 2 + λ 2 ∑ j = 1 N ∣ w j ∣ q J(w)=\frac{1}{2}\sum_{j=1}^N \{y_i-w^T\sigma(x_j)\}^2+\frac{\lambda}{2}\sum_{j=1}^N|w_j|_q J(w)=21​j=1∑N​{yi​−wTσ(xj​)}2+2λ​j=1∑N​∣wj​∣q​
其中 q = 2 q=2 q=2为L2正则化, q = 1 q=1 q=1为L1正则化,也可以表述为下列简化形式:

  • L2正则化: J = J 0 + α ∑ w 2 J=J_0+\alpha\sum w^2 J=J0​+α∑w2
  • L1正则化: J = J 0 + α ∑ ∣ w 1 ∣ J=J_0+\alpha\sum |w^1| J=J0​+α∑∣w1∣

参数空间L2正则化和参数空间L1正则化的示意图如下:
参数空间L1和L2正则化示意图
蓝色的圆圈表示没有经过限制的损失函数在寻找最小值过程中, w w w的不断迭代的变化情况,表示的方法是等高线。蓝线和红线的交点 w ∗ w^* w∗是最小值取到的点。

  1. 岭回归和LASSO回归
    (1)对参数空间进行 L 2 L2 L2范数正则化的线性模型称为岭回归(Ridge Regression):
    J ( w ) = ∑ i = 1 N ( y i − w 0 − ∑ j = 1 p w j x i j ) 2 + λ ∑ j = 1 p w j 2 ,其中 λ > = 0 J(w)=\sum_{i=1}^N(y_i-w_0-\sum_{j=1}^p{w_jx_{ij}})^2+\lambda\sum_{j=1}^p{w_j}^2 ,其中\lambda>=0 J(w)=i=1∑N​(yi​−w0​−j=1∑p​wj​xij​)2+λj=1∑p​wj​2,其中λ>=0
    sklearn中岭回归的代码为:
sklearn.linear_model.ridge_regression(X, y, alpha, *, sample_weight=None, solver=‘auto’, max_iter=None, tol=0.001, verbose=0, random_state=None, return_n_iter=False, return_intercept=False, check_input=True)

参数列表:

  • alpha:较大的值表示更强的正则化。浮点数
  • sample_weight:样本权重,默认无。
  • solver:求解方法,{‘auto’, ‘svd’, ‘cholesky’, ‘lsqr’, ‘sparse_cg’, ‘sag’, ‘saga’}, 默认=’auto’。
    • 'svd’使用X的奇异值分解来计算Ridge系数。
    • 'cholesky’使用标准的scipy.linalg.solve函数通过dot(XT,X)的Cholesky分解获得封闭形式的解。
    • 'sparse_cg’使用scipy.sparse.linalg.cg中的共轭梯度求解器。作为一种迭代算法,对于大规模数据(可能设置tol和max_iter),此求解器比“ Cholesky”更合适。
    • 'lsqr’使用专用的正则化最小二乘例程scipy.sparse.linalg.lsqr。它是最快的,并且使用迭代过程。
    • 'sag’使用随机平均梯度下降。
    • ‘saga’使用其改进的无偏版本SAGA。两种方法都使用迭代过程,并且当n_samples和n_features都很大时,通常比其他求解器更快。请注意,只有在比例大致相同的要素上才能确保‘sag’和‘saga’快速收敛。您可以使用sklearn.preprocessing中的缩放器对数据进行预处理。最后五个求解器均支持密集和稀疏数据。但是,当fit_intercept为True时,仅’sag’和’sparse_cg’支持稀疏输入。
from sklearn import linear_model
reg_rid = linear_model.Ridge(alpha=.5)
reg_rid.fit(X,y)
reg_rid.score(X,y)

(2)对参数空间进行 L 1 L1 L1范数正则化的线性模型称为LASSO回归(LASSO Regression)。
J ( w ) = ∑ i = 1 N ( y i − w 0 − ∑ j = 1 p w j x i j ) 2 + λ ∑ j = 1 p ∣ w j ∣ ,其中 λ > = 0 J(w)=\sum_{i=1}^N(y_i-w_0-\sum_{j=1}^p{w_jx_{ij}})^2+\lambda\sum_{j=1}^p|w_j| ,其中\lambda>=0 J(w)=i=1∑N​(yi​−w0​−j=1∑p​wj​xij​)2+λj=1∑p​∣wj​∣,其中λ>=0
sklearn中关于LASSO回归的代码为:

class sklearn.linear_model.Lasso(alpha=1.0, *, fit_intercept=True, normalize=False, precompute=False, copy_X=True, max_iter=1000, tol=0.0001, warm_start=False, positive=False, random_state=None, selection=‘cyclic’)

参数列表:

  • alpha:正则化强度,1.0代表标准最小二乘。
  • fit_intercept:是否计算模型截距。默认true。
  • normalize:是否标准化,默认false。
  • positive:是否强制系数为正,默认false。
from sklearn import linear_model
reg_lasso = linear_model.Lasso(alpha = 0.5)
reg_lasso.fit(X,y)
reg_lasso.score(X,y)

岭回归和LASSO回归的不同之处:
1)使用岭回归改进的多项式回归算法,随着 α \alpha α的改变,拟合曲线始终是曲线,知道最后变成一条几乎水平的直线;也就是说,在使用岭回归之后,多项式回归算法在模型变量前还是有系数的,因此很难得到一条斜的直线。
2)而使用LASSO回归改进的多项式回归算法,随着 α \alpha α的改变,拟合曲线会很快变成一条斜的直线,最后慢慢变成一条几乎水平的直线,即模型更倾向于一条直线。

5.1.3 回归模型的评估指标和调用方法

这里评估指标一般用于对经过训练集训练后的模型来使用的,以各项指标的评估得分来比较模型的性能。因为模型上限后,一般的未知样本的标签是较难得到的。

这里注意要与参数估计中的公式区分开,虽然有些参数估计的公式用到了诸如MSE的方法,但只是方法相同,用处却不一样。

回归模型的评估指标有平均绝对值误差、均方误差、均方根误差、R平方值。

  1. 平均绝对值误差
    平均绝对值误差,也称**L1损失(MAE)**是预测值与真实值之差的绝对值,计算公式如下:
    M A E = 1 n ∑ i = 1 n ∣ f i − y i ∣ = 1 n ∑ i = 1 n ∣ e i ∣ MAE = \frac{1}{n}\sum_{i=1}^n{|f_i-y_i|}=\frac{1}{n}\sum_{i=1}^n{|e_i|} MAE=n1​i=1∑n​∣fi​−yi​∣=n1​i=1∑n​∣ei​∣
    以下是sklearn中调用MAE的示例代码:
from sklearn.metrics import mean_absolute_error
mean_absolute_error(y_test,y_pred)
  1. 均方误差
    均方误差,也称**L2损失(MSE)**是指的参数估计值与参数真实值之差平方的期望值。MSE是衡量平均误差的一种较方便的方法,可以用来评价数据的变化程度。MSE的值越小,说明预测模型描述实验数据具有越好的精确度,计算公式如下:
    M S E = 1 n ∑ i = 1 n ( o b s e r v e d i − p r e d i c t e d i ) 2 MSE = \frac{1}{n}\sum_{i=1}^n{(observed_i-predicted_i)^2} MSE=n1​i=1∑n​(observedi​−predictedi​)2
    以下是sklearn中调用MAE的示例代码:
from sklearn.metrics import mean_squared_error
mean_squared_error(y_test,y_pred)
  1. 均方根误差
    均方根误差(RMSE)是MSE的平方根,计算公式如下:
    R M S E = M S E = S S E N = 1 N ∑ i = 1 N ( o b s e r v e d i − p r e d i c t e d i ) 2 RMSE =\sqrt{MSE}=\sqrt{\frac{SSE}{N}}= \frac{1}{N}\sum_{i=1}^N{(observed_i-predicted_i)^2} RMSE=MSE ​=NSSE​ ​=N1​i=1∑N​(observedi​−predictedi​)2
    以下是sklearn中调用RMSE的示例代码:
from sklearn.metrics import mean_squared_error
Pred_Error = mean_squared_error(y_test,y_pred)
Sqrt(Pred_Error)
  1. R平均值
    R平方值(R-Squared)反映了回归模型在多大程度上解释了因变量的变化,或者说模型对观测值的拟合程度如何。计算公式如下:
    R 2 ( y , y ^ ) = 1 − ∑ i = 0 n s a m p l e s − 1 ( y i − y i ^ ) 2 ∑ i = 0 n s a m p l e s − 1 ( y i − y i ˉ ) 2 R^2(y,\hat{y})=1-\frac{\sum_{i=0}^{n_{samples}-1}(y_i-\hat{y_i})^2}{\sum_{i=0}^{n_{samples}-1}(y_i-\bar{y_i})^2} R2(y,y^​)=1−∑i=0nsamples​−1​(yi​−yi​ˉ​)2∑i=0nsamples​−1​(yi​−yi​^​)2​
    以下是sklearn中调用R平方值的示例代码:
from sklearn.metrics import r2_score
r2_score(y_test,y_pred)

补充:

  1. 均方对数差损失(Mean Squared Log Error,MSLE)
    l o s s ( y i ^ , y ) = 1 N ∑ i = 1 N ( l o g y i ^ − l o g y i ) 2 loss(\hat{y_i},y) = \frac{1}{N}\sum_{i=1}^N(log\hat{y_i}-logy_i)^2 loss(yi​^​,y)=N1​i=1∑N​(logyi​^​−logyi​)2
  2. Huber损失(Huber loss)
    Huber损失
  3. Log-Cosh损失函数(Log-Cosh loss)
    l o s s ( y i ^ , y ) = 1 N ∑ i = 1 N l o g ( c o s h ( y i ^ − y ) ) loss(\hat{y_i},y) = \frac{1}{N}\sum_{i=1}^N{log(cosh(\hat{y_i}-y))} loss(yi​^​,y)=N1​i=1∑N​log(cosh(yi​^​−y))
  • L2损失是使用最广泛的损失,在优化过程中更为稳定和准确,但是对于局外点敏感。
  • L1损失会比较有效地惩罚局外点,但它的导数不连续使得寻找最优解的过程低效。
  • Huber损失由L2损失与L1损失合成,当 δ \delta δ趋于0时退化成了L1损失,当 δ \delta δ趋于无穷时则退化为L2损失。 δ \delta δ决定了模型处理局外点的行为,当残差大于 δ \delta δ时使用L1损失,很小时则使用更为合适的L2损失来进行优化。Huber损失函数克服了L1损失和L2损失的缺点,不仅可以保持损失函数具有连续的导数,同时可以利用L2损失梯度随误差减小的特性来得到更精确的最小值,也对局外点具有更好的鲁棒性。但Huber损失函数的良好表现得益于精心训练的超参数 δ \delta δ。
  • Log-Cosh损失拥有Huber损失的所有优点,并且在每一个点都是二次可导的,这在很多机器学习模型中是十分必要的。

5.1.4 分类模型的评估指标和调用方法

  1. Logistic损失(Logistic loss)
  2. 负对数似然损失(Negative Log Likelihood loss)
  3. 交叉熵损失(Cross Entropy loss)

Logistic损失用于解决每个类别的二分类问题,为了方便数据集把最大似然转化为负对数似然,而得到负对数似然损失,交叉熵损失从两个类别扩展到M个类别,交叉熵损失在二分类时应当是负对数似然损失。

5.1.5 交叉验证

交叉验证(Cross Validation)是验证分类器性能的一种统计分析方法,其基本思想是在某种意义下将原始数据进行分组,一部分作为训练集,另一部分作为验证集。首先用训练集对分类器进行训练,再利用验证集来测试训练得到的模型,以此来作为评价分类器的性能指标。常用的交叉验证法包括简单交叉验证、K折交叉验证、留一法交叉验证和留P法交叉验证。

  1. 简单交叉验证
    简单交叉验证(Cross Validation)是将原始数据随机分为两组,一组作为训练集,另一组作为验证集,利用训练集训练分类器,然后利用验证集验证模型,将最后的分类准确率作为此分类器的性能指标。通常划分30%的数据作为测试数据。
  2. K折交叉验证
    K折交叉验证(K-Fold Cross Validation),是将原始数据分成K组(一般是均分),然后将每个子集数据分别做一次验证集,其余K-1组子集数据做训练集,这样就会得到K个模型,将K个模型最终的验证集的分类准确率取平均值,作为K折交叉验证分类器的性能指标。通过设置K大于或等于3。

注意:当数据集比较大时,K不能取值过大,例如数据集包含1百万个样本,则需要训练1百万个模型,这还是未考虑算法调参的情况下。
3. 留一法交叉验证
留一法交叉验证(Leave-One-Out Cross Validation,LOO-CV),是指每个训练集由除一个样本之外的其余样本组成,留下的一个样本为验证集。这样,对于N个样本的数据集,最终可以形成N个模型,用N个模型最终的验证集的分类准确率的平均数作为分类器的性能指标。留一法是K折交叉验证,K=N时的特例。

留一法中被实际评估的模型与期望评估的用全部数据集D训练出的模型很相似。因此,留一法的评估结果往往被认为比较准确。但留一法的估计结果未必永远比其他评估方法准确;“没有免费的午餐”NFL定理对实验评估方法同样适用。 ———周志华《机器学习》P27

  1. 留P法交叉验证
    留P法交叉验证(Leave-P-Out Cross Validation,LPO-CV),与留一法交叉验证类似,是从完整的数据集中删除p个样本,产生所有可能的训练集和验证集。对于N个样本,能产生 ( N , p ) (N,p) (N,p)个训练-检验对。也就是每个训练集由除P个样本之外的其余样本组成,留下的P个样本为验证集。

注意:
1)训练/测试集的划分要尽可能保持数据分布的一致性,避免因数据划分过程引入额外的偏差而对最终结果产生影响,例如在分类任务中至少要保持样本的类别比例相似—分层采样(stratified sampling)。
2)即使在给定训练/测试集的样本比例后,仍存在多种划分方式对初始数据集D进行分割。不同的分割将导致不同的训练/测试集,相应的,模型评估的结果也会有所差别。因此在采用留出法时往往采用若干次随机划分、重复进行实验评估后取平均值作为留出法的评估结果。

  1. 几种交叉验证在sklearn中的调用方法示例代码
    (1)简单交叉验证
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris

iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=.4, random_state=0)

(2)K折交叉验证

from sklearn.model_selection import KFold
kf = KFold(n_splits=10)

(3)留一法交叉验证

from sklearn.model_selection import LeaveOneOut
loo = LeaveOneOut()

(4)留P法交叉验证

from sklearn.model_selection import LeavePOut
lpo = LeavePOut(p=5)
  1. 其他交叉验证分割方法
    (1)基于类标签,具有分层的交叉验证。
    这一类交叉验证方法主要用于解决样本不平衡的问题。
    StratifiedKFold是 k-fold 的变种,会返回 stratified(分层) 的折叠:每个小集合中, 各个类别的样例比例大致和完整数据集中相同。使用sklearn.model_selection 中的类StratifiedKFold 。
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=3)
for train ,test in skf.split(iris.data,iris.target):
    print("分层k折拆分:%s %s" %(train.shape, test.shape))

#分层k折拆分:(100,) (50,)
#分层k折拆分:(100,) (50,)
#分层k折拆分:(100,) (50,)

StratifiedShuffleSplit是 ShuffleSplit 的一个变种,会返回直接的划分,比如创建一个划分,但是划分中每个类的比例和完整数据集中的相同。

from sklearn.model_selection import StratifiedShuffleSplit
skf = StratifiedShuffleSplit(n_splits=3 ,test_size=0.25, random_state=0)
for train ,test in skf.split(iris.data,iris.target):
    print("分层k折拆分:%s %s" %(train.shape, test.shape))

(2)用于分组数据的交叉验证
这一类交叉验证方法主要用于进一步测试模型的泛化能力。留出一组特定的不属于测试集和训练集的数据。常用的方法包括GroupKFold、LeaveOneGroupOut、LeavePGroupsOut、GroupShuffleSplit。

  • GroupKFold是 k-fold 的变体,它确保同一个group在测试和训练集中都不被表示。
  • LeaveOneGroupOut是LeaveOneOut的变体,根据用户提供的整数组的数组来区别不同组,以此来提供样本。这个组的信息可以用来编码任意域特定的预定义交叉验证折叠。每个训练集都是由除特定组别意外的所有样本构成的。
  • LeavePGroupsOut类似于 LeaveOneGroupOut ,但为每个训练/测试集删除与 P 组有关的样本。
  • GroupShuffleSplit迭代器是 ShuffleSplit 和 LeavePGroupsOut 的组合,它生成一个随机划分分区的序列,其中为每个分组提供了一个组子集。
    (3)时间序列分割
    TimeSeriesSplit是 K-fold 的一个变体,它首先返回 K 折作为训练数据集,并且 (K+1) 折作为测试数据集。 请注意,与标准的交叉验证方法不同,连续的训练集是超越前者的超集,有关时间序列的样本切分必须保证时间上的顺序性,不能用未来的数据去验证现在数据的正确性,只能使用时间上之前一段时间的数据建模,而用后一段时间的数据来验证模型预测的效果。 另外,它将所有的剩余数据添加到第一个训练分区,它总是用来训练模型。
    时间序列分割

5.2 模型调参

5.2.1 调参

  1. 调参的目标
    调参就是对模型的参数进行调整,以找到使模型性能最优的参数。调参的目标就是达到整体模型的偏差和方差的大和谐!

参数可分为两类:过程影响类参数和子模型影响类参数。具体来说:

  • 过程影响类参数就是在子模型不变的前提下,调整“子模型数(n_estimators)”、“学习率(learning_rate)”等参数,改变训练过程,从而提高整体模型的性能。
  • 子模型影响类参数就是调整“最大树深度(max_depth)”、“分裂条件(criterion)”等参数,改变子模型的性能,从而提高整体模型的性能。

bagging的训练过程旨在降低方差,而boosting的训练过程旨在降低偏差,过程影响类的参数能够引起整体模型性能的大幅度变化。

  1. 参数对整体模型性能的影响
    参数对RandomForest的影响
    图5.2.1.1 参数对Random Forest的影响
    参数对GradientTree Boosting的影响
    图5.2.1.2 参数对Gradient Tree Boosting的影响

5.2.2 网格搜索

网格搜索(Grid Search)是一种穷举搜索的调参手段。在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果。其原理就像是在数组中找最大值。以有两个参数的模型为例,参数a有三种可能,参数b有4种可能,把所有可能性列出来,可以表示成一个3*4的表格,其中每个单元就是一个网格,循环过程就像是在每个网格中遍历、搜索,因此得名网格搜索。
下面是一个简单的网格搜索示例,应用iris数据集,对SVC模型参数做一次网格搜索调参。

C=0.001C=0.01…C=10
grmma=0.001SVC(C=0.001,grmma=0.001)SVC(C=0.01,grmma=0.001)…SVC(C=10,grmma=0.001)
grmma=0.01SVC(C=0.001,grmma=0.01)SVC(C=0.01,grmma=0.01)…SVC(C=10,grmma=0.01)
……………
grmma=100SVC(C=0.001,grmma=100)SVC(C=0.01,grmma=100)…SVC(C=10,grmma=100)

具体的代码和调参结果如下:

from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
import numpy as np

iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=0)
print("Size if training set:{} size of testing size:{}".format(X_train.shape[0], X_test.shape[0]))  #total number 150

'''
C:正则化参数。正则化的强度与C成反比。必须严格为正。惩罚是平方的l2惩罚。
kernel:{'linear','poly','rbf','sigmoid','precomputed'},默认='rbf'
degree:多项式和的阶数
gamma:“ rbf”,“ poly”和“ Sigmoid”的内核系数。
shrinking:是否软间隔分类,默认true
'''

# grid search start
best_score = 0
for gamma in [0.001, 0.01, 0.1, 1, 10, 100]:
    for C in [0.001, 0.01, 0.1, 1, 10, 100]:
        svm = SVC(gamma=gamma, C=C)  #对于每种参数的可能组合,都进行一次训练
        svm.fit(X_train, y_train)
        score = svm.score(X_test, y_test)
        if score > best_score:
            best_score = score
            best_parameters = {'gamma': gamma, 'C': C}
# grid search end
print("Best score:{:.2f}".format(best_score))
print("Best parameters:{}".format(best_parameters))

运行结果:

Size if training set:112 size of testing size:38
Best score:0.97
Best parameters:{'gamma': 0.001, 'C': 100}

5.2.3 随机搜索

网格搜索相当于暴力地从参数空间中每个都尝试一遍,然后选择最优的那组参数,这样的方法显然是不够高效的,因为随着参数类别个数的增加,需要尝试的次数呈指数级增长。有没有一种更加高效的调优方式呢?那就是使用随机搜索的方式,这种方式不仅仅高效,而且实验证明,随机搜索法结果比稀疏化网格法稍好(有时候也会极差,需要权衡)。参数的随机搜索中的每个参数都是从可能的参数值的分布中采样的。与网格搜索相比,这有两个主要优点:

  • 可以独立于参数数量和可能的值来选择计算成本。
  • 添加不影响性能的参数不会降低效率。

调参实例
首先,对未调参的SVR进行评价:

rom sklearn.svm import SVR  # 引入SVR类
from sklearn.pipeline import make_pipeline  # 引入管道简化学习流程
from sklearn.preprocessing import StandardScaler  # 由于SVR基于距离计算,引入对数据进行标准化的类
from sklearn.model_selection import GridSearchCV  # 引入网格搜索调优
from sklearn.model_selection import cross_val_score  # 引入K折交叉验证
from sklearn import datasets

boston = datasets.load_boston()  # 返回一个类似于字典的类
X = boston.data
y = boston.target
features = boston.feature_names
pipe_SVR = make_pipeline(StandardScaler(), SVR())
score1 = cross_val_score(estimator=pipe_SVR, X=X, y=y, scoring='r2', cv=10)  # 10折交叉验证
print("CV accuracy: %.3f +/- %.3f" % ((np.mean(score1)), np.std(score1)))

输出:CV accuracy: 0.187 +/- 0.649

交叉验证经常与网格搜索进行结合,作为参数评价的一种方法,这种方法叫做grid search with cross validation。sklearn因此设计了一个这样的类GridSearchCV,这个类实现了fit,predict,score等方法,被当做了一个estimator,使用fit方法,该过程中:(1)搜索到最佳参数;(2)实例化了一个最佳参数的estimator;

然后,使用网格搜索来对SVR调参:

from sklearn.pipeline import Pipeline

pipe_svr = Pipeline([("StandardScaler", StandardScaler()),
                     ("svr", SVR())])
param_range = [0.0001, 0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0]
param_grid = [{"svr__C": param_range, "svr__kernel": ["linear"]},  # 注意__是指两个下划线,一个下划线会报错的
              {"svr__C": param_range, "svr__gamma": param_range, "svr__kernel": ["rbf"]}]
gs = GridSearchCV(estimator=pipe_svr, param_grid=param_grid, scoring='r2', cv=10)  # 10折交叉验证
gs = gs.fit(X, y)
print("网格搜索最优得分:", gs.best_score_)
print("网格搜索最优参数组合:\n", gs.best_params_)

输出:

网格搜索最优得分: 0.6081303070817479
网格搜索最优参数组合:
 {'svr__C': 1000.0, 'svr__gamma': 0.001, 'svr__kernel': 'rbf'}

最后,使用随机搜索来对SVR调参:

from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import uniform  # 引入均匀分布设置参数

pipe_svr = Pipeline([("StandardScaler", StandardScaler()),
                     ("svr", SVR())])
distributions = dict(svr__C=uniform(loc=1.0, scale=4),  # 构建连续参数的分布
                     svr__kernel=["linear", "rbf"],  # 离散参数的集合
                     svr__gamma=uniform(loc=0, scale=4))

rs = RandomizedSearchCV(estimator=pipe_svr,
                        param_distributions=distributions,
                        scoring='r2',
                        cv=10)  # 10折交叉验证
rs = rs.fit(X, y)
print("随机搜索最优得分:", rs.best_score_)
print("随机搜索最优参数组合:\n", rs.best_params_)

输出:

随机搜索最优得分: 0.3013294958679655
随机搜索最优参数组合:
 {'svr__C': 1.3542346449631775, 'svr__gamma': 0.8362549744047394, 'svr__kernel': 'linear'}

5.2.4 学习曲线

学习曲线是在训练集大小不同时,通过绘制模型训练集和交叉验证集上的准确率来观察模型在新数据上的表现,进而判断模型的方差或偏差是否过高,以及增大训练集是否可以减小过拟合。
模型欠拟合、过拟合、偏差和方差平衡 时对应的学习曲线如下图所示:
学习曲线
图5.2.4.1 学习曲线示意图

左上角的图中训练集和验证集上的曲线能够收敛。在训练集合验证集上准确率相差不大,却都很差。这说明模拟对已知数据和未知都不能进行准确的预测,属于高偏差。这种情况模型很可能是欠拟合。可以针对欠拟合采取对应的措施。

右上角的图中模型在训练集上和验证集上的准确率差距很大。说明模型能够很好的拟合已知数据,但是泛化能力很差,属于高方差。模拟很可能过拟合,要采取过拟合对应的措施。

学习曲线的代码如下:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.datasets import load_digits
from sklearn.model_selection import learning_curve
from sklearn.model_selection import ShuffleSplit


def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,
                        n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):
    """
    画出data在某模型上的learning curve.
    参数解释
    ----------
    estimator : 你用的分类器。
    title : 表格的标题。
    X : 输入的feature,numpy类型
    y : 输入的target vector
    ylim : tuple格式的(ymin, ymax), 设定图像中纵坐标的最低点和最高点
    cv : 做cross-validation的时候,数据分成的份数,其中一份作为cv集,其余n-1份作为training(默认为3份)
    n_jobs : 并行的的任务数(默认1)
    """
    plt.figure()
    plt.title(title)
    if ylim is not None:
        plt.ylim(*ylim)
    plt.xlabel("Training examples")
    plt.ylabel("Score")
    train_sizes, train_scores, test_scores = learning_curve(
        estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)
    train_scores_mean = np.mean(train_scores, axis=1)
    train_scores_std = np.std(train_scores, axis=1)
    test_scores_mean = np.mean(test_scores, axis=1)
    test_scores_std = np.std(test_scores, axis=1)
    plt.grid()

    plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
                     train_scores_mean + train_scores_std, alpha=0.1,
                     color="r")
    plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
                     test_scores_mean + test_scores_std, alpha=0.1, color="g")
    plt.plot(train_sizes, train_scores_mean, 'o-', color="r",
             label="Training score")
    plt.plot(train_sizes, test_scores_mean, 'o-', color="g",
             label="Cross-validation score")

    plt.legend(loc="best")
    plt.draw()
    plt.show()

    midpoint = ((train_scores_mean[-1] + train_scores_std[-1]) + (test_scores_mean[-1] - test_scores_std[-1])) / 2
    diff = (train_scores_mean[-1] + train_scores_std[-1]) - (test_scores_mean[-1] - test_scores_std[-1])
    return midpoint, diff


digits = load_digits()
X, y = digits.data, digits.target

title = "Learning Curves (Naive Bayes)"
# Cross validation with 100 iterations to get smoother mean test and train
# score curves, each time with 20% data randomly selected as a validation set.
cv = ShuffleSplit(n_splits=100, test_size=0.2, random_state=0)

estimator = GaussianNB()
plot_learning_curve(estimator, title, X, y, ylim=(0.7, 1.01), cv=cv, n_jobs=4)

title = "Learning Curves (SVM, RBF kernel, $\gamma=0.001$)"
# SVC is more expensive so we do a lower number of CV iterations:
cv = ShuffleSplit(n_splits=10, test_size=0.2, random_state=0)
estimator = SVC(gamma=0.001)
plot_learning_curve(estimator, title, X, y, (0.7, 1.01), cv=cv, n_jobs=4)

学习曲线

5.2.5 验证曲线

和学习曲线不同,验证曲线的横轴为某一个超参数的一系列值,由此比较不同参数设置下(而非不同训练集大小)模型的准确率。
学习曲线示例图

参考资料

[1] 《阿里云天池大赛赛题解析——机器学习篇》
[2] 机器学习交叉验证的数据分割算法
[3] 学习曲线(learning curve)来判断模型状态:过拟合欠拟合

【机器学习】阿里云天池竞赛——工业蒸汽量预测(1) 其首先是利用从有效数据集中识别出的关系来评估缺失值,然后用计算的该变量所有已知值得平均值或中值(定量属性)或众数(定性属性)来替换给定属性得缺失值,此方法也是最常用的方法。例如,在某个数据集中需要预测缺失的年龄值,为了预测缺失项的价值,我们可以提取名称中的称呼(Master、Mr、Mrs、Miss)作为新变量。生成的新变量可能与目标变量有更好的相关性,有助于进行数据分析。黑色粗条中间的白点表示中位数,粗条的顶边和底边分别表示上四分位数和下四分位数,通过边的位置所对应的y轴的数值就可以看到四分位数的值。 阅读详情

相关推荐

B.机器学习实战系列[一]:工业蒸汽量预测(最新版本上篇)含数据探索、特征工程、特征降维、决策树、随机森林,lightgbm等

火力发电的基本原理是:燃料在燃烧时加热水生成蒸汽,蒸汽压力推动汽轮机旋转,然后汽轮机带动发电机旋转,产生电能。在这一系列的能量转化中,影响发电效率的核心是锅炉的燃烧效率,即燃料燃烧加热水产生高温高压蒸汽。锅炉的燃烧效率的影响因素很多,包括锅炉的可调参数,如燃烧给量,一二次风,引风,返料风,给水水量;以及锅炉的工况,比如锅炉床温、床压,炉膛温度、压力,过热器的温度等。经脱敏后的锅炉传感器采集的数据(采集频率是分钟级别),根据锅炉的工况,预测产生的蒸汽量。数据分成训练数据(train.txt)和测试数据(tes

丨汀、的博客 1579

天池赛:工业蒸汽量预测

每一次的比赛都能学到新的东西,都能得到提升。

weixin_46685991的博客 2996

阿里云天池工业蒸汽量预测代码jupyter

阿里云天池工业蒸汽量预测代码jupyter

工业蒸汽量预测

本文主要介绍阿里云天池大数据平台的学习赛——工业蒸汽量预测。文章内容来自《阿里云天池大赛赛题解析》以及我自己的理解。涉及到的技术点包括数据分析、缺失值、异常值的处理、新变量生成、多种数据可视化(KDE、线性回归、直方图、Q-Q图、箱形图)以及特征变量之间的相关性计算、热力图展示因内容较多,此后会不断更新

L1142456160的博客 5047

2024银行科技岗笔试通关秘籍:从资料准备到实战技巧

本文系统解析了2024年银行科技岗笔试的考察内容与备考策略。文章指出,笔试是一场涵盖通用能力测试、计算机专业基础、金融科技知识和英语性格测试的复合型考试,并重点提供了数据结构与算法、计算机网络、数据库等高频考点的深度解析与实战突破技巧,帮助考生高效准备,顺利通关。

weixin_29243279的博客 121

车载以太网测试技术解析

在智能汽车与HiL测试领域,高效解析与模拟车载网络通信是开发验证的关键。ZD-Converter 2000以媒体/介质转换器、嗅探器、拦截器、仿真器四合一的颠覆性设计,成为工程师应对复杂车载以太网测试的瑞士军刀。它支持双路车载/标准以太网智能转换、实时通信嗅探、硬件级数据拦截及ECU通信模拟,更通过串口命令实现全参数远程配置,赋能自动化测试流程。本文将深度解析其核心功能与实战应用场景。

Triv2025的博客 1142

【机器学习】阿里云天池竞赛——工业蒸汽量预测(7)

在选择一个模型进行训练后,如何判断模型的优势及优化模型的性能呢?一般可以从以下几个方面进行优化:欠拟合(高偏差)、过拟合(高方差)和正常拟合三种学习曲线:模型融合,即先产生一组个体学习器,再用某种策略将他们结合起来,以加强模型效果。随着集成中个体分类器数目的增加,集成学习器的错误率也会呈指数级下降,最终趋于零。综合个体学习器的优势是能够降低预测误差,优化整体模型的性能。而且个体学习器的准确性越高,多样性越大,模型融合的提升效果越好。按个体学习器的关系,模型融合技术可以分为两类: (1)个体学习器不存在强依赖

小哲的博客 2401

小秋SLAM入门实战ubuntu所有文章汇总

ubuntu 终端如何停止快速打印的输出以及恢复命令 ubuntu 终端如何快速打开当前路径下的图形化窗口界面? killall -9用途用法 ps -xu | grep这个命令的用途 linux 下 top命令显示的是内存是堆内存吗? zip分割和合并 关闭除当前 GNOME 终端窗口以外的所有其他 GNOME 终端窗口 如何在安装系统后设置短密码 【如何使用getrusage获取消耗的CPU时间和进程使用的最大物理内存】 【webots安装使用教程】 Linux系统下查看当前运行的进程和线程的几种方法

小秋 AI SLAM 入门实战教程 1402

天池大赛——工业蒸汽量预测

从0开始学大数据分析与机器学习,简简单单写下竞赛心得。本文使用了多种机器学习回归算法,也运用了深度学习pytorch搭建神经网络来进行回归计算。 一、背景介绍 本文记录的是工业蒸汽量赛题,链接:AI训练营计算机视觉-阿里云天池 赛题背景 火力发电的基本原理是:燃料在燃烧时加热水生成蒸汽,蒸汽压力推动汽轮机旋转,然后汽轮机带动发电机旋转,产生电能。在这一系列的能量转化中,影响发电效率的核心是锅炉的燃烧效率,即燃料燃烧加热水产生高温高压蒸汽。锅炉的燃烧效率的影响因素很多,包括锅炉的可调参数,如燃烧给量,

weixin_43406384的博客 1576

OFDM调制解调系统信道估计和均衡算法的MATLAB仿真

然后,从接收到的信号中提取导频序列,并使用LS算法进行信道估计。OFDM(正交频分复用)是一种常用于高速数据传输的调制技术,它将高速数据流分割成多个低速子载波,通过在不同的子载波上传输数据,实现了频域上的正交性。因此,信道估计和均衡算法在OFDM系统中起着至关重要的作用,用于减小信道衰落引起的影响。通过运行上述代码,可以进行基于LS算法的OFDM调制解调系统信道估计和均衡的MATLAB仿真。本文将介绍一种基于LS(最小二乘)算法的OFDM调制解调系统信道估计和均衡算法,并提供相应的MATLAB仿真代码。

uote_e的博客 229

鸿蒙ArkUI内部API10以及11开发,输入框唤起输入法键盘,页面会被顶起的解决办法

鸿蒙ArkUI内部API10以及11开发,输入框唤起输入法键盘,页面会被顶起的解决办法

zmx781284440的博客 3214

【机器学习】阿里云天池竞赛——工业蒸汽量预测(6)

好的特征对于模型性能有着至关重要的影响。可以通过合成特征、对特征做简单变换、用决策树创造新特征、特征组合等方法对特征进行优化。

小哲的博客 1861

lammps原子组速度的计算方法

在lammps摩擦、冲击、压痕等模拟过程中,涉及到某个原子组的整体移动,如果要输出这个原子组的整体移动速度,可以使用vcm()函数。下面是一个具体的使用案例,金刚石球在盒子内移动,输出移动过程中金刚石球在x方向的质心速度。vcm()是lammps自带的一个函数,返回原子组质心在设定方向的速度。其中,ID为group-ID,dim为方向,可设置x、y或者z方向。大家好,我是小马老师。

lammps_jiayou的博客 343

【机器学习】阿里云天池竞赛——工业蒸汽量预测(2)

特征工程的处理流程为首先去掉无用特征,接着去除冗余的特征,如共线特征,并利用存在的特征、转换特征、内容中的特征以及其他数据源生成新特征,然后对特征进行转换(数值化、类别转换、归一化等),最后对特征进行处理(异常值、最大值、最小值,缺失值等)以符合模型的使用。在前面的数据探索中,通过KDE分布对比了特征变量在两个数据集中的分布情况,这里不再重复过程。使用相关系数法,先要计算各个特征对目标值的相关系数及相关系数的P值,然后根据阈值筛选特征。”,具体来说,特征越好、灵活性越强,构建的模型越简单、性能越出色。

小哲的博客 2037

SAP中关于预测需求的重要载体:计划独立需求

预测,就是为了调节客户需求的波动、不平衡,使企业的生产计划、物料计划尽量平稳、有序的必备工具。计划独立需求,Planned Independent Requirement(PIR)是SAP系统中最常见的预测需求。

saplakes的博客 1878

【RTD】二分法查找和分段线性插值算法在RTD中应用

二分法查找和分段线性插值算法在RTD中的典型应用。

只要思想不滑坡,想法总比问题多。 2369

阿里云天池比赛-工业蒸汽量预测:智能优化能源管理的关键一步

阿里云天池比赛-工业蒸汽量预测:智能优化能源管理的关键一步 去发现同类优质开源项目:https://gitcode.com/ 项目核心功能/场景 预测工业生产中的蒸汽消耗量,提升能源利用效率。 项目介绍 在当今工业生产中,蒸汽作为重要的能源介质,其消耗量的精确预测对于提高能源使用效率和降低生产成本具有重要意义。阿里云天池比赛-工业蒸汽量预测项目,正是为了解决这一问题而发起的挑战。该项目通过提供丰富...

gitblog_06710的博客 469

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

阿里云天池大赛赛题解析——机器学习篇 | 留言赠书

国内第一本针对竞赛实操的图书:《阿里云天池大赛赛题解析——机器学习篇》,正式发售。阿里云天池7年200多场数据大赛精华提取录为什么写这本书七年前,天池团队的几名创始成员带着“让全世界没有...

我爱计算机视觉 6456

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【机器学习】阿里云天池竞赛——工业蒸汽量预测(5)

欠拟合、过拟合、L1正则化、L2正则化、ElasticNet联合正则化、网格搜索、随机搜索 、LGB、随机森林

小哲的博客 1504

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【阿里云天池竞赛】工业蒸汽大赛

目录1、导包与数据挖掘1....

qq_36661843的博客 1110

国内首本数据竞赛图书《阿里云天池大赛赛题解析——机器学习篇》今日开启预售!

天池平台已经举办了超过 200 场来自真实业务场景的竞赛,每场赛事沉淀的课题和数据集,将在天池保留和开放。天池平台已成为在校学生踏入职场前的虚拟实践基地,也成为聚集40万数据人才,孵化2000余家数据创新工作室的数据智能大社区。 七年前,天池团队的几名创始成员带着*“让全世界没有能力Access到大数据的人可以公平地Access到大数据”*的信念,走上了建设天池的道路。 这7年间,天池举办了超过200场来自真实业务场景的竞赛。从2014年的首场天池天猫推荐算法挑战赛到2015年的阿里巴巴集团算法黄金..

博文视点(北京)官方博客 3702

贾扬清推荐,国内首本数据竞赛图书《阿里云天池大赛赛题解析——机器学习篇》今日开启预售!...

天池平台已经举办了超过 200 场来自真实业务场景的竞赛,每场赛事沉淀的课题和数据集,将在天池保留和开放。天池平台已成为在校学生踏入职场前的虚拟实践基地,也成为聚集40万数据人才,孵化2...

weixin_40920183的博客 786

【赠书】阿里巴巴副总裁贾扬清推荐,国内第一本数据竞赛相关图书正式预售...

国内第一本针对竞赛实操的图书:《阿里云天池大赛赛题解析——机器学习篇》,正式预售。阿里云天池7年200多场数据大赛精华提取录为什么写这本书七年前,天池团队的几名创始成员带着“让全世界没有...

简说Python的博客 715

机器学习竞赛入门书籍推荐

今天给大家推一本书。最近有不少粉丝朋友想打比赛,看了一下小白居多,于是今天就给大家分享一本适合新手的竞赛入门书,《阿里云天池大赛赛题解析---机器学习篇》。应该有不少人看过吧,没看过也没关系,我这不来推荐了(doge)?

学姐带你玩AI的博客 254

书里书外丨大咖论“赛”:阿里云天池 TOP 选手不得不说的那些事儿

七年前,天池团队的几名创始成员带着“让全世界没有能力Access到大数据的人可以公平地Access到大数据”的信念,走上了建设天池的道路。7年间,天池举办了超过200场来自真实业务场...

优快云资讯 3101

【送书 10 本】阿里巴巴副总裁贾扬清推荐,国内第一本数据竞赛相关图书,今天正式预售啦...

国内第一本针对竞赛实操的图书:《阿里云天池大赛赛题解析——机器学习篇》,今天正式预售了。阿里云天池7年200多场数据大赛精华提取录为什么写这本书七年前,天池团队的几名创始成员带着“让全世...

weixin_38753422的博客 559
上一篇: 【研究计划书】疾病检测中的语音生物标识研究
下一篇: 【机器学习】阿里云天池竞赛——工业蒸汽量预测(5)
镰刀韭菜
博客等级 码龄12年 2万+粉丝 853原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

镰刀韭菜

看在我不断努力的份上,支持我吧

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

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

打赏作者

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

抵扣说明:

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

余额充值