hscredit.core.selectors.mode_selector 源代码

"""单一值筛选器.

移除单一值(众数)占比过高的特征。

**参考样例**

>>> from hscredit.core.selectors import ModeSelector
>>> import pandas as pd
>>> X = pd.DataFrame({
...     'a': [1, 1, 1, 1, 2],    # 众数(1)占比80%
...     'b': [1, 2, 3, 4, 5],    # 众数(1)占比20%
...     'c': [1, 1, 1, 1, 1]     # 常量特征,众数占比100%
... })
>>> selector = ModeSelector(threshold=0.8)  # 移除众数占比>80%的特征
>>> selector.fit(X)
>>> print(selector.selected_features_)
['a', 'b']
"""

from typing import Union, List, Optional, Dict, Any
import numpy as np
import pandas as pd

from .base import BaseFeatureSelector


def _compute_mode_ratio(series: pd.Series, dropna: bool = True) -> float:
    """计算众数占比。

    :param series: 输入序列
    :param dropna: 是否排除缺失值
    :return: 众数占比
    """
    if len(series) == 0:
        return 1.0

    summary = series.value_counts(dropna=dropna)
    if len(summary) == 0:
        return 1.0

    denominator = int(series.notna().sum()) if dropna else len(series)
    if denominator == 0:
        return 1.0
    return summary.iloc[0] / denominator


def _compute_mode_feature(task):
    """计算单列众数占比并携带特征名返回。"""
    feature, series, dropna = task
    return feature, _compute_mode_ratio(series, dropna)


[文档] class ModeSelector(BaseFeatureSelector): """单一值筛选器. 移除众数占比高于阈值的特征。 用于过滤掉取值过于集中、区分度低的特征。 **参数** :param threshold: 单一值占比阈值,默认为0.95 - 0.95: 移除单一值占比超过95%的特征 - 范围: 0-1之间的浮点数 :param dropna: 是否在计算众数占比时排除NaN,默认为True :param n_jobs: 并行计算的任务数 **参考样例** :: >>> from hscredit.core.selectors import ModeSelector >>> import pandas as pd >>> X = pd.DataFrame({ ... 'a': [1, 1, 1, 1, 2], ... 'b': [1, 2, 3, 4, 5], ... 'c': [1, 1, 1, 1, 1] ... }) >>> selector = ModeSelector(threshold=0.8) >>> selector.fit(X) >>> print(selector.selected_features_) ['a', 'b'] """ method_name = "单一值筛选" def __init__( self, threshold: float = 0.95, dropna: bool = True, target: str = "target", include: Optional[List[str]] = None, exclude: Optional[List[str]] = None, force_drop: Optional[List[str]] = None, n_jobs: Optional[Union[int, float]] = -1, binner: Optional[Any] = None, binning_params: Optional[Dict[str, Any]] = None, parallel_backend: Optional[str] = None, parallel_config: Optional[Dict[str, Any]] = None, ): super().__init__( target=target, threshold=threshold, include=include, exclude=exclude, force_drop=force_drop, n_jobs=n_jobs, binner=binner, binning_params=binning_params, parallel_backend=parallel_backend, parallel_config=parallel_config, ) self.dropna = dropna def _fit_impl( self, X: pd.DataFrame, y: Optional[Union[pd.Series, np.ndarray]], ) -> None: """拟合单一值筛选器。 :param X: 输入特征DataFrame :param y: 目标变量(此筛选器不需要) """ self._get_feature_names(X) self._validate_parallel_configuration() mode_ratios = X.apply(_compute_mode_ratio, dropna=self.dropna).reindex(X.columns) self.scores_ = mode_ratios # 选择众数占比低于阈值的特征 selected_mask = mode_ratios < self.threshold self.selected_features_ = X.columns[selected_mask].tolist() self._drop_reason = f"单一值占比 >= {self.threshold:.2%}"