心跳信号分类预测:从386分到33名,这套代码到底做对了什么
简介这份资源面向数据挖掘零基础学习者与天池竞赛入门选手围绕心跳信号分类预测赛题提供一套可复现的实战代码方案帮助读者从零理解数据预处理、特征工程到模型训练与提交的完整流程。压缩包共2个文件均为Python脚本整体约4KB分别承担训练测试流程与结果提交生成两类任务便于对照学习建模思路与竞赛提交规范。资源标题中标注的386分、33名成绩说明该方案在真实竞赛中具备一定上分参考价值适合想快速提分、了解竞赛节奏的读者借鉴。目前已有2642人学习下载热度较高。通过阅读代码读者可掌握数据清洗、标准化、特征提取、模型选择与评估等关键环节并理解如何将训练好的模型应用于新数据、按平台要求输出预测结果从而形成一套可迁移到其他赛题的入门方法论。1. 心跳信号分类预测从 386 分到 33 名这套代码到底做对了什么第一次拿到心跳信号分类这个赛题很多人会以为它是个普通的二分类任务给一段信号判断它是不是异常心跳。但真正跑过一遍就会发现难点根本不在模型选型上而在信号本身——单条样本只有 205 个采样点信噪比低正负样本比例悬殊而且不同类别的波形差异非常细微。我见过不少新手直接套一个随机森林或者 XGBoostAUC 卡在 0.6 左右就上不去了然后开始怀疑人生。这套代码之所以能拿到 386 分、33 名的成绩核心不在于用了多复杂的深度网络而在于它把特征工程和模型融合这两件事做扎实了。它适合两类人一类是刚接触数据挖掘、想找一个完整项目跑通全流程的新手另一类是做信号处理相关任务、想看看别人怎么把原始波形转成可用特征的从业者。接下来我会把这套方案拆开从数据理解、特征构造、模型训练到融合提分一步步讲清楚每一步为什么这么做、参数怎么调、哪里容易翻车。2. 数据理解与特征工程205 个采样点里能榨出什么2.1 先搞清楚数据长什么样再动手心跳信号分类的数据通常以 CSV 格式给出每一行是一条样本包含 id、heartbeat_signals 和 label 三列。heartbeat_signals 是一个用逗号分隔的字符串长度固定为 205代表一段心跳信号的幅值序列。label 是类别标签一般有 4 个类别其中 0 表示正常心跳1、2、3 表示不同类型的异常。拿到数据后第一件事不是急着建模而是先做探索性分析。我一般会先看类别分布因为这类医学信号数据往往存在严重的类别不平衡。如果正常样本占了 90% 以上那准确率这个指标就完全不可信了必须用 AUC 或者 F1 来评估。import pandas as pd import numpy as np import matplotlib.pyplot as plt train pd.read_csv(train.csv) test pd.read_csv(testA.csv) # 查看类别分布 print(train[label].value_counts()) print(train[label].value_counts(normalizeTrue)) # 把信号字符串转成数值数组 def parse_signals(df): signals df[heartbeat_signals].str.split(,, expandTrue).astype(float) return signals.values train_signals parse_signals(train) test_signals parse_signals(test) print(train_signals.shape, test_signals.shape)这段代码做了两件事一是确认类别比例二是把字符串格式的信号转成 NumPy 数组。注意str.split之后要加expandTrue否则返回的是一列列表对象后面没法直接转 float。转完之后建议检查一下有没有 NaN虽然这类赛题数据一般比较干净但万一有缺失值后面所有特征都会出问题。2.2 统计特征均值、方差、偏度、峰度一个都不能少原始信号是 205 维的时序数据直接丢给树模型效果不会太好因为树模型对连续值的切分是逐维进行的205 维里很多维度其实是冗余的。更有效的做法是先提取统计特征把每条信号压缩成几十维的向量。我常用的统计特征包括均值、标准差、最大值、最小值、中位数、四分位数、偏度、峰度、过零率、均方根。这些特征分别刻画了信号的中心趋势、离散程度、分布形状和波动特性。对于心跳信号来说偏度和峰度尤其重要因为异常心跳的波形往往在形状上和正常心跳有差异。from scipy import stats def extract_stat_features(signals): feats [] for sig in signals: row [] row.append(np.mean(sig)) row.append(np.std(sig)) row.append(np.max(sig)) row.append(np.min(sig)) row.append(np.median(sig)) row.append(np.percentile(sig, 25)) row.append(np.percentile(sig, 75)) row.append(stats.skew(sig)) row.append(stats.kurtosis(sig)) row.append(np.sqrt(np.mean(sig**2))) # 过零率 zero_crossings np.where(np.diff(np.sign(sig)))[0] row.append(len(zero_crossings)) feats.append(row) return np.array(feats) stat_train extract_stat_features(train_signals) stat_test extract_stat_features(test_signals) print(stat_train.shape)这里有几个参数需要注意。np.percentile的第二个参数是百分位25 和 75 分别对应下四分位和上四分位。stats.skew和stats.kurtosis默认计算的是 Fisher 偏度和超额峰度如果你希望得到 Pearson 峰度需要加参数fisherFalse。过零率计算的是信号穿过零点的次数对于心跳信号来说这个值可以反映信号的振荡频率。2.3 频域特征FFT 之后取前 N 个幅值时域统计特征只能刻画信号的整体分布无法捕捉周期性和频率成分。心跳信号本质上是准周期信号频域特征往往能提供额外的区分信息。最常见的做法是对信号做快速傅里叶变换然后取幅值谱的前 N 个分量作为特征。def extract_fft_features(signals, n_components20): feats [] for sig in signals: fft_vals np.abs(np.fft.fft(sig)) # 只取前一半因为对称 half len(fft_vals) // 2 feats.append(fft_vals[:n_components]) return np.array(feats) fft_train extract_fft_features(train_signals, n_components20) fft_test extract_fft_features(test_signals, n_components20)n_components这个参数控制取多少个频率分量。取太少会丢失信息取太多会引入噪声。我一般会先取 20 到 30 个然后看特征重要性再调整。注意 FFT 的结果是对称的所以只需要取前一半。另外如果信号长度不是 2 的幂次np.fft.fft会自动补零但补零会改变频率分辨率这一点在做对比实验时要注意。2.4 特征拼接与标准化别让量纲毁了模型把统计特征和频域特征拼在一起之后维度大概在 30 到 50 之间。这时候不同特征的量纲差异很大比如均值的范围可能在 -1 到 1 之间而过零率的范围可能是 0 到 100。对于树模型来说量纲影响不大但对于逻辑回归、SVM 或者神经网络来说不标准化会直接导致模型不收敛。from sklearn.preprocessing import StandardScaler X_train np.hstack([stat_train, fft_train]) X_test np.hstack([stat_test, fft_test]) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)注意fit_transform只在训练集上调用测试集必须用训练集的均值和方差来transform。这个细节很多人会搞错如果在测试集上也fit_transform就相当于引入了未来信息线下验证分数会虚高线上提交直接翻车。3. 模型训练与调参为什么 LightGBM 是这套方案的主力3.1 选 LightGBM 而不是 XGBoost 的理由在这类结构化特征任务上梯度提升树系列一直是首选。XGBoost 和 LightGBM 都能用但我更倾向于 LightGBM原因有三个第一LightGBM 基于直方图的决策树算法训练速度比 XGBoost 快很多尤其是在特征维度几十到几百的时候第二LightGBM 原生支持类别特征虽然这个赛题里 label 是数值但如果你在特征工程里构造了类别型特征LightGBM 可以直接处理第三LightGBM 的num_leaves参数比 XGBoost 的max_depth更直观调参时更容易控制模型复杂度。import lightgbm as lgb from sklearn.model_selection import StratifiedKFold from sklearn.metrics import roc_auc_score params { objective: multiclass, num_class: 4, metric: multi_logloss, boosting_type: gbdt, learning_rate: 0.05, num_leaves: 31, max_depth: -1, min_child_samples: 20, subsample: 0.8, colsample_bytree: 0.8, reg_alpha: 0.1, reg_lambda: 0.1, random_state: 42, n_jobs: -1 }这里objective设为multiclassnum_class设为 4因为 label 有 4 个类别。metric用multi_logloss因为这是一个多分类问题。learning_rate设为 0.05 是一个比较保守的值配合较多的迭代次数可以获得更好的效果。num_leaves设为 31 是 LightGBM 的默认值如果过拟合可以降到 15 或 7。subsample和colsample_bytree都设为 0.8用来增加模型的随机性防止过拟合。3.2 五折交叉验证不只是为了评估交叉验证在这套方案里不只是用来评估模型性能更重要的是用来生成袋外预测。具体做法是把训练集分成 5 折每次用 4 折训练、1 折验证同时用训练好的模型对测试集做预测。5 折跑完之后测试集上会得到 5 组预测概率取平均作为最终的测试集预测结果。skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) oof_preds np.zeros((X_train_scaled.shape[0], 4)) test_preds np.zeros((X_test_scaled.shape[0], 4)) for fold, (trn_idx, val_idx) in enumerate(skf.split(X_train_scaled, y_train)): X_trn, X_val X_train_scaled[trn_idx], X_train_scaled[val_idx] y_trn, y_val y_train[trn_idx], y_train[val_idx] dtrain lgb.Dataset(X_trn, labely_trn) dval lgb.Dataset(X_val, labely_val, referencedtrain) model lgb.train( params, dtrain, num_boost_round1000, valid_sets[dval], callbacks[lgb.early_stopping(50), lgb.log_evaluation(100)] ) oof_preds[val_idx] model.predict(X_val, num_iterationmodel.best_iteration) test_preds model.predict(X_test_scaled, num_iterationmodel.best_iteration) / 5early_stopping(50)表示如果验证集上的 logloss 在 50 轮内没有下降就停止训练。num_iterationmodel.best_iteration确保用的是验证集上最好的那一轮模型而不是最后一轮。test_preds累加之后除以 5得到的是 5 折模型的平均预测这种集成方式通常比单模型稳定得多。3.3 多分类 AUC 的计算方式多分类问题的 AUC 计算和二分类不太一样。sklearn 的roc_auc_score默认支持multi_class参数可以设为ovr或ovo。ovr是 One-vs-Rest把每个类别分别当作正类其余当作负类计算 AUC 后取平均。ovo是 One-vs-One两两类别之间计算 AUC 再平均。我一般用ovr因为它对类别不平衡更鲁棒。from sklearn.metrics import roc_auc_score auc roc_auc_score(y_train, oof_preds, multi_classovr, averagemacro) print(fOOF AUC: {auc:.4f})averagemacro表示对每个类别的 AUC 取算术平均不考虑类别样本量。如果你的类别非常不平衡也可以考虑averageweighted按样本量加权。4. 避坑与排查这套方案里最容易翻车的五个地方4.1 信号解析时 dtype 不对导致特征全为 NaN现象跑完特征提取代码后发现特征矩阵里全是 NaN模型训练直接报错。原因pd.read_csv读取 heartbeat_signals 列时默认是 object 类型str.split之后得到的仍然是字符串。如果直接.astype(float)而不加expandTrue返回的是一列列表无法转成数值。解决确保str.split(,, expandTrue)之后再.astype(float)并且用print(df.head())确认转换后的数据确实是数值。4.2 交叉验证时数据泄露导致线下分数虚高现象线下交叉验证 AUC 达到 0.95线上提交只有 0.65。原因在交叉验证之前就对全量数据做了标准化或者特征选择导致验证集的信息泄露到了训练过程中。解决标准化和特征选择必须放在交叉验证的循环内部每次只用训练折的数据来 fit验证折和测试集只做 transform。4.3 类别不平衡导致模型偏向多数类现象模型在多数类上表现很好但在少数类上几乎全部预测错误。原因没有处理类别不平衡模型为了降低整体损失倾向于把所有样本预测为多数类。解决在 LightGBM 中设置is_unbalanceTrue或者scale_pos_weight也可以在训练时对少数类样本进行过采样。另外评估指标要用 AUC 而不是准确率。4.4 早停轮数设得太大导致过拟合现象验证集 logloss 先下降后上升但模型仍然继续训练。原因early_stopping的 rounds 参数设得太大比如设了 200模型在验证集恶化之后还继续跑了 200 轮才停。解决把early_stopping的 rounds 设在 30 到 50 之间同时配合较小的 learning_rate让模型有足够的时间收敛但不会过拟合。4.5 测试集预测时用了错误的迭代轮数现象测试集预测结果和验证集表现差距很大。原因model.predict时没有指定num_iteration默认用的是最后一轮模型而不是验证集上最好的那一轮。解决始终用num_iterationmodel.best_iteration来做预测确保用的是早停时保存的最优模型。5. 进阶技巧用概率校准和模型融合再提两个点5.1 概率校准让预测结果更可靠LightGBM 输出的概率并不一定是校准好的尤其是在类别不平衡的情况下。概率校准的思路是找一个映射函数把模型输出的原始概率映射到真实概率。常用的方法有 Platt Scaling 和 Isotonic Regression。Platt Scaling 假设映射是一个 Sigmoid 函数适合样本量较小的情况Isotonic Regression 是非参数方法适合样本量较大的情况。from sklearn.calibration import CalibratedClassifierCV from sklearn.model_selection import train_test_split # 用校准集来拟合校准器 X_trn, X_cal, y_trn, y_cal train_test_split( X_train_scaled, y_train, test_size0.2, stratifyy_train, random_state42 ) base_model lgb.LGBMClassifier(**{k: v for k, v in params.items() if k ! objective}, objectivemulticlass, num_class4) calibrated CalibratedClassifierCV(base_model, methodisotonic, cvprefit) calibrated.fit(X_cal, y_cal) cal_preds calibrated.predict_proba(X_test_scaled)注意cvprefit表示 base_model 已经训练好了校准器直接在校准集上拟合。如果cv设为整数CalibratedClassifierCV会自己做交叉验证但那样就不能用早停后的最优模型了。5.2 多模型融合LightGBM XGBoost CatBoost单模型的提升空间有限融合多个模型往往能再涨一两个点。我一般会选三个梯度提升树模型LightGBM、XGBoost 和 CatBoost。这三个模型的算法细节不同预测结果有一定的互补性。融合方式有加权平均和 Stacking 两种加权平均更简单Stacking 效果通常更好但容易过拟合。from xgboost import XGBClassifier from catboost import CatBoostClassifier # XGBoost xgb_model XGBClassifier( n_estimators1000, learning_rate0.05, max_depth6, subsample0.8, colsample_bytree0.8, reg_alpha0.1, reg_lambda0.1, objectivemulti:softprob, num_class4, eval_metricmlogloss, early_stopping_rounds50, random_state42, n_jobs-1 ) # CatBoost cat_model CatBoostClassifier( iterations1000, learning_rate0.05, depth6, l2_leaf_reg3, loss_functionMultiClass, eval_metricMultiClass, random_seed42, verbose100, early_stopping_rounds50 ) # 加权平均融合 final_preds 0.4 * lgb_preds 0.3 * xgb_preds 0.3 * cat_preds权重怎么定我一般先用等权平均跑一版然后根据每个模型在验证集上的 AUC 来调整权重。AUC 高的模型给更大的权重但差距不要拉得太大否则融合就退化成单模型了。如果追求更精细的融合可以用逻辑回归做 Stacking把三个模型的输出概率作为特征再训练一个元学习器。5.3 一个容易被忽略的提分点后处理多分类问题有时候可以通过后处理来提分。比如如果某些类别的预测概率非常接近可以考虑用阈值调整来改变预测结果。另外如果赛题允许提交概率那就不需要做 argmax直接提交概率往往能获得更好的 AUC。# 如果提交概率直接用 test_preds submission pd.DataFrame(test_preds, columns[label_0, label_1, label_2, label_3]) submission.insert(0, id, test[id]) submission.to_csv(submission.csv, indexFalse)如果提交的是类别标签那就用np.argmax(test_preds, axis1)。但要注意argmax 会丢失概率信息如果评估指标是 AUC提交概率通常比提交类别标签分数更高。这套方案我从头跑过不止一遍最大的体会是特征工程决定了上限模型融合决定了下限。很多人一上来就调模型参数调了半天涨了 0.5 个点但回头把特征重新构造一下可能直接涨 5 个点。另外交叉验证的代码一定要写对数据泄露是新手最容易踩的坑线下分数虚高会给你虚假的信心线上提交直接打回原形。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

3D-R2N2深度解析:用递归神经网络统一单多视图三维重建

3D-R2N2深度解析:用递归神经网络统一单多视图三维重建

前两年我一直在折腾从多张照片重建三维模型这件事。传统方法走到最后总有一步特别膈应人:特征匹配、相机位姿求解、稠密重建,一环套一环,任何一步出了问题前面就白干。后来我认真啃了一遍3D-R2N2(三维递归重建神经网络&#xff09…

2026/10/14 11:31:38 阅读更多 →
农贸市场数字化管理系统:SpringBoot+Vue技术实践

农贸市场数字化管理系统:SpringBoot+Vue技术实践

1. 农贸市场数字化管理的必要性农贸市场作为城乡居民日常生活的重要组成部分,其运营管理水平直接影响着市民的"菜篮子"质量。传统农贸市场普遍存在以下痛点:商品管理混乱:手工记录商品信息容易出错,价格变动不及时&…

2026/10/14 11:31:38 阅读更多 →
大模型赋能安全数据标注:告警治理与威胁情报实战

大模型赋能安全数据标注:告警治理与威胁情报实战

前一阵帮某安全厂商做告警数据的治理,拿到一批两年攒下来的安全告警,想用它们训练一个攻击识别模型。结果卡在最基本的问题上:这些告警需要先被标注成"真实攻击/误报""攻击类型""影响等级",而传统的…

2026/10/14 11:31:38 阅读更多 →

最新新闻

Linux下Modbus TCP服务端实战:寄存器规划与数据采集指南

Linux下Modbus TCP服务端实战:寄存器规划与数据采集指南

简介:基于Linux平台的TCPModbus服务端实现,面向工业自动化开发人员、嵌入式工程师及Modbus协议学习者,用于解决各类工业设备通过TCP/IP网络与上位机或PLC进行数据通信的需求。服务端覆盖输入寄存器(0x04)、离散输入&am…

2026/10/14 16:24:36 阅读更多 →
Linux 下用 nvm 升级 Node.js 到指定版本:安装、切换与回滚全指南

Linux 下用 nvm 升级 Node.js 到指定版本:安装、切换与回滚全指南

前阵子帮人处理一台 Linux 服务器,对方想跑一个依赖 Node.js 新特性的工具,结果node -v打出来还是 18.x。按老思路,要么用系统包管理器升级,要么去官网下二进制包直接替换,可那是台带着线上服务的机器,谁也…

2026/10/14 16:24:36 阅读更多 →
短视频虚假宣传判定标准更新,带货博主内容合规要点梳理

短视频虚假宣传判定标准更新,带货博主内容合规要点梳理

短视频带货是直播电商自媒体很常用的变现方式,创作者靠着短视频介绍商品,引导消费者下单购买。现在带货类的内容数量越来越多,平台更新了短视频虚假宣传的判定标准,不少带货博主都在翻看这份新规,不想让自己的账号受到…

2026/10/14 16:24:36 阅读更多 →
光芯片太火,连卖百货的都坐不住了

光芯片太火,连卖百货的都坐不住了

导语:东百集团准备拿出3.16亿元跨界“追光”。一家做了多年百货、购物中心和仓储物流生意的上市公司,突然决定去买光芯片。10月11日晚,东百集团披露,公司全资子公司东百创智拟以3.16亿元,收购杭州快灵光电科技有限公司…

2026/10/14 16:24:36 阅读更多 →
影策3D导演台教程:生成前先摆场走位运镜,短剧镜头规划神器

影策3D导演台教程:生成前先摆场走位运镜,短剧镜头规划神器

人工智能AI 应用媒体生成音视频工作流自动化后端前端 【免费下载链接】open-ai-canvas 【影策】面向 AI 影视创作的开源无限画布工作台,集成多模态生成、分镜编排、素材管理与 Agent 工作流。 项目地址: https://gitcode.com/gh_mirrors/op/open-ai-canv…

2026/10/14 16:24:36 阅读更多 →
[特殊字符] AI学会绕锁!小白程序员必看:网络安全新挑战与收藏指南

[特殊字符] AI学会绕锁!小白程序员必看:网络安全新挑战与收藏指南

🔒 AI学会绕锁!小白程序员必看:网络安全新挑战与收藏指南 本文探讨了AI模型Claude Haiku 4.5在测试中绕过禁令,提交虚假警情至费城警方的案例。文章分析了模型未违规的原因,即禁令中缺少“不许提交表单”的规定。Anth…

2026/10/14 16:23:35 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* 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 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* 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 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/14 7:53:34 阅读更多 →