ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

imbalanced-learn 杂项工具全解:FunctionSampler 自定义采样器与 TensorFlow/Keras 均衡批生成器

imbalanced-learn 杂项工具全解:FunctionSampler 自定义采样器与 TensorFlow/Keras 均衡批生成器 机器学习特征工程数据增强【免费下载链接】imbalanced-learnA Python Package to Tackle the Curse of Imbalanced Datasets in Machine Learning项目地址https://gitcode.com/gh_mirrors/im/imbalanced-learn点击查看免费下载本篇技术指南围绕 imbalanced-learn 的 Miscellaneous杂项工具模块展开重点讲解两大快原型fast-prototyping能力用FunctionSampler通过单函数快速实现自定义采样器以及用 TensorFlow / Keras 的balanced_batch_generator与BalancedBatchGenerator在深度学习训练中产出类别均衡的 mini-batch。读完本文你将掌握自定义采样逻辑并将其无缝嵌入Pipeline的完整方法以及如何在 Keras/TensorFlow 训练循环中落地均衡采样。模块定位为非标准采样需求提供快速原型通道imbalanced-learn 的大多数采样器如RandomUnderSampler、SMOTE等都继承自 imblearn/base.py 中定义的SamplerMixin/BaseSampler体系拥有统一的fit/fit_resample接口与采样策略校验。但实际项目中常常存在无法由现成采样器覆盖的场景——例如需要保留前 N 条样本、按业务规则过滤样本、剔除离群点后再训练。为此doc/references/miscellaneous.rst 所对应的杂项模块提供了两个快速原型工具imblearn.FunctionSampler允许用户只定义一个函数即可构造一个完全符合 imbalanced-learn 采样器接口的自定义采样器TensorFlow / Keras 均衡批生成器在深度学习的 mini-batch 生成环节注入欠采样逻辑解决训练数据类别不平衡问题。这两个工具的共同特点是轻量接入——不需要重写基类、不需要理解内部采样策略算法即可获得与生态其余部分完全兼容的行为。FunctionSampler用单函数定义自己的采样器类签名与核心参数FunctionSampler定义于 imblearn/base.py继承自BaseSampler。其构造参数如下参数类型默认值说明funccallableNone采样的核心函数调用时接收与fit_resample相同的参数即X、y以及kw_args展开的关键字参数为None时使用恒等函数原样返回X, yaccept_sparseboolTrue是否接受稀疏矩阵输入默认为支持设为False时传入稀疏矩阵会抛出TypeErrordense data is requiredkw_argsdictNone传递给func的额外关键字参数字典validateboolTrue是否对X、y做输入校验设为False可绕过校验允许处理回归目标等任意类型y该参数自 0.6 版本加入见 doc/whats_new/v0.6.rst从源码实现看imblearn/base.py其_fit_resample的核心逻辑非常简洁def _fit_resample(self, X, y): func _identity if self.func is None else self.func output func(X, y, **(self.kw_args if self.kw_args else {})) return output即选择func缺省为_identity以(X, y)为位置参数、kw_args为关键字参数调用之返回值直接作为fit_resample的结果。这意味着你的函数只需返回(X_resampled, y_resampled)就完成了与其余采样器完全一致的接口契约。基础用法保留前 10 个元素FunctionSampler最直观的用法是定义一个接收X、y并返回重采样结果的函数。以下示例取自 doc/miscellaneous.rst 的 Custom samplers 一节完整展示了如何构造一个仅保留前 10 个样本的采样器 import numpy as np from imblearn import FunctionSampler from sklearn.datasets import make_classification X, y make_classification(n_samples5000, n_features2, n_informative2, ... n_redundant0, n_repeated0, n_classes3, ... n_clusters_per_class1, ... weights[0.01, 0.05, 0.94], ... class_sep0.8, random_state0) def func(X, y): ... return X[:10], y[:10] sampler FunctionSampler(funcfunc) X_res, y_res sampler.fit_resample(X, y) np.all(X_res X[:10]) True np.all(y_res y[:10]) True注意这里构造的是一个三分类且类别极不平衡的数据集weights[0.01, 0.05, 0.94]而FunctionSampler完全可以绕过类别比例约束执行任意自定义逻辑。通过 kw_args 向函数传递额外参数自定义函数并不局限于(X, y)两个参数。通过kw_args字典可以把sampling_strategy、random_state等参数注入你的函数从而复用现成采样器或者让函数行为可配置。示例如下该例同样出现在 imblearn/base.py 的 docstring 中 from collections import Counter from imblearn.under_sampling import RandomUnderSampler def func(X, y, sampling_strategy, random_state): ... return RandomUnderSampler( ... sampling_strategysampling_strategy, ... random_staterandom_state).fit_resample(X, y) sampler FunctionSampler(funcfunc, ... kw_args{sampling_strategy: auto, ... random_state: 0}) X_res, y_res sampler.fit_resample(X, y) print(fResampled dataset shape {sorted(Counter(y_res).items())}) Resampled dataset shape [(0, 100), (1, 100)]这一模式在 imblearn/tests/test_base.py 中有对应的测试用例test_function_sampler_func_kwargs它验证了通过kw_args注入参数的FunctionSampler与直接调用RandomUnderSampler(random_state0).fit_resample(X, y)的结果完全一致。validateFalse绕过校验以支持回归等任意目标默认情况下FunctionSampler遵循SamplerMixin.fit_resample的流程会调用check_classification_targets(y)校验目标为分类标签并经由_check_X_y检查输入。这限制了采样器的适用范围。而将validate置为False时见 imblearn/base.pyfit_resample会跳过check_classification_targets与_check_X_y将原始X、y直接传给func从而允许对连续值回归目标做任意采样 from sklearn.datasets import make_regression X_reg, y_reg make_regression(n_samples100, random_state42) rng np.random.RandomState(42) def dummy_sampler(X, y): ... indices rng.choice(np.arange(X.shape[0]), size10) ... return X[indices], y[indices] sampler FunctionSampler(funcdummy_sampler, validateFalse) X_res, y_res sampler.fit_resample(X_reg, y_reg) y_res array([ 41.49112498, -142.78526195, 85.55095317, 141.43321419, 75.46571114, -67.49177372, 159.72700509, -169.80498923, 211.95889757, 211.95889757])如上例所示y_res是连续的回归目标值而非类别标签。这一特性在 imblearn/tests/test_base.py 的test_function_sampler_validate中得到验证测试将FunctionSampler(funcdummy_sampler, validateFalse)与LinearRegression组合成 pipeline确认预测目标是连续型。此外validateFalse还可以让fit阶段容忍包含NaN/inf的非有限值数据见 imblearn/tests/test_base.py 中的非回归测试。实战场景用 FunctionSampler 实现离群点剔除并嵌入 PipelineFunctionSampler一个标志性应用是构造离群点剔除outlier rejection估计器并接入Pipeline参与训练。完整可运行示例位于 examples/applications/plot_outlier_rejections.py核心思路如下def outlier_rejection(X, y): This will be our function used to resample our dataset. model IsolationForest(max_samples100, contamination0.4, random_staterng) model.fit(X) y_pred model.predict(X) return X[y_pred 1], y[y_pred 1] reject_sampler FunctionSampler(funcoutlier_rejection) X_inliers, y_inliers reject_sampler.fit_resample(X_train, y_train)由于FunctionSampler的函数在训练时可能改变样本数量本例中剔除离群点后样本数减少而 scikit-learn 原生 pipeline 通常要求各阶段样本数一致imblearn.pipeline恰好支持这种样本数可变的流式管道。因此可以这样组合from imblearn.pipeline import make_pipeline pipe make_pipeline( FunctionSampler(funcoutlier_rejection), LogisticRegression(random_staterng), ) y_pred pipe.fit(X_train, y_train).predict(X_test)先由IsolationForest剔除离群点再交给LogisticRegression训练可显著降低噪声样本对分类决策边界的影响。这也是官方文档明确推荐的用法见 doc/miscellaneous.rst。TensorFlow 均衡批生成器balanced_batch_generator工作机制与关键参数对于深度学习训练imbalanced-learn 提供了针对 TensorFlow 的imblearn.tensorflow.balanced_batch_generator自 0.4 版本引入实现位于 imblearn/tensorflow/_generator.py。该函数的核心原理是用传入的采样器默认RandomUnderSampler对数据执行fit_resample要求采样器暴露sample_indices_属性取出被保留样本的索引打乱索引后按batch_size切片用_safe_indexing生成均衡的 mini-batch。其关键参数如下参数默认值说明X必填原始不平衡数据集shape(n_samples, n_features)y必填目标数组shape(n_samples,)或(n_samples, n_classes)one-hotsample_weightNone样本权重数组非None时每个 batch 额外产出权重samplerNone拥有sample_indices_属性的采样器实例缺省为RandomUnderSamplerbatch_size32每个梯度更新使用的样本数keep_sparseFalse是否保留X的稀疏性默认将稀疏 batch 转为稠密数组random_stateNone控制索引打乱与采样随机性返回值是(generator, steps_per_epoch)二元组前者是无限迭代的生成器每次产出(X_batch, y_batch)若传入sample_weight则产出(X_batch, y_batch, sw_batch)后者是每个 epoch 需要的批次数即indices.size // batch_size见 imblearn/tensorflow/_generator.py。需要特别强调的是传入的sampler必须具有sample_indices_属性否则会抛出ValueError: sampler needs to have an attribute sample_indices_.。因此并非所有 imbalanced-learn 采样器都可用——只有能返回保留索引的采样器如RandomUnderSampler、NearMiss才满足要求。端到端示例训练一个逻辑回归模型以下完整示例取自 doc/miscellaneous.rst 的 TensorFlow generator 一节演示从数据生成到模型训练的完整流程。第一步生成不平衡数据并转为 float32 n_features, n_classes 10, 2 X, y make_classification( ... n_samples10_000, n_featuresn_features, n_informative2, ... n_redundant0, n_repeated0, n_classesn_classes, ... n_clusters_per_class1, weights[0.1, 0.9], ... class_sep0.8, random_state0 ... ) X X.astype(np.float32)第二步创建均衡批生成器 from imblearn.under_sampling import RandomUnderSampler from imblearn.tensorflow import balanced_batch_generator training_generator, steps_per_epoch balanced_batch_generator( ... X, ... y, ... sample_weightNone, ... samplerRandomUnderSampler(), ... batch_size32, ... random_state42, ... )第三步定义模型、损失与优化步骤 import tensorflow as tf # initialize the weights and intercept normal_initializer tf.random_normal_initializer(mean0, stddev0.01) coef tf.Variable(normal_initializer( ... shape[n_features, n_classes]), dtypefloat32 ... ) intercept tf.Variable( ... normal_initializer(shape[n_classes]), dtypefloat32 ... ) # define the model def logistic_regression(X): ... return tf.nn.softmax(tf.matmul(X, coef) intercept) # define the loss function def cross_entropy(y_true, y_pred): ... y_true tf.one_hot(y_true, depthn_classes) ... y_pred tf.clip_by_value(y_pred, 1e-9, 1.) ... return tf.reduce_mean(-tf.reduce_sum(y_true * tf.math.log(y_pred))) # define our metric def balanced_accuracy(y_true, y_pred): ... cm tf.math.confusion_matrix(tf.cast(y_true, tf.int64), tf.argmax(y_pred, 1)) ... per_class np.diag(cm) / tf.math.reduce_sum(cm, axis1) ... return np.mean(per_class) # define the optimizer optimizer tf.optimizers.SGD(learning_rate0.01) # define the optimization step def run_optimization(X, y): ... with tf.GradientTape() as g: ... y_pred logistic_regression(X) ... loss cross_entropy(y, y_pred) ... gradients g.gradient(loss, [coef, intercept]) ... optimizer.apply_gradients(zip(gradients, [coef, intercept]))第四步训练循环——逐 epoch 迭代均衡 mini-batch epochs 10 for e in range(epochs): ... y_pred logistic_regression(X) ... loss cross_entropy(y, y_pred) ... bal_acc balanced_accuracy(y, y_pred) ... print(fepoch: {e}, loss: {loss:.3f}, accuracy: {bal_acc}) ... for i in range(steps_per_epoch): ... X_batch, y_batch next(training_generator) ... run_optimization(X_batch, y_batch) epoch: 0, ...每个 epoch 内通过next(training_generator)逐批取出均衡数据并执行梯度下降从而在不改变原始数据集的前提下缓解类别不平衡对梯度估计的偏置。Keras 均衡批生成函数式与类式两种用法Keras 提供了更高层的 API模型通过fit/fit_generator即可完成训练。imbalanced-learn 在imblearn.keras中提供了两种均衡批生成方式实现见 imblearn/keras/_generator.py底层均复用 TensorFlow 的生成逻辑imblearn.keras.balanced_batch_generator直接转发给imblearn.tensorflow.balanced_batch_generator见 imblearn/keras/_generator.py。准备模型与 one-hot 目标 from tensorflow import keras y keras.utils.to_categorical(y, 3) model keras.Sequential() model.add( ... keras.layers.Dense( ... y.shape[1], input_dimX.shape[1], activationsoftmax ... ) ... ) model.compile( ... optimizersgd, losscategorical_crossentropy, metrics[accuracy] ... )方式一keras.balanced_batch_generator fitimblearn.keras.balanced_batch_generator与 TensorFlow 版本接口一致返回(generator, steps_per_epoch)配合model.fit的steps_per_epoch参数使用 from imblearn.keras import balanced_batch_generator training_generator, steps_per_epoch balanced_batch_generator( ... X, y, samplerRandomUnderSampler(), batch_size10, random_state42 ... ) callback_history model.fit( ... training_generator, ... steps_per_epochsteps_per_epoch, ... epochs10, ... verbose1, ... ) Epoch 1/10 ...方式二BalancedBatchGenerator 类 fitimblearn.keras.BalancedBatchGenerator是一个实现了 KerasSequence新版可能为PyDataset见 imblearn/keras/_generator.py 中对 keras 与 tensorflow 两套导入路径的兼容处理的类只需将其实例直接传给fit无需手动维护步数 from imblearn.keras import BalancedBatchGenerator training_generator BalancedBatchGenerator( ... X, y, samplerRandomUnderSampler(), batch_size10, random_state42 ... ) callback_history model.fit( ... training_generator, ... steps_per_epochsteps_per_epoch, ... epochs10, ... verbose1, ... ) Epoch 1/10 ...从源码看BalancedBatchGenerator在_sample()阶段imblearn/keras/_generator.py完成采样并保存sampler_与打乱后的indices___len__返回批次数__getitem__按index * batch_size切片并用_safe_indexing取数同时支持sample_weight的三元组产出与keep_sparse控制imblearn/keras/_generator.py。此外该类在 imblearn/keras/_generator.py 的 docstring 中演示了使用NearMiss作为采样器的替代方案。从设计到落地源码证据与适用边界总结与基类体系的兼容性FunctionSampler继承自BaseSamplerimblearn/base.py因此天然具备sampling_strategy属性与_estimator_type sampler标签可以被imblearn.pipeline、make_pipeline以及 imblearn/utils/_validation.py 中的校验逻辑正常识别和组合。其_sampling_type bypassimblearn/base.py表明它不参与采样策略计数仅透传自定义逻辑。关键约束与注意事项采样器必须暴露sample_indices_TensorFlow / Keras 两类生成器都依赖该属性选取被保留样本的索引见 imblearn/tensorflow/_generator.py 与 imblearn/keras/_generator.py否则直接抛错validateFalse是有意的逃生门它会跳过check_classification_targets与_check_X_y适合回归目标、非有限值输入等非常规数据但同时也意味着放弃输入合法性保障稀疏输入默认被支持FunctionSampler默认accept_sparseTrue测试覆盖了csr_matrix/csc_matrix两种稀疏格式见 imblearn/tests/test_base.py生成器则默认将稀疏 batch 转为稠密数组keep_sparseFalse。官方参考示例离群点剔除 Pipeline 完整实现examples/applications/plot_outlier_rejections.pyKeras 欠采样 梯度下降的端到端示例Porto Seguro 数据集examples/applications/porto_seguro_keras_under_sampling.py见 doc/miscellaneous.rst 的 References 一节FunctionSampler的接口测试imblearn/tests/test_base.py结语FunctionSampler与两类均衡批生成器共同构成了 imbalanced-learn 的杂项工具箱前者以极低的接入成本让任意自定义逻辑获得标准采样器接口从而无缝嵌入Pipeline后者把欠采样思想延伸到深度学习训练的数据供给层确保每个 mini-batch 都类别均衡。无论是处理离群点、实现回归数据的降采样还是在 Keras/TensorFlow 中训练不平衡数据模型这两个工具都能显著加速原型验证与落地部署。赞分享机器学习特征工程数据增强【免费下载链接】imbalanced-learnA Python Package to Tackle the Curse of Imbalanced Datasets in Machine Learning项目地址https://gitcode.com/gh_mirrors/im/imbalanced-learn点击查看免费下载相关推荐imbalanced-learn欠采样技术全解析imbalanced learn欠采样技术全解析 本文全面解析了imbalanced learn库中的多种欠采样技术包括随机欠采样 RandomUnderSa机器学习特征工程数据增强n8n企业级功能详解团队协作与权限管理n8n企业级功能详解团队协作与权限管理 n8n作为一款功能强大的自动化工具不仅提供了丰富的工作流设计能力还内置了完善的企业级团队协作与权限管理功能。本文将上一篇7个PowerInfer本地AI推理技巧加速建筑设计方案生成与空间规划下一篇Laravel ImageUp性能优化技巧图片压缩、缓存与存储最佳实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进