news 2026/10/13 1:38:04

鱼鹰算法优化XGBoost的Matlab分类预测实现与调参实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鱼鹰算法优化XGBoost的Matlab分类预测实现与调参实战

简介:针对鱼鹰算法优化XGBoost的分类预测任务,提供一套完整的Matlab实现源码及配套数据,适用于计算机、电子信息、数学等专业学生的课程设计、期末大作业和毕业设计。压缩包共18个文件约53.69MB,包含8个m源程序、4个mat实验数据、3张结果对比图,以及XGBoost运行所需的dll动态库、h头文件和一份报错解决方案文档,类型覆盖算法实现、数据输入、结果展示与排错指导。目前已有272人学习下载。代码采用参数化编程,注释详细,各函数独立可调,便于替换数据或修改超参数;运行后可直接输出分类对比图、混淆矩阵与预测准确率。此外,资源内还包含了OOA鱼鹰算法的完整优化流程,以及XGBoost常见报错的处理思路,有助于学习者掌握智能优化算法与集成分类模型的结合方法,快速复现并迁移到其他数据集。

1. 鱼鹰算法优化XGBoost分类预测:这个Matlab方案解决什么问题

OOA-XGBoost这个标题听起来拗口,拆开就一句话:用鱼鹰算法给XGBoost自动找超参数,再做分类预测。多少人把learning_rate从0.3试到0.05、max_depth从6试到3,一下午过去AUC还是卡在0.82。这不是能力问题,是XGBoost参数组合空间太大,手动试参本质就是穷举变体。OOA-XGBoost做的事,是把learning_rate、max_depth、subsample、colsample_bytree、gamma这一组超参数一次性交给鱼鹰算法搜出来,直接用于分类预测。全程在Matlab里跑通:数据读取、交叉验证、寻优、终评一条线走完。适合手里有Matlab、不想为了一个模型转Python,又需要在论文或交付里给出优化前后对比的工程师和学生。

2. 看懂OOA之前,先看懂XGBoost在Matlab里怎么落地

2.1 Matlab没有原生XGBoost:三种调用方式对比

很多下载过OOA-XGBoost相关源码的人,第一个困惑是Matlab里找不到xgboost函数。这不是你的问题,Matlab自带的机器学习工具箱里没有官方XGBoost接口。网上流传的“Matlab跑XGBoost”方案,本质上是以下三种里面的某一种。

调用方案本质优点缺点
fitcensemble('LSBoost')用集成学习器近似梯度提升零外部依赖,开箱即用不是真正的XGBoost,缺gamma、colsample_bytree等参数
Python引擎 py.xgboost调用本机Python环境里的xgboost参数完全对齐,真XGBoost需要安装Python与xgboost,调试略麻烦
第三方编译MEX接口把C++源码编译成Matlab MEX运行最快编译环境配置难度高,易劝退

先说第一类。fitcensemble训练LSBoost的好处是不装任何环境,坏处是它和XGBoost之间隔着至少三个关键参数:gamma、colsample_bytree、min_child_weight都没有对位概念。你用鱼鹰算法搜出来的colsample_bytree,fitcensemble根本不认。如果标题写的是XGBoost,内部却用LSBoost顶替,同行评审一眼就能看出来。

我一般直接推荐Python引擎这条路线,理由只有一个:参数完全对齐,OOA搜出什么参数,最终的XGBoost模型就吃进什么参数,结果经得起复现。第二是安装成本比想象中低,Python环境加一个pip install xgboost就够,比折腾编译省太多时间。先看一个最小调用:

pyenv; % 查看当前Python环境 py.importlib.import_module('xgboost'); % 确认xgboost可导入 % 把Matlab矩阵转成Python numpy数组 px = py.numpy.array(trainX); pyy = py.numpy.array(trainY); % 创建XGBoost专用数据结构 dd = py.xgboost.DMatrix(px, label=pyy);

这段代码的逻辑是先确认Matlab的Python引擎已经绑到正确的解释器,再把数据从Matlab内存搬到numpy,最后塞进DMatrix。参数说明有两点:pyenv在R2021a之后更常用,如果机器上有多个Python版本,要在调用之前执行pyenv('Version','你的解释器路径')指定环境;否则后续所有py.xgboost调用都会落到默认环境,而默认环境里往往没有xgboost,这是Matlab里跑这套方案的第一个坑。

至于第三种编译MEX接口的方案,性能确实最好,但坑在编译链路:需要配好MinGW或MSVC,拉下源码编译一次动辄半小时。除非你的产品对单次预测延迟有硬指标,否则为一个分类实验去啃编译,性价比太低。

2.2 需要优化的是哪几个超参数

一批数据喂进XGBoost之后,决定效果的是那组不直接参与建树的超参数。OOA不优化树结构本身,它只负责在超参数空间里搜索。我一般固定优化这6个,覆盖“学习率-树复杂度-采样”三条线:

参数类型范围对模型的影响
learning_rate连续[0.01, 0.3]学习率,越小模型越稳但越慢
max_depth整数[3, 10]树深,过大容易过拟合
min_child_weight连续[1, 10]叶子最小样本权重和,控制分裂
subsample连续[0.5, 1]行采样比例
colsample_bytree连续[0.5, 1]列采样比例
gamma连续[0, 1]分裂所需最小损失下降量

这6个参数之外,n_estimators不建议放进OOA搜索。原因不是它不重要,而是它和learning_rate强相关:树给太少,学习率再小也欠拟合;树给太多,早停机制又能兜住。我一般固定400棵树,配合后续的early stopping,让鱼鹰算法专注搜那6个靠手感很难摸准的参数。

还要注意参数的尺度差异:learning_rate是0.01到0.3之间的小数,max_depth是3到10的整数,gamma是0到1的连续值。直接把原始值扔进OOA,学习率在算法眼里小到可以被忽略。这也是第3章里我把lb和ub按每个维度单独设置的原因。如果习惯把所有变量映射到[0,1],那适应度函数里必须做一次反向解码。很多开源代码在这一步偷懒,结果就是搜出来的learning_rate永远贴着上界或下界,模型表现失真。

2.3 鱼鹰算法为什么比网格搜索和RandomizedSearchCV更省时间

有过调参经验的人大概率用过GridSearchCV或RandomizedSearchCV。网格搜索在6个参数、每个参数5个候选值时的组合数是几百到几万,直接穷举不现实;退一步用sklearn的RandomizedSearchCV随机抽几百组,运气成分又太大。鱼鹰算法是2023年提出的群智能优化算法,思路很直白:鱼鹰在高空能定位鱼群,这是全局勘探;锁定位置后俯冲捕鱼,这是局部开发。换成优化语言,就是先在整个参数空间里撒一批个体,快速找出几片“鱼多”的区域,再在好区域里精细搜索。

以这段简化代码为例,看一眼它的搜索逻辑:

% 全局勘探:模仿鱼鹰高空定位鱼群,向随机个体偏移 Xn = X(i,:) + rand(1,dim) .* (X(k,:) - X(i,:)); % 局部开发:模仿俯冲捕鱼,在半径r内精细搜索 Xn = X(i,:) + (2*rand(1,dim)-1) .* r .* (ub - lb);

这个公式说明OOA的两个阶段作用不同:前一式让个体向种群中某个位置移动,信息在个体之间共享;后一式在当前位置附近做小幅度扰动。相比网格搜索的穷举和随机搜索的盲抽,OOA每一轮都在朝已经发现的更优区域收敛,同一个时间预算内搜索质量明显更高。用我自己的话说,随机搜索像闭着眼往墙上扔飞镖,OOA至少给每支飞镖装了个向靶心靠近的磁铁。

但鱼鹰算法不是万能的。如果参数只有两三个、每轮评估只需要几毫秒,网格搜索仍然是首选,穷举反而最省心。OOA的价值在“每轮评估要跑一次交叉验证、数据集上万行”的场景里才真正体现出来:一次适应度计算几十秒,搜索次数直接决定什么时候下班。

3. 用OOA在Matlab里搜超参数的完整流程

3.1 数据划分:分层抽样与验证集拆分

先把数据拆干净,再谈寻优。很多人习惯拿randperm一打了之,这是后面一切虚高指标的源头。用今天这个方案的完整流程看,第一步必须是分层划分:

% 载入示例数据:最后一列是二分类标签 load('heart_data.mat'); % 替换成你自己的.mat文件 X = data.X; % 特征矩阵 Y = data.Y; % 标签,0/1 % 分层划分:训练70%,测试30% rng(2024); % 固定种子,保证可复现 cv = cvpartition(Y, 'HoldOut', 0.3, 'Stratify', true); trainX = X(cv.training, :); trainY = Y(cv.training, :); testX = X(cv.test, :); testY = Y(cv.test, :);

逻辑说明:cvpartition的Stratify参数保证训练集和测试集的正负样本比例接近原始数据。这在类别不平衡时特别关键,随机切分很可能把稀有类样本切到只剩几个,后面OOA看到的AUC就失真了。参数说明:HoldOut的0.3指测试集占30%,表格数据我一般取0.2到0.3;Stratify=true必须开,除非你的数据本身就是平衡的。

提示:测试集在第一步就要锁死,后续所有搜索与验证只碰trainX和trainY,最优参数定了之后再做一次终评。

这里多说一句:测试集在这个阶段就要“锁死”,后面所有搜索、验证都只碰trainX和trainY。等鱼鹰算法跑完,最优参数定了,测试集才能拿出来做一次终评。这是整个流程里最重要的一条数据纪律。

3.2 适应度函数:五折交叉验证与AUC

OOA所谓“适应度”,就是给每组候选参数打一个分。这个函数怎么写,直接决定搜索结果值不值得信。二分类场景里我不用准确率,而是用五折分层交叉验证的平均AUC:

function fitness = ooa_fitness(params, trainX, trainY) % params是一个1x6向量,对应6个超参数 lr = params(1); md = round(params(2)); % 深度取整,XGBoost不认小数 mcw = params(3); sub = params(4); col = params(5); gamma = params(6); % 五折分层交叉验证 cv = cvpartition(trainY, 'KFold', 5, 'Stratify', true); aucs = zeros(cv.NumTestSets, 1); for k = 1:cv.NumTestSets kx = trainX(cv.training(k), :); ky = trainY(cv.training(k), :); vx = trainX(cv.test(k), :); vy = trainY(cv.test(k), :); % 用这组参数训练一折XGBoost,返回预测概率 prob = run_xgb_fold(kx, ky, vx, vy, ... lr, md, mcw, sub, col, gamma); [~, ~, ~, auc] = perfcurve(vy, prob, 1); aucs(k) = auc; end fitness = 1 - mean(aucs); % OOA求最小,所以取1减平均AUC end

逻辑说明:适应度函数里把候选参数先翻译成真实XGBoost调用,每一折训练一次、验证一次,最后五折AUC取平均。为什么用1-AUC而不是accuracy:类别不平衡的数据里,准确率会被多数类拉高,AUC对正负样本比例不敏感,更能反映分类器排名的真实质量。参数说明:cv.NumTestSets在KFold下等于5,每折的training/test索引已经互斥,不需要再手动打乱。

这个函数的运行时间决定了整个寻优的耗时。如果一折训练要10秒,五折就是50秒,鱼鹰算法迭代40轮、种群20个,粗算就是20乘40乘50秒,接近11个小时。所以数据量大时,要么减少种群和迭代次数,要么把KFold从5降到3,要么先在采样数据上探路。后面第5章会给一组我常用的折中参数。

run_xgb_fold这个函数是连接Matlab与Python的关键,完整实现如下:

function prob = run_xgb_fold(kx, ky, vx, vy, lr, md, mcw, sub, col, gamma) % 用关键字参数构造XGBoost分类器 model = py.xgboost.XGBClassifier(pyargs(... 'eta', lr, ... 'max_depth', int32(md), ... 'min_child_weight', mcw, ... 'subsample', sub, ... 'colsample_bytree', col, ... 'gamma', gamma, ... 'n_estimators', int32(400), ... 'random_state', int32(42), ... 'use_label_encoder', false)); % 训练与预测 model.fit(py.numpy.array(kx), py.numpy.array(ky)); % proba转Matlab矩阵,第二列是正类概率 pred = double(py.numpy.array(model.predict_proba(py.numpy.array(vx)))); prob = pred(:, 2); end

这段代码的思路是:Matlab的矩阵通过py.numpy.array转成Python可读的数组,预测概率再转回Matlab。pyargs的作用是逐个传入XGBoost的关键字参数,注意max_depth用了int32强转,因为它要求整数类型;use_label_encoder=false是为了避免新版XGBoost的告警刷屏。如果你的Matlab版本较老,对py.numpy.array转二维double的支持不理想,可以先把数据拆成cell再转,效果一样。

3.3 OOA主循环的Matlab实现

鱼鹰算法的主循环不长,两个阶段加起来不到四十行。下面是我常用的一版实现:

function [globalBest, globalBestF] = OOA_XGB(... nPop, MaxIt, dim, lb, ub, trainX, trainY) % 初始化种群:在边界内随机撒点 X = repmat(lb, nPop, 1) + rand(nPop, dim) .* (ub - lb); F = zeros(nPop, 1); for i = 1:nPop F(i) = ooa_fitness(X(i,:), trainX, trainY); end [globalBestF, idx] = min(F); globalBest = X(idx, :); for t = 1:MaxIt % 阶段一:全局勘探,定位鱼群 for i = 1:nPop k = randi(nPop); while k == i k = randi(nPop); end Xn = X(i,:) + rand(1,dim) .* (X(k,:) - X(i,:)); Xn = max(min(Xn, ub), lb); % 边界夹逼 Fn = ooa_fitness(Xn, trainX, trainY); if Fn < F(i) X(i,:) = Xn; F(i) = Fn; end end % 阶段二:局部开发,俯冲捕鱼,半径随迭代收缩 r = 0.05 * (1 - t / MaxIt); for i = 1:nPop Xn = X(i,:) + (rand(1,dim)*2-1) .* r .* (ub - lb); Xn = max(min(Xn, ub), lb); Fn = ooa_fitness(Xn, trainX, trainY); if Fn < F(i) X(i,:) = Xn; F(i) = Fn; end end % 更新全局最优 [curBest, idx] = min(F); if curBest < globalBestF globalBestF = curBest; globalBest = X(idx, :); end end end

逻辑说明:两个阶段都用了“新位置更差就不接受”的贪心规则,保证种群整体不会越搜越差。阶段一的参照个体k是随机挑的,信息就在个体间扩散;阶段二的r从0.05线性降到接近0,前期大范围扫、后期小步精搜,这是让鱼鹰算法不早熟的关键。参数说明:nPop我一般取15到20,MaxIt取30到50,dim固定为6,lb和ub按3.4节设置。要注意max_depth上界不建议给超过10,树太深除了过拟合,还会让每轮交叉验证的训练时间成倍上涨。

3.4 完整调用与结果回收

主脚本把前面的函数串起来,跑一次完整的OOA-XGBoost:

%% 超参数边界:务必按每个参数的物理含义单独设置 lb = [0.01, 3, 1, 0.5, 0.5, 0]; ub = [0.30, 10, 10, 1, 1, 1]; % 跑鱼鹰算法 [bestP, bestF] = OOA_XGB(20, 40, 6, lb, ub, trainX, trainY); bestAUC = 1 - bestF; fprintf('最优AUC(五折交叉验证): %.4f\n', bestAUC); fprintf('learning_rate = %.3f\n', bestP(1)); fprintf('max_depth = %d\n', round(bestP(2))); % 用最优参数在训练集上重训,测试集终评放在第5章 finalParams = containers.Map('KeyType','char','ValueType','any'); finalParams('eta') = bestP(1); finalParams('max_depth') = round(bestP(2)); finalParams('min_child_weight') = bestP(3); finalParams('subsample') = bestP(4); finalParams('colsample_bytree') = bestP(5); finalParams('gamma') = bestP(6);

逻辑说明:搜索阶段和终评阶段分开,是这套流程最要紧的原则。搜索过程中测试集完全不参与,参数定了之后再拿训练集重训、测试集终评,避免数据泄漏。containers.Map只是把最优参数装进字典方便传给下一步的训练函数,也方便保存成.mat文件做实验记录。参数说明:lb/ub两行要跟上文的6个参数一一对应,顺序一旦错位,搜出来的参数全部串味;nPop与MaxIt的组合建议第一次运行先用(15, 30)探路,确认单轮适应度耗时后再放大。

4. OOA-XGBoost常见翻车现场与排查

4.1 现象一:Matlab报错ModuleNotFoundError: No module named 'xgboost'

这是个高频翻车点。很多人装好了Matlab,pyenv显示的是系统自带Python,那个环境里根本没装xgboost。现象就是在py.importlib.import_module('xgboost')这行直接报ModuleNotFoundError。

原因是Python环境和Matlab绑定的解释器不是同一个。解决分两步:先在命令行里用pip install xgboost装到目标环境,再在Matlab里把pyenv指过去:

% 指定解释器:路径必须和安装xgboost的环境一致 pyenv('Version', 'C:\Python311\python.exe'); py.importlib.import_module('xgboost'); % 验证是否成功

说明:pyenv('Version', ...)只需要在每次启动Matlab后设置一次,但要注意生效顺序——先设pyenv,再导包,顺序反了依然报错。如果你的机器上只有一个Python,大概率不会踩这个坑;多个环境并存时,八成问题都出在这里。

4.2 现象二:训练集AUC高达0.97,测试集只有0.71

现象很刺眼:搜索过程中适应度一路走低,最后测试集AUC却比训练集低一截。这不是鱼鹰算法不行,而是数据泄漏。最常见两个来源:一是归一化或标准化在全量数据上算均值方差,统计量把测试集的信息带进了训练过程;二是搜索阶段就偷偷用测试集做验证,或者测试集在多次调参中被重复查阅。

解决方法是把预处理严格限制在训练集内部:

% 错误做法:均值方差用全量数据算,测试信息已泄漏 mu = mean(X); s = std(X); X = (X - mu) ./ s; % 正确做法:只用训练集估计,测试集沿用同一组统计量 mu = mean(trainX); s = std(trainX); trainX = (trainX - mu) ./ s; testX = (testX - mu) ./ s;

说明:XGBoost本身是树模型,不做归一化通常也能跑,但一旦流程里混进了PCA或标准化,这个坑就必须按上述方式规避。另外测试集只能做一次终评,同一份测试集反复用来调阈值、改参数,本质上也是泄漏。

4.3 现象三:max_depth输出8.7,subsample输出1.15

OOA是连续优化算法,输出全是实数,但XGBoost的max_depth必须是整数,subsample范围是(0,1]。直接把8.7塞进xgboost,要么报参数错误,要么模型静默忽略,让人以为搜出的参数有效。

解决方式是在适应度函数入口和最终训练入口都做一次类型与边界校正:

md = round(bestP(2)); % 深度取整 sub = min(max(bestP(4), 0.01), 1); % 采样率夹到(0,1] lr = min(max(bestP(1), 0.005), 0.5); % 学习率兜底

说明:取整和夹逼必须同时用在两处——OOA内部的ooa_fitness里,以及最终用bestP重训时。只改一处,会出现“搜索时模型A和最终模型B参数不一致”的问题。我习惯把这类校正封装成一个sanitize_params函数,两处共用,避免改漏。

4.4 现象四:同一份代码,别人跑AUC 0.90,自己跑只有0.83

这里有两层问题。第一次跑出来0.83,在合理范围;同一个人连续跑三次,结果在0.80到0.86之间跳,那就要查随机源了。鱼鹰算法初始化种群是随机的,交叉验证划分是随机的,XGBoost内部的subsample和colsample采样也是随机的,三处叠加,方差不可能小。

排查顺序:先固定Matlab随机种子,再固定XGBoost的random_state,最后确认cvpartition每次调用前重置过种子。

rng(42); cv = cvpartition(trainY, 'KFold', 5, 'Stratify', true); % 调用py.xgboost时固定内部随机源 model = py.xgboost.XGBClassifier(pyargs(... 'subsample', sub, ... 'colsample_bytree', col, ... 'random_state', int32(42), ... 'use_label_encoder', false));

说明:固定种子只能保证同一台机器上可复现,跨机器跑会因浮点库版本不同出现毫米级差异,这是正常的。做实验记录时,把种子、参数范围、AUC结果一起写进日志,后续排查才有据可查。

5. 参数设置表与模型验证

5.1 OOA与XGBoost参数速查表

很多第一次跑这套方案的人,纠结的是“nPop到底给多少”。给少了搜索不充分,给多了时间爆炸。我常用的初值如下,数据量中等(一万行左右)时可以直接抄:

参数推荐初值调整方向
nPop(种群数)20数据量大减到15,优先保迭代次数
MaxIt(迭代数)40看收敛曲线,40轮后AUC不再变就停
K折数5小样本用10折更稳,大样本3折省时间
lb / ub见3.4max_depth上界别超过10
适应度1-AUC二分类默认;多分类可换logloss
每轮评估次数nPop×MaxIt第一次跑建议(15,30),探明耗时

关于“xgboost超参数自动设置”,这套参数表就是起点。真正提升xgboost提升运行效率的做法是记录每一次迭代的全局最优适应度,画出收敛曲线,观察曲线在多少轮后变平。如果20轮就平了,MaxIt给30就是浪费;如果40轮还在往下走,就加迭代。不要盲目照抄固定值。

5.2 混淆矩阵与AUC验证:结果怎么才算好

最优参数定下来之后,用训练集重训,再在锁了半天的测试集上做终评:

% 用最优参数在训练集上重训,预测测试集 [testPred, testProb] = train_and_predict(... trainX, trainY, testX, finalParams); % 混淆矩阵 C = confusionmat(testY, testPred); disp(C); % 综合指标 acc = sum(diag(C)) / sum(C(:)); [~,~,~,auc] = perfcurve(testY, testProb, 1); fprintf('Accuracy: %.4f, AUC: %.4f\n', acc, auc);

看结果时不要只盯准确率。表格数据的二分类问题里,混淆矩阵的右下角(假阴性)往往比准确率更关键。如果正样本是故障、骗贷、生病这类少数类,假阴性代价极高,应该同时看召回率和F1。期望值:样本规模中等、特征质量不差时,测试集AUC在0.85以上算及格,0.90以上算优秀;低于0.80就该回头检查特征和标签质量,而不是继续调参数。AUC这玩意儿有它的玄学成分,但它对类别不平衡不敏感,作为寻优目标是够用的。

5.3 与网格搜索和随机搜索的对比

给一个我在实际对比中得到的经验性结论,供参考:

方法单次开销搜索质量适用维度
网格搜索 GridSearchCV穷举,耗时随维度爆炸依赖候选值好坏≤3个参数
随机搜索 RandomizedSearchCV固定预算随机抽看运气,重复性差中等维度且预算紧
OOA-XGBoost种群×迭代可控稳定且可复现4个以上参数

网格搜索在参数维度少时依然是最优选,穷举意味着没有遗漏;但维度到6个之后,组合数让穷举失去意义。RandomizedSearchCV一次给几百组随机组合,每组之间没有关联,抽中了就赚,抽不中就白跑。鱼鹰算法的优势在于种群之间有信息交流,每次迭代都在向更优区域靠拢。我自己的经验是,同样给两个小时预算,OOA搜出的参数组合在测试集上的表现普遍比RandomizedSearchCV高0.02到0.05的AUC。

6. 把OOA-XGBoost沉淀成可复用模型

6.1 模型保存与加载

用Python引擎训练出的XGBoost模型,不能直接用matlab save存成.mat再load回来,那样模型对象会变成一堆丢失类型的结构体。正确做法是用Python侧的工具直接序列化:

% 训练结束后,把模型对象交给joblib保存 py.joblib.dump(model, 'xgb_model.pkl'); % 下次加载 model = py.joblib.load('xgb_model.pkl');

说明:joblib对XGBoost的兼容性比pickle更稳,尤其是树结构大的时候。保存时把finalParams和特征顺序一起存成单独的.mat文件,一个模型一个文件夹,以后回溯才有依据。

6.2 上线前的三个习惯

第一个习惯是固定所有随机源并写进日志。我一开始跑OOA-XGBoost没锁种子,AUC在0.80到0.86之间跳,后来把所有随机源全锁住才稳定。第二个习惯是记录特征顺序。XGBoost训练接受的是矩阵,模型本身不存特征名,上线时特征顺序一旦错位,预测结果全错而且很隐蔽。第三个习惯是每轮搜索只动训练集,测试集最后解锁,这个纪律在上述所有实验里贯穿到底。

如果你打算把这个方向做成产品的基线模型,我会建议在OOA搜完参数之后,再用全部数据以最优参数重训一次,替代只在训练集重训的做法;同时把早停开启,让模型在大样本下自动决定树数量。这套流程能不能直接提升业务指标,取决于特征工程和标签质量,但至少它把调参这件事从“玄学”变成了“可复现的搜索”。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 1:38:03

副队长CSS教程(1)–初识CSS

本文目录0. 写在前面1. HTML与CSS区别2. CSS有哪些功能3. 如何学习CSS0. 写在前面 这段话是这个系里教程完结后写的&#xff0c;CSS教程一共39篇&#xff0c;终于是完结了。 我用个人认为的合理顺序&#xff0c;介绍了CSS技术主要的技能点&#xff0c;并且对比较复杂的知识点…

作者头像 李华
网站建设 2026/10/13 1:38:03

VirtualBox虚拟机与主机互通,并且虚拟机又能上网

## 四种网络模式1、NAT 网络地址转换模式(NAT,Network Address Translation) 2、Bridged Adapter 桥接模式 3、Internal 内部网络模式 4、Host-only Adapter 主机模式 版本一&#xff1a;## 设置1、关闭虚拟机&#xff0c;VirtualBox->偏好设置->网络NAT网络&#xff0c;…

作者头像 李华
网站建设 2026/10/13 1:37:57

Sobel算子原理与OpenCV实战:图像梯度与边缘检测核心技术

1. 项目概述&#xff1a;为什么Sobel算子至今仍是图像边缘检测的“教科书级”起点在某高校计算机视觉实验课上&#xff0c;我带过一批刚接触OpenCV的大三学生。第一堂实操课布置任务&#xff1a;“用OpenCV实现一张灰度图的边缘提取”。结果近七成同学直接调用cv2.Canny()&…

作者头像 李华
网站建设 2026/10/13 1:37:41

手机号码定位HTML源码拆解:原理与实现全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:37:34

ARM平台手工部署MySQL 5.7:预编译包安装与避坑全指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:37:34

空想症与拖延绝症:神经科学视角下的行动启动障碍

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华