天池竞赛——工业蒸汽量预测(完整代码详细解析)

这篇具有很好参考价值的文章主要介绍了天池竞赛——工业蒸汽量预测(完整代码详细解析)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 赛题理解

1.1 赛题背景

火力发电的基本原理是:燃料在燃烧时加热水生成蒸汽,蒸汽压力推动汽轮机旋转,然后汽轮机带动发电机旋转,产生电能。在这一系列的能量转化中,影响发电效率的核心是锅炉的燃烧效率,即燃料燃烧加热水产生高温高压蒸汽。锅炉的燃烧效率的影响因素很多,包括锅炉的可调参数,如燃烧给量,一二次风,引风,返料风,给水水量;以及锅炉的工况,比如锅炉床温、床压,炉膛温度、压力,过热器的温度等。

赛事链接:https://tianchi.aliyun.com/competition/entrance/231693/information

1.2 赛题目标

经脱敏后的锅炉传感器采集的数据(采集频率是分钟级别),根据锅炉的工况,预测产生的蒸汽量。

2 数据探索

2.1 导库

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings("ignore")
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor # 随机森林回归
# from sklearn.svm import SVR       # 支持向量机
import lightgbm as lgb
from sklearn.model_selection import train_test_split   # 切分数据
from sklearn.metrics import mean_absolute_error        # 评价指标
from sklearn.metrics import mean_squared_error

2.2 获取数据

train_data_file = "D:/download/zhengqi_train.txt"
test_data_file = "D:/download/zhengqi_test.txt"

train_data = pd.read_csv(train_data_file, sep='\t', encoding='utf-8')
test_data = pd.read_csv(test_data_file, sep='\t',encoding='utf-8')

2.3 查看数据

train_data.info() 
train_data.describe()
  • info()与describe()的区别介绍

2.4 可视化数据分布

# KDE图 对比训练集与数据集中的数据分布
train_cols=6
train_rows=len(column)
plt.figure(figsize=(4*train_cols,4*train_rows))

i=0
for col in test_data.columns:
    i+=1
    ax = plt.subplot(train_rows,train_cols,i)
    ax = sns.kdeplot(train_data[col], color='red',shade=True)
    ax = sns.kdeplot(test_data[col], color='blue',shade=True)
    plt.ylabel('Frequency')
    ax.legend(['train','test'])
plt.tight_layout()

天池竞赛——工业蒸汽量预测(完整代码详细解析)

  • 根据上面KDE图对比可知:V2,V5,V9,V11,v13,V14,V17,V19,V20,V21,V22,V27,这12个训练集和测试集的特征差异较大,予以删除
# 删除训练集和测试集的特征差异较大的
train_data_X_new = train_data_X.drop(['V2','V5','V9','V11','V13','V14','V17','V19','V20','V21','V22','V27'], axis = 1)
test_data_new = test_data.drop(['V2','V5','V9','V11','V13','V14','V17','V19','V20','V21','V22','V27'], axis = 1)
all_data_X = pd.concat([train_data_X_new,test_data_new]) 

3 特征工程

  • 特征工程介绍

3.1 异常值分析

  • 以箱线图展示
# 异常值分析
plt.figure(figsize=(18,10))
plt.boxplot(x=train_data.values, labels=train_data.columns )
plt.hlines([-7.5,7.5], 0, 40, colors='red')    # 上下界限

天池竞赛——工业蒸汽量预测(完整代码详细解析)

  • 从箱线图可看出,V9变量明显存在异常,予以删除训练集和测试集中的异常值
#  删除异常值
train_data=train_data[train_data['V9']>-7.5]
test_data=test_data[test_data['V9']>-9.5]

3.2 归一化处理

#  归一化处理
from sklearn import preprocessing

feature_columns = [col for col in test_data.columns]
min_max_scaler = preprocessing.MinMaxScaler()
train_data_scaler = min_max_scaler.fit_transform(train_data[feature_columns])   # 进行标准化处理
test_data_scaler = min_max_scaler.fit_transform(test_data[feature_columns])

train_data_scaler = pd.DataFrame(train_data_scaler)  # 数组转换成表格
train_data_scaler.columns = feature_columns
test_data_scaler = pd.DataFrame(test_data_scaler)
test_data_scaler.columns = feature_columns

train_data_scaler['target']=train_data['target']

display(train_data_scaler.describe())
display(test_data_scaler.describe())

3.3 特征降维

#  特征相关性
plt.figure(figsize=(20,16))
column = train_data_scaler.columns

mcorr = train_data_scaler[column].corr(method='spearman')  # 相关性

# 特征降维       (相关性筛选)
mcorr = mcorr.abs()
numerical_corr = mcorr[mcorr['target']>0.1]['target']   # 筛选>0.1的特征变量, 并只显示特征变量
numerical_corr.sort_values(ascending=False)  # 从大到小排序

3.5 PCA处理

#  PCA 处理    (除去数据的多重共线性)
from sklearn.decomposition import PCA

pca = PCA(n_components=0.9)   # 保持90%的信息

new_train_pca = pca.fit_transform(train_data_scaler.iloc[:,0:-1])
new_test_pca = pca.fit_transform(test_data_scaler)
# pd.DataFrame(new_train_pca).describe()
  • PCA 处理后保留16个主要成分
pca = PCA(n_components=16)
new_train_pca_16 = pca.fit_transform(train_data_scaler.iloc[:,0:-1])
new_train_pca_16 = pd.DataFrame(new_train_pca_16)
new_test_pca_16 = pca.fit_transform(test_data_scaler)
new_test_pca_16 = pd.DataFrame(new_test_pca_16)
new_train_pca_16['target']=train_data_scaler['target']

4 模型训练

4.1 切分数据

# 切分数据
# 用PCA保留16维特征数据
new_train_pca_16 = new_train_pca_16.fillna(0)
train = new_train_pca_16[new_test_pca_16.columns]
target = train_data['target']

# 切分数据
train_data,test_data,train_target, test_target = train_test_split(train,target, test_size=0.2, random_state=0)

采用以下几个模型进行训练和融合:

  • 多元线性回归
  • 随机森林回归
  • LGB模型回归

4.2 多元线性回归

# 多元线性回归
clf = LinearRegression()
clf.fit(train_data, train_target)
mse = mean_absolute_error(test_target, clf.predict(test_data))

4.3 随机森林回归

# 随机森林回归
clf = RandomForestRegressor(n_estimators=400)
clf.fit(train_data,train_target)
mse2 = mean_absolute_error(test_target, clf.predict(test_data))

4.4 LGB模型回归

# LGB模型回归
clf = lgb.LGBMRegressor(learning_rate=0.01,
                       max_depth=-1,
                       n_estimators=5000,
                       boosting_type='gbdt',
                       random_state=2022,
                       objective='regression')
clf.fit(X=train_data, y=train_target,eval_metric='MSE',verbose=50)
mse3 = mean_absolute_error(test_target, clf.predict(test_data))

print('LinearRegression的测试集的MSE得分为:{}'.format(mse))
print('RandomForestRegressor的测试集的MSE得分为:{}'.format(mse2))
print('LGBMRegressor的测试集的MSE得分为:{}'.format(mse3))

LinearRegression的测试集的MSE得分为:0.27154696439540776
RandomForestRegressor的测试集的MSE得分为:0.33357155112651654
LGBMRegressor的测试集的MSE得分为:0.2925846323943153

5 调参

5.1 RandomForest网格搜索调参

#  # 使用数据训练随机森林模型,采用网格搜索方法调参
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

train_data, test_data, train_target, test_target = train_test_split(train, target, test_size=0.2, random_state=0)
randomForestRegression = RandomForestRegressor()
parameters = {'n_estimators':[50,100,200], 'max_depth':[1,2,3]}
clf = GridSearchCV(randomForestRegression, parameters, cv=5)
clf.fit(train_data, train_target)
score_test = mean_squared_error(test_target, clf.predict(test_data))

print('调参后的RandomForest_Regressor的训练集得分:{}'.format(clf.score(train_data,train_target)))
print('调参后的RandomForest_Regressor的测试集得分:{}'.format(clf.score(test_data,test_target)))
print("RandomForest模型调参前MSE:{}".format(mse))
print("RandomForest模型调参后MSE:{}".format(score_test))

调参后的RandomForest_Regressor的训练集得分:0.7511256945888011
调参后的RandomForest_Regressor的测试集得分:0.7536945206333742
RandomForest模型调参前MSE:0.2715462476084652
RandomForest模型调参后MSE:0.25594319639915

5.2 RandomForest随机参数优化调参

# 使用数据训练随机森林模型,采用随机参数优化方法调参
from sklearn.model_selection import RandomizedSearchCV
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split 

train_data, test_data, train_target, test_target =train_test_split(train, target, test_size=0.2, random_state=0)
randomForestRegressior = RandomForestRegressor()
parameters = {'n_estimators':[50, 100, 200, 300], 'max_depth':[1,2,3,4,5]}
clf = RandomizedSearchCV(randomForestRegressior, parameters, cv=5)
clf.fit(train_data, train_target)
score_test = mean_squared_error(test_target, clf.predict(test_data))

print('调参后的RandomForest_Regressor的训练集得分:{}'.format(clf.score(train_data,train_target)))
print('调参后的RandomForest_Regressor的测试集得分:{}'.format(clf.score(test_data,test_target)))
print("RandomForest模型调参前MSE:{}".format(mse))
print("RandomForest模型调参后MSE:{}".format(score_test))

调参后的RandomForest_Regressor的训练集得分:0.8403572920031047
调参后的RandomForest_Regressor的测试集得分:0.8108811667658115
RandomForest模型调参前MSE:0.2715386496432197
RandomForest模型调参后MSE:0.19651888704102724

5.3 LGB调参

# lgb模型调参
clf = lgb.LGBMRegressor(num_leaves=31)
parameters = {'learning_rate':[0.01,0.1,1],'n_estimators':[20,40]}
clf= GridSearchCV(clf, parameters, cv=5)
clf.fit(train_data, train_target)
score_test = mean_squared_error(test_target, clf.predict(test_data))

print('调参后的LGB的训练集得分:{}'.format(clf.score(train_data,train_target)))
print('调参后的LGB的测试集得分:{}'.format(clf.score(test_data,test_target)))
print("LGB模型调参前MSE:{}".format(mse))
print("LGB模型调参后MSE:{}".format(score_test))

调参后的LGB的训练集得分:0.9323247311228453
调参后的LGB的测试集得分:0.8634907871306278
LGB模型调参前MSE:0.2651442640764948
LGB模型调参后MSE:0.15026337772469497文章来源地址https://www.toymoban.com/news/detail-501374.html

6.1 模型融合

  • 将LinearRegression,LGB,RandomForestRegressor三个模型融合
# 3个模型融合
def model_mix(pred_1, pred_2, pred_3):
    result = pd.DataFrame(columns=['LinearRegression', 'LGB', 'RandomForestRegressor', 'Combine'])

    for a in range(10):
        for b in range(10):
            for c in range(1,10):
                test_pred = (a * pred_1 + b * pred_2 + c * pred_3) / (a + b + c)

                mse = mean_squared_error(test_target, test_pred)

                result = result.append([{'LinearRegression': a,
                                         'LGB': b,
                                         'RandomForestRegressor': c,
                                         'Combine': mse}],
                                       ignore_index=True)
    return result


model_combine = model_mix(linear_predict, LGB_predict, RandomForest_predict)

model_combine.sort_values(by='Combine', inplace=True)
print(model_combine.head())
  • a, b , c = 10的结果:
    天池竞赛——工业蒸汽量预测(完整代码详细解析)
  • a, b , c = 30的结果:
    天池竞赛——工业蒸汽量预测(完整代码详细解析)
    通过上述两次改变权重的实验,发现权重从10加大到30,对最终的combine值有些提高

完整代码:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings("ignore")
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor # 随机森林回归
# from sklearn.svm import SVR       # 支持向量机
import lightgbm as lgb
from sklearn.model_selection import train_test_split   # 切分数据
from sklearn.metrics import mean_absolute_error        # 评价指标
from sklearn.metrics import mean_squared_error
# from xgboost import XGBRegressor

train_data_file = "D:/download/zhengqi_train.txt"
test_data_file = "D:/download/zhengqi_test.txt"

train_data = pd.read_csv(train_data_file, sep='\t', encoding='utf-8')
test_data = pd.read_csv(test_data_file, sep='\t',encoding='utf-8')

    # train_data.info()
    # train_data.describe()

train_cols=6
train_rows=len(train_data.columns)
plt.figure(figsize=(4*train_cols,4*train_rows))
i = 0
for col in test_data.columns:
    i += 1
    ax = plt.subplot(train_rows,train_cols,i)
    ax = sns.kdeplot(train_data[col], color='red',shade=True)
    ax = sns.kdeplot(test_data[col], color='blue',shade=True)
    plt.ylabel('Frequency')
    ax.legend(['train','test'])
plt.tight_layout()

train_data_y = train_data['target']
train_data_new = train_data.drop(['V2','V5','V9','V11','V13','V14','V17','V19','V20','V21','V22','V27','target'], axis = 1)
test_data_new = test_data.drop(['V2','V5','V9','V11','V13','V14','V17','V19','V20','V21','V22','V27'], axis = 1)
all_data_X = pd.concat([train_data_new,test_data_new])

# 异常值分析
plt.figure(figsize=(18,10))
plt.boxplot(x=train_data.values, labels=train_data.columns )
plt.hlines([-7.5,7.5], 0, 40, colors='red')    # 上下界限
#  删除异常值
train_data=train_data[train_data['V9']>-7.5]
test_data=test_data[test_data['V9']>-9.5]

#  归一化处理
from sklearn import preprocessing

feature_columns = [col for col in test_data.columns]
min_max_scaler = preprocessing.MinMaxScaler()
train_data_scaler = min_max_scaler.fit_transform(train_data[feature_columns])   # 进行标准化处理
test_data_scaler = min_max_scaler.fit_transform(test_data[feature_columns])

train_data_scaler = pd.DataFrame(train_data_scaler)  # 数组转换成表格
train_data_scaler.columns = feature_columns
test_data_scaler = pd.DataFrame(test_data_scaler)
test_data_scaler.columns = feature_columns

train_data_scaler['target']=train_data['target']

#  特征相关性
plt.figure(figsize=(20,16))
column = train_data_scaler.columns

mcorr = train_data_scaler[column].corr(method='spearman')  # 相关性
mcorr = mcorr.abs()
numerical_corr = mcorr[mcorr['target']>0.1]['target']   # 筛选>0.1的特征变量, 并只显示特征变量
numerical_corr.sort_values(ascending=False)  # 从大到小排序

#  PCA 处理    (除去数据的多重共线性)
from sklearn.decomposition import PCA

pca = PCA(n_components=0.9)   # 保持90%的信息

new_train_pca = pca.fit_transform(train_data_scaler.iloc[:,0:-1])
new_test_pca = pca.fit_transform(test_data_scaler)

pca = PCA(n_components=16)
new_train_pca_16 = pca.fit_transform(train_data_scaler.iloc[:,0:-1])
new_train_pca_16 = pd.DataFrame(new_train_pca_16)
new_test_pca_16 = pca.fit_transform(test_data_scaler)
new_test_pca_16 = pd.DataFrame(new_test_pca_16)
new_train_pca_16['target']=train_data_scaler['target']


# 用PCA保留16维特征数据
new_train_pca_16 = new_train_pca_16.fillna(0)
train = new_train_pca_16[new_test_pca_16.columns]
target = train_data['target']

# 切分数据
train_data,test_data,train_target, test_target = train_test_split(train,target, test_size=0.2, random_state=0)

# 多元线性回归
clf = LinearRegression()
clf.fit(train_data, train_target)
mse = mean_absolute_error(test_target, clf.predict(test_data))
linear_predict = clf.predict(test_data)

# LGB模型回归
clf2 = lgb.LGBMRegressor(learning_rate=0.01,
                       max_depth=-1,
                       n_estimators=5000,
                       boosting_type='gbdt',
                       random_state=2022,
                       objective='regression')
clf2.fit(X=train_data, y=train_target,eval_metric='MSE',verbose=50)
mse2 = mean_absolute_error(test_target, clf2.predict(test_data))
LGB_predict = clf2.predict(test_data)

# 随机森林回归
clf = RandomForestRegressor(n_estimators=400)
clf.fit(train_data,train_target)
mse3 = mean_absolute_error(test_target, clf.predict(test_data))
# RandomForest_predict = clf.predict(test_data)

#  # 使用数据训练随机森林模型,采用网格搜索方法调参
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

train_data, test_data, train_target, test_target = train_test_split(train, target, test_size=0.2, random_state=0)
randomForestRegression = RandomForestRegressor()
parameters = {'n_estimators':[50,100,200], 'max_depth':[1,2,3]}
clf = GridSearchCV(randomForestRegression, parameters, cv=5)
clf.fit(train_data, train_target)
score_test = mean_squared_error(test_target, clf.predict(test_data))


# 使用数据训练随机森林模型,采用随机参数优化方法调参
from sklearn.model_selection import RandomizedSearchCV
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

train_data, test_data, train_target, test_target =train_test_split(train, target, test_size=0.2, random_state=0)
randomForestRegressior = RandomForestRegressor()
parameters = {'n_estimators':[50, 100, 200, 300], 'max_depth':[1,2,3,4,5]}
clf = RandomizedSearchCV(randomForestRegressior, parameters, cv=5)
clf.fit(train_data, train_target)
score_test = mean_squared_error(test_target, clf.predict(test_data))

# lgb模型调参
clf3 = lgb.LGBMRegressor(num_leaves=31)
parameters = {'learning_rate':[0.01,0.1,1],'n_estimators':[20,40]}
clf3= GridSearchCV(clf3, parameters, cv=5)
clf3.fit(train_data, train_target)
score_test = mean_squared_error(test_target, clf3.predict(test_data))
RandomForest_predict = clf3.predict(test_data)
# print('调参后的LGB的训练集得分:{}'.format(clf.score(train_data,train_target)))
# print('调参后的LGB的测试集得分:{}'.format(clf.score(test_data,test_target)))
# print("LGB模型调参前MSE:{}".format(mse))
# print("LGB模型调参后MSE:{}".format(score_test))

# 3个模型融合
def model_mix(pred_1, pred_2, pred_3):
    result = pd.DataFrame(columns=['LinearRegression', 'LGB', 'RandomForestRegressor','Combine'])

    for a in range(30):
        for b in range(30):
            for c in range(1,30):
                test_pred = (a * pred_1 + b * pred_2 + c * pred_3) / (a + b + c)

                mse = mean_squared_error(test_target, test_pred)

                result = result.append([{'LinearRegression': a,
                                        'LGB': b,
                                         'RandomForestRegressor': c,
                                         'Combine': mse}],
                                        ignore_index=True)
    return result


model_combine = model_mix(linear_predict, LGB_predict, RandomForest_predict)

model_combine.sort_values(by='Combine', inplace=True)
print(model_combine.head())

到了这里,关于天池竞赛——工业蒸汽量预测(完整代码详细解析)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 带头结点单链表【详细解析+完整代码】

    它是通过一组任意的储存单元来存储线性表中的数据元素。为建立线性关系,每个结点需要一个指针域以及指向下一结点的指针域。带头结点链表头节点不存储数据。 结点结构: 带头结点链表结构: 保证了每个结点都有前驱结点,因此在链表上第一个结点的操作与其他结点操

    2024年04月15日
    浏览(44)
  • 时间序列预测实战(二十五)PyTorch实现Seq2Seq进行多元和单元预测(附代码+数据集+完整解析)

    本文给大家带来的时间序列模型是Seq2Seq,这个概念相信大家都不陌生了,网上的讲解已经满天飞了,但是本文给大家带来的是我在Seq2Seq思想上开发的一个模型和新的架构,架构前面的文章已经说过很多次了,其是专门为新手开发的,而且为了方便大家使用只定义了一个文件

    2024年02月04日
    浏览(46)
  • Java——ATM程序(完整代码详细解析)

    目录 一、需求 二、详细解析 三、完整代码

    2024年02月07日
    浏览(46)
  • Python | 基于LendingClub数据的分类预测研究Part02——进一步分类研究+结论+完整详细代码

    本文利用Python对数据集进行数据分析,并用多种机器学习算法进行分类预测。 具体文章和数据集可以见我所发布的资源:发布的资源 前半部分:Python | 基于LendingClub数据的分类预测研究Part01——问题重述+特征选择+算法对比 在前文中,我们用 Logistic Regression 模型研究 Lending

    2023年04月21日
    浏览(36)
  • 阿里天池竞赛 - CCKS2023-面向金融领域的主体事件检测

    主体事件检测 是语言文本分析和金融领域智能应用的重要任务之一,如在金融风控领域往往会对公司主体进行 风险事件的检测 。基于 句子粒度的上下文 进行公司事件检测,事件包含 事件类型 和 主体要素(即公司主体 ),句中可能存在多个事件,多个公司主体且每个公司

    2024年02月09日
    浏览(44)
  • 第十六届“华中杯”大学生数学建模挑战赛(B题)深度剖析|建模完整过程+详细思路+代码全解析

    问题1的建模过程如下: 假设信号灯周期固定不变,且已知所有车辆的行车轨迹,我们可以建立如下模型来估计信号灯的红绿周期: 首先,我们需要定义一些符号: T s i g n a l T_{signal} T s i g na l ​ :信号灯的红绿周期,单位为秒 T t r a c k T_{track} T t r a c k ​ :车辆行车轨迹数

    2024年04月28日
    浏览(88)
  • 天池案例赛--银行产品认购预测

    大赛是以银行产品认购预测为背景,根据记录的用户信息来推测该银行的用户是否会购买银行的产品。 赛题提供的数据集有3万条(训练集2.25万,测试集0.75万),包括20个特征变量,本文构建了XGBoost、LGBM、随机森林、逻辑回归、支持向量机、朴素贝叶斯分类器;得分分别为

    2024年02月08日
    浏览(36)
  • 【TIANCHI】天池大数据竞赛(学习赛)--- 淘宝用户购物行为数据可视化分析

    目录 前言 一、数据集的来源和各个字段的意义 二、数据分析 1.引入库 2.读入数据 3.查看数据数量级 4.PV(Page View)/UV访问量 5.漏斗模型 6.用户购买商品的频次分析。 7.ARPPU(average revenue per paying user)  计算 ARPPU  ARPPU出图 8.复购情况分析 计算用户购买频次 复购周期分析 总结

    2024年02月09日
    浏览(42)
  • pytorch分类和回归:阿里天池宠物年龄预测

    阿里天池宠物年龄预测 https://tianchi.aliyun.com/competition/ 实验了多种方法,最终成绩并不是特别好,比赛结束后如果有更好的思路,欢迎指教。 直接回归 分段分类 分段求概率,求加权期望,其实相当于回归。 三种方法的表现 其他方法: 拟合分布,而不是one-hot 排序的方式 数

    2024年02月15日
    浏览(67)
  • 天池长期赛:二手车价格预测(422方案分享)

    前言 一、赛题介绍及评测标准 二、数据探索(EDA) 1.读取数据、缺失值可视化 2.特征描述性统计 3.测试集与验证集数据分布 4.特征相关性 三、数据清洗 四、特征工程 1.构建时间特征 2.匿名特征交叉 3.平均数编码 五、建模调参 六、模型融合 总结 赛题属于回归类型,相比于

    2024年02月01日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包