NumPy数组拼接利器:np.r_与np.c_的深度解析与应用
1. 从两个不起眼的“快捷方式”说起如果你在NumPy的官方文档里闲逛或者翻看一些开源项目的代码大概率会碰到np.c_和np.r_这两个看起来有点“简陋”的对象。它们不像np.array或np.linspace那样是正经的函数名字也短得不像话一个下划线加一个字母乍一看像是某个内部变量或者临时占位符。很多初学者甚至一些用过一阵子NumPy的朋友对它们的印象可能都停留在“哦好像是用来拼接数组的”至于具体怎么用、什么时候用、背后有什么门道往往就一笔带过了。但恰恰是这种看似简单的工具在实际的数据处理、矩阵构造、特征工程等场景中能极大地提升代码的简洁性和可读性。我见过不少代码为了把几个一维数组按列拼成一个二维数组写了好几行reshape和concatenate其实用np.c_一行就能优雅解决。更关键的是不理解它们的本质就很容易用错比如把np.r_当np.c_用导致数据维度完全错乱排查起来还特别费劲。今天我们就来彻底拆解这两个“快捷方式”把它们从“熟悉的陌生人”变成你工具箱里得心应手的利器。简单来说np.c_和np.r_是NumPy提供的两个特殊的对象用于沿第二个轴列column和第一个轴行row快速拼接数组。它们的核心价值在于语法糖用非常简洁的方括号[]语法替代了相对繁琐的np.concatenate函数调用尤其在处理切片对象和生成网格坐标时显得无比方便。2. 核心机制np.r_与np.c_的本质剖析要理解这两个工具我们不能只看表面得深入到NumPy的源码逻辑和设计哲学里去。它们并不是魔法而是基于Python的索引语法和np.lib.index_tricks模块实现的“语法糖”。2.1 它们究竟是什么np.lib.index_tricks的产物首先np.r_和np.c_并不是函数而是np.lib.index_tricks模块中RClass和CClass类的实例。这个模块的名字就很有意思——“索引技巧”index tricks。它的设计初衷就是提供一些利用Python索引语法即方括号[]来实现复杂操作的便捷工具。当你写下np.r_[...]时你实际上是在对一个RClass的实例使用__getitem__方法。Python会把你写在方括号里的所有内容作为一个元组传递给这个方法。RClass和CClass的__getitem__方法则负责解析这个元组根据特定的规则按行拼还是按列拼调用底层的np.concatenate函数最终返回拼接后的数组。所以np.r_[a, b, c]本质上等价于np.concatenate((a, b, c), axis0)而np.c_[a, b, c]则等价于np.concatenate((a, b, c), axis1)前提是a, b, c的维度满足concatenate的要求。但np.r_和np.c_的强大之处在于它们对方括号内的内容做了更多“贴心”的处理。2.2 维度提升与自动处理让拼接更“智能”这是np.r_和np.c_最实用也最容易让人困惑的特性之一。普通的np.concatenate要求所有输入数组在非拼接轴上的维度必须完全一致否则直接报错。但np.r_和np.c_会尝试进行一些自动化的维度提升让拼接操作更宽容、更符合直觉。对于np.r_按行拼接axis0它的目标是沿着第一个轴行方向把数据堆叠起来。如果传入的是一维数组它会被自动视为一个“行向量”即形状为(1, n)的二维数组。这样多个一维数组就能被按行拼成一个二维数组。这个行为非常符合“将多个序列上下堆叠成表格”的直觉。import numpy as np a np.array([1, 2, 3]) b np.array([4, 5, 6]) # 使用 np.r_一维数组被提升为二维行向量后再拼接 result_r np.r_[a, b] print(result_r) # 输出[[1 2 3] # [4 5 6]] print(result_r.shape) # 输出(2, 3) # 等效的 concatenate 操作需要手动升维 result_concat np.concatenate([a[np.newaxis, :], b[np.newaxis, :]], axis0) print(result_concat) # 输出[[1 2 3] # [4 5 6]]对于np.c_按列拼接axis1它的目标是沿着第二个轴列方向把数据并排放在一起。如果传入的是一维数组它会被自动视为一个“列向量”即形状为(n, 1)的二维数组。这样多个一维数组就能被按列拼成一个二维数组。这对应着“将多个特征序列并排组成特征矩阵”的常见操作。import numpy as np a np.array([1, 2, 3]) b np.array([4, 5, 6]) # 使用 np.c_一维数组被提升为二维列向量后再拼接 result_c np.c_[a, b] print(result_c) # 输出[[1 4] # [2 5] # [3 6]] print(result_c.shape) # 输出(3, 2) # 等效的 concatenate 操作需要手动升维 result_concat np.concatenate([a[:, np.newaxis], b[:, np.newaxis]], axis1) print(result_concat) # 输出[[1 4] # [2 5] # [3 6]]注意这种自动升维是有条件的。当输入数组本身就是二维或更高维时np.r_和np.c_会严格按照axis0和axis1的规则进行拼接不再进行额外的维度变换。你需要对输入数组的维度心中有数。2.3 切片对象的魔法快速生成序列这是np.r_独有的一个“杀手级”特性也是它名字中 “r” 可能代表 “range” 的由来尽管官方未明确说明。你可以在方括号里直接使用类似于start:stop:step的切片语法np.r_会将其解释为np.arange(start, stop, step)。更强大的是它支持用逗号分隔多个切片最终会将所有切片生成的序列按行拼接起来。import numpy as np # 生成一个从0到9的序列 seq1 np.r_[0:10] print(seq1) # 输出[0 1 2 3 4 5 6 7 8 9] # 生成从0到4以及从10到14的序列并拼接 seq2 np.r_[0:5, 10:15] print(seq2) # 输出[ 0 1 2 3 4 10 11 12 13 14] # 可以指定步长 seq3 np.r_[0:10:2, 15:20:3] print(seq3) # 输出[ 0 2 4 6 8 15 18] # 甚至可以和已有的数组混合拼接 arr np.array([100, 200]) seq4 np.r_[arr, 0:5, 999] print(seq4) # 输出[100 200 0 1 2 3 4 999]这个功能在需要快速构造一个非连续、或由几段连续区间组成的索引数组时极其方便。np.c_不支持这种切片语法因为它被设计为按列拼接而切片生成的一维序列按列拼接的意义不大除非再转置但那不如直接用np.r_生成后转置更清晰。3. 实战场景对比np.r_与np.c_该如何选择理解了原理我们就要在实战中见真章。选择np.r_还是np.c_核心在于你的数据组织逻辑你是想增加样本行还是想增加特征列3.1 场景一构建机器学习特征矩阵np.c_的主场这是np.c_最经典的应用场景。假设你有一组样本每个样本有多个特征这些特征最初存储在不同的数组或序列中。你需要将它们组合成一个二维数组X其中每一行是一个样本每一列是一个特征。import numpy as np # 假设我们有3个样本收集了它们的年龄、收入两个特征 ages np.array([25, 30, 35]) # 形状 (3,) incomes np.array([50000, 60000, 80000]) # 形状 (3,) # 目标构建特征矩阵 X形状应为 (3, 2) # 使用 np.c_自动将一维数组转为列向量后按列拼接 X np.c_[ages, incomes] print(“特征矩阵 X:”) print(X) print(“X.shape:”, X.shape) # 输出 # 特征矩阵 X: # [[ 25 50000] # [ 30 60000] # [ 35 80000]] # X.shape: (3, 2) # 如果后续又计算了一个新特征工作年限 years_exp np.array([2, 5, 10]) # 可以轻松地添加为新列 X np.c_[X, years_exp] print(“添加新特征后的 X:”) print(X) print(“X.shape:”, X.shape) # 输出 # 添加新特征后的 X: # [[ 25 50000 2] # [ 30 60000 5] # [ 35 80000 10]] # X.shape: (3, 3)在这个场景下使用np.c_比用np.concatenate简洁太多意图也清晰无比“把这些数据按列特征拼起来”。3.2 场景二合并多个数据集或批量样本np.r_的主场当你需要将多个同结构的数据集或批次在垂直方向堆叠时np.r_就派上用场了。比如从多个文件加载数据或者在线学习时积累新的训练样本。import numpy as np # 第一批数据2个样本每个样本3个特征 batch1 np.array([[1, 2, 3], [4, 5, 6]]) # shape (2, 3) # 第二批数据同样是3个特征 batch2 np.array([[7, 8, 9], [10, 11, 12]]) # shape (2, 3) # 目标合并成一个数据集形状 (4, 3) # 使用 np.r_沿行方向axis0拼接 full_data np.r_[batch1, batch2] print(“合并后的数据集:”) print(full_data) print(“full_data.shape:”, full_data.shape) # 输出 # 合并后的数据集: # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] # full_data.shape: (4, 3) # 如果 batch2 是一维的错误情况np.r_会尝试升维但可能不符合预期 # batch2_wrong np.array([7, 8, 9, 10, 11, 12]) # shape (6,) # full_data_wrong np.r_[batch1, batch2_wrong] # 这会出错因为维度不匹配3.3 场景三生成网格坐标点np.r_与np.c_的默契配合在绘图、数值计算、创建测试数据时我们经常需要生成一个二维网格上所有点的坐标。np.meshgrid是标准做法但np.r_和np.c_结合切片语法提供了一种非常紧凑的替代方式尤其适合生成坐标向量。import numpy as np # 假设我们想要 x 从 -1 到 1共5个点y 从 0 到 2共3个点 x_points np.linspace(-1, 1, 5) y_points np.linspace(0, 2, 3) # 方法1使用 np.meshgrid标准方法 X, Y np.meshgrid(x_points, y_points) # 将网格展平并组合成坐标对 (x, y) coords_mesh np.c_[X.ravel(), Y.ravel()] print(“通过 meshgrid 生成的坐标 (前5个):”) print(coords_mesh[:5]) # 方法2利用 np.r_ 的切片语法生成所有 y 和 x 的重复序列 # 这个技巧需要一点思维转换我们需要的是每个 x 点重复 len(y)次每个 y 点整体重复 len(x)次 # 可以借助 np.r_ 的切片和数组拼接来实现更精细的控制但通常不如 meshgrid 直观。 # 一个更直接的“快捷”方式是生成索引网格但不如上述方法通用。 # 然而np.r_在生成一维坐标向量时非常简洁 # 快速生成一个非均匀采样的坐标轴 complex_axis np.r_[0:5, 10:20:2, 30] print(“复杂的坐标轴采样:”, complex_axis)对于生成完整网格np.meshgrid或np.mgrid/np.ogrid也是 index_tricks 模块的更合适。但np.r_在快速构造一维坐标序列上无可替代。4. 深入细节参数、陷阱与性能考量仅仅会用还不够用得好、用得稳还需要了解一些细节和潜在的坑。4.1np.r_的“字符串指令”参数np.r_的方括号内除了数组和切片还可以接收特殊的字符串指令用于微调拼接行为。最常见的是‘r’和‘c’用于控制一维数组在拼接前被转换成的二维数组的形状。‘r’代表 “row”强制将一维数组视为行向量1行N列。这是默认行为。‘c’代表 “column”强制将一维数组视为列向量N行1列。import numpy as np a np.array([1,2,3]) b np.array([4,5,6]) # 默认情况相当于 ‘r’按行拼接 print(np.r_[a, b]) # 输出[[1 2 3] [4 5 6]] shape (2,3) # 使用 ‘c’ 指令会将一维数组转为列向量但按行拼接列向量这会产生什么 # 实际上它会把 a 和 b 都变成列向量然后尝试沿行拼接两个列向量。 # 这要求两个列向量的列数相同都是1所以结果是上下堆叠两个列向量。 result np.r_[‘c’, a, b] print(result) # 输出 # [[1] # [2] # [3] # [4] # [5] # [6]] # shape (6, 1) # 更常见的用法是控制单个数组的转换比如确保按列拼接时标量或一维数组被正确当作列 # 但通常在 np.c_ 上下文中我们更关心列向量的转换而 np.c_ 本身默认就是 ‘c’ 行为。对于绝大多数应用你不需要显式使用这些指令。np.r_和np.c_的默认行为已经为各自的主要场景优化好了。了解它们的存在主要是为了在阅读复杂代码时能理解其意图。4.2 维度不匹配的陷阱与调试虽然np.r_和np.c_有自动升维的魔法但魔法不是万能的。维度不匹配是最大的错误来源。np.r_的陷阱np.r_沿axis0拼接。对于二维数组它要求所有数组的列数必须相同。import numpy as np a np.array([[1, 2], [3, 4]]) # shape (2, 2) b np.array([[5, 6, 7]]) # shape (1, 3) 列数不同 try: result np.r_[a, b] except ValueError as e: print(f“错误: {e}”) # 会报错all the input array dimensions except for the concatenation axis must match exactlynp.c_的陷阱np.c_沿axis1拼接。对于二维数组它要求所有数组的行数必须相同。import numpy as np a np.array([[1, 2], [3, 4]]) # shape (2, 2) b np.array([[5], [6], [7]]) # shape (3, 1) 行数不同 try: result np.c_[a, b] except ValueError as e: print(f“错误: {e}”) # 同样会报维度不匹配的错误调试建议当拼接出错时第一反应应该是打印每个输入数组的shape属性。确认你希望作为行/列对齐的维度是否一致。对于一维数组想清楚你希望它被当作行向量还是列向量。如果np.r_/np.c_的自动升维不符合你的预期可以手动使用arr[:, np.newaxis]转列向量或arr[np.newaxis, :]转行向量来明确控制维度然后再进行拼接。4.3 性能与np.concatenate的对比np.r_和np.c_是np.concatenate的语法糖最终都会调用它。因此在性能上它们与直接使用np.concatenate没有本质区别。主要的开销在于方括号语法解析的那一层薄薄的包装这在绝大多数应用中可以忽略不计。选择使用哪一个首要考虑的是代码清晰度和便利性。当你需要快速拼接几个数组尤其是混合了切片和数组时np.r_无可替代。当你明确要按列构建特征矩阵时np.c_的意图表达比np.concatenate(..., axis1)清晰得多。在性能关键的循环中或者拼接逻辑非常复杂时直接使用np.concatenate可能更直接避免了对语法糖的额外理解成本。但这种情况很少因为拼接操作本身通常不是性能瓶颈。一个细微的差别是np.concatenate接受一个包含所有数组的元组或列表作为第一个参数而np.r_和np.c_的方括号内是直接罗列。在数组数量动态生成时使用np.concatenate会更方便因为你很容易构造一个列表。import numpy as np # 动态生成数组列表进行拼接 list_of_arrays [np.random.randn(2, 3) for _ in range(5)] # 使用 concatenate 很自然 result_concat np.concatenate(list_of_arrays, axis0) # 使用 np.r_ 则需要解包略显繁琐 result_r np.r_[*list_of_arrays] # 使用 * 解包5. 举一反三相关工具与进阶技巧了解了np.r_和np.c_你的NumPy工具箱应该再补充另外两个“兄弟”工具np.mgrid和np.ogrid。它们同样来自np.lib.index_tricks用于生成网格。np.mgrid返回“密集”网格即直接生成多维坐标数组。它使用切片语法但返回的是已经广播broadcast好的多维数组。# 生成一个 2x3 的网格x从0到1y从0到2 Y, X np.mgrid[0:2, 0:3] # 注意顺序第一个切片对应第一个轴行第二个切片对应第二个轴列 print(“X (列坐标):”) print(X) # [[0 1 2] [0 1 2]] print(“Y (行坐标):”) print(Y) # [[0 0 0] [1 1 1]] # 可以直接用于计算例如计算距离D np.sqrt(X**2 Y**2)np.ogrid返回“开放”网格生成的是可广播的一维数组更节省内存。y, x np.ogrid[0:2, 0:3] print(“x:”, x) # [[0 1 2]] shape (1, 3) print(“y:”, y) # [[0] [1]] shape (2, 1) # x 和 y 可以直接通过广播机制进行运算效果和 mgrid 一样但内存占用小。一个实用的进阶技巧快速添加偏置项在机器学习中为线性模型添加偏置项bias term时通常需要在特征矩阵X左侧添加一列1。用np.c_可以优雅地实现import numpy as np X np.random.randn(100, 5) # 100个样本5个特征 # 添加偏置项一列1 X_with_bias np.c_[np.ones(X.shape[0]), X] print(X_with_bias.shape) # 输出(100, 6)这比np.hstack([np.ones((X.shape[0], 1)), X])或np.concatenate(...)都要简洁直观。最后记住np.r_和np.c_是工具而不是目的。它们的出现是为了让代码更清晰、更易写。当你发现自己在重复写reshape和concatenate来组合数组时不妨想想能不能用这两个“快捷方式”来简化。同时也要时刻清楚你操作的数据维度避免掉进自动升维的陷阱里。多写、多试、多打印shape是掌握它们的不二法门。

相关新闻

CTF实战:从Rabin密码系统原理到网鼎杯赛题解密

CTF实战:从Rabin密码系统原理到网鼎杯赛题解密

1. 项目概述:从一道CTF赛题看Rabin密码系统的实战攻防 最近在复盘一些经典的CTF(Capture The Flag)密码学赛题,2022年网鼎杯的“crypto661-rabin”这道题给我留下了挺深的印象。它没有用更常见的RSA,而是选择了Rabin密…

2026/10/11 4:14:49 阅读更多 →
Linux字符设备驱动开发:从基础概念到实战实现

Linux字符设备驱动开发:从基础概念到实战实现

1. 项目概述:为什么字符设备驱动是Linux内核的基石 在嵌入式开发、服务器运维乃至桌面应用开发中,只要你的程序需要和硬件打交道,或者需要在内核层面实现一个特殊的虚拟设备,那么“驱动”这个概念就绕不开。而字符设备驱动&#x…

2026/10/10 18:08:50 阅读更多 →
汇编语言入门:从寄存器理解CPU工作原理与实战应用

汇编语言入门:从寄存器理解CPU工作原理与实战应用

1. 从“黑盒子”到“透明车间”:为什么学汇编必须从寄存器开始 很多人一听到“汇编语言”,第一反应就是“天书”、“底层”、“难”。确实,相比Python、Java这些高级语言,汇编直接和硬件对话,少了层层抽象的保护壳。但…

2026/10/5 7:46:11 阅读更多 →

最新新闻

第2章:Linux 基础,pwd 命令

第2章:Linux 基础,pwd 命令

专栏导航 上一篇:第2章:Linux 基础,date 命令 回到目录 下一篇:第2章:Linux 基础,whoami 命令 本节前言 对于本节所讲解的知识,有可能,你会需要时不时地参考本专栏的其它文章。真…

2026/10/14 11:05:15 阅读更多 →
UE4 C++静态加载SkeletalMesh与动画蓝图完整实操

UE4 C++静态加载SkeletalMesh与动画蓝图完整实操

我们接着往下写。这是“基于C代码的UE4学习”系列第三十八篇,这次主题很聚焦:用C代码把 SkeletalMesh 加载到角色身上,并且静态加载一个动画蓝图。很多人在这个阶段会开始纠结——明明蓝图里拖个引用、拉个变量就行,为什么偏要用代…

2026/10/14 11:05:15 阅读更多 →
Kotlin泛型深度解析:类型擦除、型变与reified实战

Kotlin泛型深度解析:类型擦除、型变与reified实战

1. 从类型擦除说起:为什么Kotlin泛型值得单独开一个专题很多人学Kotlin泛型的时候,第一反应是"这不就是Java那套吗"。我一开始也这么想,直到在一个数据解析模块里踩了个坑——写了一个看似完美的泛型转换函数,编译通过&…

2026/10/14 11:05:15 阅读更多 →
重积分建模本质:从物理直觉到高维应用

重积分建模本质:从物理直觉到高维应用

1. 为什么重积分的应用远不止“算体积”——从物理建模到几何直觉的跃迁很多人学完二重积分,脑子里只留下一个公式:∬_D f(x,y) dσ。考试时套用极坐标换元、画个积分区域、算个数值,就以为掌握了。但我在带某高校数学分析实验课时发现&#…

2026/10/14 11:05:15 阅读更多 →
libxl 4.1.1带注册信息:C++离线生成Excel报表实践

libxl 4.1.1带注册信息:C++离线生成Excel报表实践

简介:libxl4.1.1 带注册信息资源包,聚焦高效轻量级 Excel 读写库的跨平台集成,面向需要将 Excel 处理能力嵌入应用的 C/C、C# 开发者,重点梳理 API 调用、依赖库、编译选项以及注册授权验证在 Windows 与 Linux 环境下的差异&…

2026/10/14 11:05:15 阅读更多 →
航空订票系统UML建模:用例图、时序图与类图实战指南

航空订票系统UML建模:用例图、时序图与类图实战指南

简介:航空订票系统是典型的信息管理系统设计案例,适合软件工程、系统分析与设计课程的学生,以及正在学习UML建模的开发者参考。资源以UML可视化建模为主线,覆盖用例图、类图、包图、顺序图、协作图、状态图、活动图、组件图与部署…

2026/10/14 11:04:13 阅读更多 →

日新闻

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 阅读更多 →