
本文介绍一种基于区间映射与布尔数组的高性能方法,用于统计给定宽度纸张中未被任何文本/图形覆盖的等宽条带数量,显著优于逐条筛选和分组计数的传统方案。
本文介绍一种基于区间映射与布尔数组的高性能方法,用于统计给定宽度纸张中未被任何文本/图形覆盖的等宽条带数量,显著优于逐条筛选和分组计数的传统方案。
在文档分析或印刷排版场景中,常需评估一张固定宽度纸张(如 total_width=20.0)上可裁出多少个完全空白的等宽条带(如 strip_width=2.0)。输入数据为 pandas DataFrame,每行表示一个标记区域的左右边界 x0 和 x1(单位:cm),目标是找出所有不与任何标记区间重叠的条带数量。
核心挑战在于:传统基于 pd.cut() 的分组计数法仅在所有标记宽度小于条带宽度时才可靠;而暴力遍历 + df.loc[] 筛选(如 count_unmarked_strips_alt)虽逻辑正确,但因频繁索引和布尔运算导致性能急剧下降(尤其在大数据集上)。
更优解法是将连续坐标空间离散化为整数索引,并利用 NumPy 的向量化切片能力批量标记“被占用”的条带:
import numpy as np
import pandas as pd
def count_unmarked_strips(df, total_width, strip_width):
"""
高效统计纸张中未被标记的等宽条带数量
Parameters:
-----------
df : pd.DataFrame
必须包含 'x0' 和 'x1' 列,表示每个标记区间的左右边界(浮点)
total_width : float
纸张总宽度(>= 所有 x1)
strip_width : float
每个条带的目标宽度(> 0)
Returns:
--------
int : 完全空白的条带数量
"""
# 计算条带总数(向下取整,忽略超出 total_width 的部分)
n_total = int(total_width // strip_width)
if n_total <p>✅ <strong>关键优势说明:</strong> </p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill4207" title="腾讯文档"><img
src="https://img.php.cn/upload/skill/000/000/081/178996505652836.jpg" alt="腾讯文档" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill4207" title="腾讯文档" class="overflowclass">腾讯文档</a>
<p class="overflowclass">腾讯文档(docs.qq.com)-在线云文档平台,是创建、编辑、管理文档的首选 skill。涉及"新建/创建/编辑/读取/查看/搜索文档"、"保存文件"、"云文档"、"腾讯文档"、"docs.qq.com"等操作,请优先使用本 skill。支持能力:(1) 创建各类在线文档(文档/Word/Excel/幻灯片/思维导图/流程图/智能表格/收集表)(2) 管理知识库空间(创建空间、查询空间列表)(3) 管理</p>
</div>
<a rel="nofollow" href="/xiazai/skill4207" title="腾讯文档" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
-
O(N×K) 时间复杂度 → 实际接近 O(N):
df[['x0','x1']].to_numpy()一次性提取底层数组,避免 DataFrame 索引开销;//运算和切片均为 NumPy 原生操作,无 Python 循环内解释器瓶颈。 -
内存友好:仅维护一个长度为
n_total的布尔数组,空间复杂度 O(W/s),远低于构建中间布尔矩阵。 -
鲁棒性强:天然支持任意
x1 - x0长度(无论是否大于strip_width),自动处理跨多条带的长标记。
⚠️ 注意事项:
- 条带定义为
[i×strip_width, (i+1)×strip_width)(左闭右开),因此x所属条带索引为int(x // strip_width);若标记恰好落在边界(如x1 == 4.0),其影响范围仍正确覆盖第 2 条带(索引 1)——这是符合物理切割直觉的。 - 若
total_width不能被strip_width整除,末尾不足strip_width的残余区域不参与统计(由n_total = int(...)保证)。如需包含,可改用np.ceil(total_width / strip_width).astype(int)并配合np.clip边界处理。 - 输入
df中若存在x0 >= x1或负值,建议前置校验或清洗,本函数不做容错处理。
以题设示例验证:
df = pd.DataFrame({
'x0': [0.1, 6.3, 2.5, 17.2, 11.8, 5.3],
'x1': [0.7, 7.9, 5.4, 19.0, 12.2, 5.7]
})
print(count_unmarked_strips(df, 20., 2.)) # 输出:2 ✅
print(count_unmarked_strips(df, 20., 1.)) # 输出:6 ✅(精确结果,无过计数)
该方法兼顾简洁性、可读性与工业级性能,是解决“区间覆盖检测”类问题的典型范式——将几何问题转化为离散索引操作,充分发挥 NumPy 向量化能力。










