拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Data-Juicer 字符级 n-gram 重复率过滤算子 character_repetition_filter 深入解析与实战

Data-Juicer 字符级 n-gram 重复率过滤算子 character_repetition_filter 深入解析与实战
  • 人工智能
  • 大模型
  • 数据工程
  • 数据清洗
  • 数据增强
  • 数据质检

【免费下载链接】data-juicer

Data processing for and with foundation models! 🍎 🍋 🌽 ➡️ ➡️🍸 🍹 🍷

项目地址:https://gitcode.com/gh_mirrors/da/data-juicer
点击查看免费下载

导读

character_repetition_filter是 Data-Juicer 中用于文本质量清洗的核心 filter 算子之一:它按字符级 n-gram 统计每个样本的重复率,并只保留重复率落在指定区间内的样本,从而批量剔除「重复轰炸」(如连续复读同一片段)的低质文本。读完本文,你将掌握该算子的数学定义与源码级实现原理、rep_len/min_ratio/max_ratio三个核心参数的调参方法、在 YAML recipe 与 Python API 两种使用方式下的完整配置示例,以及它与word_repetition_filter的选型差异。

算子概览:定位与适用场景

在 Data-Juicer 的算子体系中,character_repetition_filter属于filter(过滤)类型,算子注册名为character_repetition_filter,标签为cpu, text,即纯 CPU 文本算子,不依赖任何模型与 GPU。官方文档 character_repetition_filter.md 对其核心职责的表述是:计算每个样本的字符级 n-gram 重复率(character-level n-gram repetition ratio),并过滤掉不在指定范围内的样本;关键指标char_rep_ratio会被缓存进样本的stats字段。

该算子最常见的应用场景:

  • 剔除模型训练语料中的复读、口水话、重复拼接的文本;
  • 在清洗流程中与其他文本质量过滤器(如alphanumeric_filter、word_repetition_filter、perplexity_filter)组合,构成多层次的文本质检链路。

从源码看,本算子的算法实现参考了 HuggingFace 的 text-data-filtering 头注释),属于业界常用的重复率清洗方法在 Data-Juicer 中的工程化落地。

参数配置:三个核心参数与扩展参数

算子参数在 character_repetition_filter.md 的「Parameter Configuration」一节有完整表格,结合源码 character_repetition_filter.py 的构造函数可一一对应:

参数名类型默认值含义
rep_lenint(要求 > 0,即PositiveInt/Gt(gt=0))10字符级 n-gram 的窗口长度 n,即每个待统计的 n-gram 包含的字符数
min_ratiofloat0.0重复率下限,样本char_rep_ratio低于此值则被过滤
max_ratiofloat0.5重复率上限,样本char_rep_ratio超过此值则被过滤
args/kwargs-''透传给基类Filter/OP的扩展参数(如batch_size、text_key、num_proc等)

需要说明的是,args/kwargs实际接收的是 Data-Juicer 算子基类 base_op.py 中定义的全部通用参数,主要包括:

  • 数据键:text_key(默认"text",指定待处理的文本字段)、image_key、video_key等;
  • 执行策略:batch_size(默认 1000)、num_proc(默认 -1,自动计算并发度)、skip_op_error(默认 False,是否跳过单样本异常)、auto_op_parallelism;
  • Ray 相关:num_cpus、num_gpus、memory、runtime_env等。

另外,所有 filter 算子还继承了基类的三个过滤语义参数(见 base_op.py):

  • min_closed_interval(默认 True):下限是否为闭区间(>= min_ratio而非> min_ratio);
  • max_closed_interval(默认 True):上限是否为闭区间(<= max_ratio而非< max_ratio);
  • reversed_range(默认 False):是否反转过滤区间,即只保留落在区间之外(< min_ratio或> max_ratio)的样本。

参数取值的实战建议

  • rep_len控制重复检测的"粒度":窗口越大,只有足够长的连续重复片段才会被记为重复,误伤率越低;窗口过小(如 2~3)会把正常文本中偶然出现的短字符串重复也计入重复率,导致误过滤。默认值 10 是兼顾灵敏度与准确率的经验取值。
  • max_ratio是调节严格程度的关键旋钮:默认 0.5 意味着重复 n-gram 频次贡献占总 n-gram 频次一半以上的样本会被剔除;调低更严格、调高更宽松。对于聊天记录、对话类数据建议放宽,对于网页抓取、OCR 文本建议收紧。

核心原理:重复率char_rep_ratio的精确计算方式

重复率指标char_rep_ratio的名字定义在 constant.py 的StatsKeysConstant中,与word_rep_ratio(词级重复率)等指标并列。它的完整计算过程实现在 character_repetition_filter.py 的compute_stats_batched方法中,分为四步:

第 1 步:统计所有字符 n-gram 的频次。对文本cur_text,以self.n(即rep_len)为窗口做滑窗:

freq_char_ngrams = {} for i in range(len(cur_text) - self.n + 1): char_ngram = cur_text[i : i + self.n] freq_char_ngrams[char_ngram] = freq_char_ngrams.get(char_ngram, 0) + 1

这里中英文一视同仁:文档效果演示中明确指出「中文也是一个字算一个长度」,即一个汉字算一个字符、参与滑窗统计。

第 2 步:处理过短文本。若文本长度小于 n,滑窗一个 n-gram 都产生不了,freq_char_ngrams为空,此时重复率直接记为0.0(不会被误判为重复)。

第 3 步:确定「重复 n-gram」的集合。将频次降序排列后:

num_no_rep_char_ngrams = freq_char_ngrams.count(1) # 只出现 1 次的 n-gram 数量 num_rep_char_ngrams = min( int(np.sqrt(len(freq_char_ngrams))), # 取 n-gram 种类数的平方根 len(freq_char_ngrams) - num_no_rep_char_ngrams, # 且不超过“出现不止一次”的种类数 )

重复 n-gram 被定义为:频次降序排列后,取前sqrt(种类数)个(且这些 n-gram 必须出现超过 1 次)。这一设计借鉴了长尾分布假设——正常情况下绝大多数 n-gram 只出现一次,只有真正重复的 n-gram 才会高频出现,用平方根截断可以避免把低频正常片段也算进重复集合。

第 4 步:计算重复率。重复 n-gram 的频次之和占总频次(即文本中所有 n-gram 的出现总次数)的比例:

total = sum(freq_char_ngrams) char_rep_ratio = sum(freq_char_ngrams[:num_rep_char_ngrams]) / total if total != 0 else 0.0

因此char_rep_ratio的取值范围是[0.0, 1.0]:完全没有重复的文本为 0.0,全文只有单一字符反复出现的极端文本接近 1.0。这一点被单元测试 test_character_repetition_filter.py 直接验证:25 个a组成的文本重复率> 0.9,26 个互不重复字母组成的文本重复率恰为0.0。

缓存与复用机制

compute_stats_batched开头会检查该样本的stats字段中是否已有char_rep_ratio:若已存在则直接跳过重算(character_repetition_filter.py)。这意味着:

  • 同一算子重复执行不会覆盖已算好的统计值(测试 test_compute_stats_batched_skips_existing 验证了预计算的0.42会被原样保留);
  • 该指标可以被其他算子或分析模块复用,例如 Data-Juicer 的统计分析工具会读取StatsKeys.char_rep_ratio展示重复率分布(参见 app.py 中该指标与可视化效果的绑定)。

过滤判定:区间比较与基类语义

统计完成后,过滤判定由process_batched完成(character_repetition_filter.py):

return map( lambda stat: self.get_keep_boolean(stat[StatsKeys.char_rep_ratio], self.min_ratio, self.max_ratio), samples[Fields.stats], )

get_keep_boolean定义在基类 base_op.py,它完整实现了前面提到的区间语义:

  • 默认(闭区间)下,保留条件为min_ratio <= ratio <= max_ratio;
  • 若设置min_closed_interval=False,下限变为开区间(> min_ratio);
  • 若设置max_closed_interval=False,上限变为开区间(< max_ratio);
  • 若设置reversed_range=True,上述比较结果整体取反,即只保留不在区间内的样本。

注意本算子_batched_op = True(character_repetition_filter.py),因此实际执行走的是批处理路径:compute_stats_batched一次处理一个 batch 的所有样本,process_batched返回一组布尔标志。整个算子在执行器中的调用链为:Filter.run→ 先dataset.map(compute_stats)缓存统计值 → 再dataset.filter(process)剔除样本(见 base_op.py),两个阶段都支持num_proc多进程并行。此外,Data-Juicer 的 tracer 机制会在过滤阶段记录被剔除的样本,用于后续的数据质量审计(见 base_op.py 的wrap_filter_with_tracer)。

效果演示:官方示例的逐步拆解

官方文档 character_repetition_filter.md 给出的效果演示采用如下配置:

CharacterRepetitionFilter(rep_len=5, min_ratio=0.0, max_ratio=0.4, batch_size=2)

即统计 5-gram 重复率,只保留重复率落在[0.0, 0.4]的样本。四组输入样本与过滤结果为:

输入样本结果
Today is Sund Sund Sund Sund Sund Sunda and it's a happy day!❌ 剔除(5-gram 重复率 > 0.4)
a v s e c s f e f g a a a a a a a a a a❌ 剔除(大量重复的a,5-gram 重复率 > 0.4)
,。、„”“«»1」「《》´∶:?!();–—.~’…━〈〉【】%►✅ 保留
中文也是一个字算一个长度✅ 保留

其中第 3 条样本虽然全是标点符号,但互不重复,因此重复率为 0,落在区间内被保留;第 4 条中文样本验证了「一个汉字算一个字符」的统计口径。

该示例与单元测试 test_case 完全一致,测试通过NestedDataset构造数据集、先map(op.compute_stats)再filter(op.process)复现了完整过滤流程,可作为自行验证算子的最小可运行样例。

实战配置:在 Data-Juicer recipe 中接入该算子

Data-Juicer 推荐通过 YAML recipe 声明式地组织处理流程。在 recipe 中,character_repetition_filter作为process列表的一员出现。官方配置模板 config_all.yaml 中的默认写法为:

process: - character_repetition_filter: # filter text with the character repetition ratio out of specific range rep_len: 10 # repetition length for char-level n-gram min_ratio: 0.0 # the min ratio of filter range max_ratio: 0.5 # the max ratio of filter range

实际 demo 配置 demo.yaml 也采用了完全相同的默认参数组合,并且把它放在alphanumeric_filter、average_line_length_filter之后、flagged_words_filter、language_id_score_filter之前,可见它通常作为通用文本质量过滤链路的中段环节。完整的 recipe 运行方式如下:

# 命令行运行(先安装>project_name: 'demo' dataset_path: './demos/data/demo-dataset.jsonl' # 输入数据集 np: 4 # 子进程数 export_path: './outputs/demo/demo-processed.jsonl' process: - character_repetition_filter: # 字符级重复率过滤 rep_len: 10 min_ratio: 0.0 max_ratio: 0.5

如果你希望更严格地剔除复读文本,可以把max_ratio调到0.3并适当缩小rep_len(如 6);反之,如果只是轻量清洗,保持默认即可。值得注意的是,Data-Juicer 支持对 filter 类算子做算子融合优化:word_repetition_filter注册了INTER_WORDS中间变量用于词切分复用(见 word_repetition_filter.py),因此将字符级与词级重复率过滤串联使用时,Data-Juicer 会尽量复用中间计算结果以提升吞吐。

与 word_repetition_filter 的选型对比

Data-Juicer 同时提供字符级(本算子)与词级(word_repetition_filter)两种重复率过滤器,二者共享相同的参数结构(rep_len/min_ratio/max_ratio,默认值均为 10 / 0.0 / 0.5),但在统计单元与实现上有本质区别:

维度character_repetition_filterword_repetition_filter
统计单元连续字符组成的 n-gram词(word)组成的 n-gram
是否需要分词否,直接滑窗是,默认按空白分词,tokenization=True时使用 sentencepiece 模型(需指定lang)
预处理无小写化、去特殊字符(words_refinement)
典型捕获目标字符级复读、aaaaa...式无意义填充词语级复读、重复的短语/句子模式

选择建议:处理字母堆积、乱码填充、标点轰炸类问题选字符级;处理整句整段复读类问题,词级往往语义更直观。两者都继承Filter基类,也都缓存各自的统计指标(char_rep_ratio/word_rep_ratio),可放心在同一 recipe 中组合使用。

测试与验证:如何确认算子行为

该算子的行为在仓库中有系统化的单元测试覆盖,文件为 test_character_repetition_filter.py,除官方效果演示对应的test_case外,还包含:

  • test_existing_stats:已缓存char_rep_ratio的样本不会被重算;
  • test_compute_stats_batched_directly:高度重复文本重复率 > 0.9、完全无重复文本重复率 = 0.0;
  • test_process_batched_directly:0.9 / 0.2 / 0.0三个比值在[0.0, 0.4]区间下分别得到False / True / True的保留标志;
  • test_compute_stats_batched_short_text:短于rep_len的文本(含空串)重复率恒为 0.0;
  • test_compute_stats_batched_mixed_repetition:中等重复文本重复率 > 0,无重复文本重复率为 0。

运行测试验证行为:

python -m pytest tests/ops/filter/test_character_repetition_filter.py -v

若想在自有数据上观察该算子的实际统计值,可先运行compute_stats阶段并把stats_export_path指向输出文件(该参数由Filter基类提供,见 base_op.py),导出的统计文件会包含每条样本的char_rep_ratio,方便你据此调整min_ratio/max_ratio阈值。

小结

character_repetition_filter是 Data-Juicer 文本质量过滤家族中一个实现精简、语义清晰的基础算子:通过「字符 n-gram 频次统计 + 平方根截断确定重复集合」的方式得到char_rep_ratio指标,再以区间比较完成过滤。它的工程化亮点包括批处理执行、统计值缓存复用、多进程并行、tracer 审计以及与词级过滤器的中间结果复用。对于任何需要控制语料文本重复度、提升数据信噪比的清洗 pipeline,它都是一块高性价比的基石组件。

延伸阅读:算子全览见 Operators.md;与词级版本对比见 word_repetition_filter.py;过滤算子的通用区间语义(开闭区间、反转区间)见基类 base_op.py;官方默认 recipe 配置见 config_all.yaml。

  • 人工智能
  • 大模型
  • 数据工程
  • 数据清洗
  • 数据增强
  • 数据质检

【免费下载链接】data-juicer

Data processing for and with foundation models! 🍎 🍋 🌽 ➡️ ➡️🍸 🍹 🍷

项目地址:https://gitcode.com/gh_mirrors/da/data-juicer
点击查看免费下载

相关推荐

上一篇:Backstage Root Lifecycle Service:后端启动与关闭钩子机制的原理及自定义实现
下一篇:freeCodeCamp Python 每日挑战实战:S P A C E J A M 字符串空格变换(Challenge 4)详解

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表