模型训练通过pandas一次分组计算多个标签的KS

模型训练通过pandas一次分组计算多个标签的KS

  1. 模型训练通常是一堆特征X和一个标签y,但是模型经常需要再多个不同的y标签上去看效果,进行综合评估,如信贷领域中需要看在不同的mob的表现
  2. 下面会使用pandas计算多个y标签效果

准备数据

  1. 生成模拟数据

    python 复制代码
    import numpy as np
    import pandas as pd
    from sklearn import metrics
    
    np.random.seed(2025)
    def gen_data(labels=['y1', 'y2', 'y3'], nums=1000):
        data = dict(
            # 模拟分组月份
            month=np.random.choice(range(1, 6), nums),
            pred=np.random.rand(nums)
        )
        df = pd.DataFrame(data)
        for y in labels:
            df[y] = np.random.choice([0, 1, np.nan], nums)
        return df
    df=gen_data(nums=10)
    print(df)
    # 输出如下
    # 
    #    month      pred   y1   y2   y3
    # 0      3  0.964238  1.0  1.0  1.0
    # 1      5  0.800984  1.0  NaN  NaN
    # 2      1  0.455205  NaN  0.0  0.0
    # 3      4  0.801058  1.0  0.0  0.0
    # 4      4  0.041718  NaN  1.0  NaN
    # 5      5  0.769458  0.0  1.0  0.0
    # 6      1  0.003171  0.0  1.0  1.0
    # 7      1  0.292809  NaN  0.0  0.0
    # 8      3  0.610914  NaN  0.0  NaN
    # 9      2  0.913027  1.0  1.0  0.0
  2. 创建计算单列ks的函数,注意处理模型打分或者标签为空的情况

    python 复制代码
    # 计算单个标签的ks
    def calc_one_ks(y_true, y_pred):
        # 去掉标签为空的
        y_true = y_true.reset_index(drop=True)
        idx = y_true[y_true.notna()].index
        # 去掉打分为空的
        y_pred = pd.Series(y_pred).reset_index(drop=True)
        idx2 = y_pred[y_pred.notna()].index
        # 取模型打分和标签都不为空的
        idx_uni = list(set(idx) & set(idx2))
        y_true = y_true[idx_uni]
        y_pred = y_pred[idx_uni]
        if len(y_true) == 0:
            return None
        tpr, fpr, _ = metrics.roc_curve(y_true, y_pred)
        ks = max(abs(tpr - fpr))
        return ks
  3. 使用pandas的groupBy和apply分组计算多个标签的ks值,同时输出主标签的数量和正样本率

    python 复制代码
        def get_ks(s: pd.Series, labels, y_main=None, score='pred'):
            cnt = len(s)
            y_main = y_main or labels[0]
            pos_cnt = s[y_main].sum()
            pos_pct = round(pos_cnt / cnt, 4)
            res = dict(cnt=cnt, pos_cnt=pos_cnt, pos_pct=pos_pct)
            for y in labels:
                res[f'{y}_ks'] = calc_one_ks(s[y], s[score])
            return pd.Series(res)
        

完整代码

python 复制代码
import numpy as np
import pandas as pd
from sklearn import metrics

np.random.seed(2025)


def gen_data(labels=['y1', 'y2', 'y3'], nums=1000):
    data = dict(
        # 模拟分组月份
        month=np.random.choice(range(1, 6), nums),
        pred=np.random.rand(nums)
    )
    df = pd.DataFrame(data)
    for y in labels:
        df[y] = np.random.choice([0, 1, np.nan], nums)
    return df


# 计算单个标签的ks
def calc_one_ks(y_true, y_pred):
    # 去掉标签为空的
    y_true = y_true.reset_index(drop=True)
    idx = y_true[y_true.notna()].index
    # 去掉打分为空的
    y_pred = pd.Series(y_pred).reset_index(drop=True)
    idx2 = y_pred[y_pred.notna()].index
    # 取模型打分和标签都不为空的
    idx_uni = list(set(idx) & set(idx2))
    y_true = y_true[idx_uni]
    y_pred = y_pred[idx_uni]
    if len(y_true) == 0:
        return None
    tpr, fpr, _ = metrics.roc_curve(y_true, y_pred)
    ks = max(abs(tpr - fpr))
    return ks


def get_ks(s: pd.Series, labels, y_main=None, score='pred'):
    cnt = len(s)
    y_main = y_main or labels[0]
    pos_cnt = s[y_main].sum()
    pos_pct = round(pos_cnt / cnt, 4)
    res = dict(cnt=cnt, pos_cnt=pos_cnt, pos_pct=pos_pct)
    for y in labels:
        res[f'{y}_ks'] = calc_one_ks(s[y], s[score])
    return pd.Series(res)


if __name__ == '__main__':
    labels = ['y1', 'y2', 'y3']
    df = gen_data(labels)
    g_cols = ['month']
    df_res = df.groupby(g_cols).apply(lambda s: get_ks(s, labels))
    print(df_res)
# 输出
#          cnt  pos_cnt  pos_pct     y1_ks     y2_ks     y3_ks
# month                                                       
# 1      212.0     55.0   0.2594  0.206674  0.270109  0.101449
# 2      183.0     66.0   0.3607  0.138675  0.088418  0.135717
# 3      188.0     63.0   0.3351  0.139406  0.120635  0.125490
# 4      196.0     63.0   0.3214  0.104762  0.192693  0.148323
# 5      221.0     80.0   0.3620  0.120833  0.092691  0.073430

注意,使用pandas直接计算的方式仅适用于样本量较小的情况下,如果样本量较大可以使用sql或者spark进行计算,后续会再进行更新

相关推荐
2601_9623446212 小时前
计算机毕业设计之基于大数据的投保数据的分析系统的设计与实现
大数据·人工智能·深度学习·机器学习·信息可视化·小程序·课程设计
星马梦缘13 小时前
机器学习与模式识别 第八章 MAP与偏方差 模拟卷及答案
人工智能·机器学习·map·岭回归·mle·双重下降
JackHCC14 小时前
自进化智能体协同进化综述
人工智能·机器学习
星马梦缘14 小时前
机器学习与模式识别 第十二章 自适应学习优化器 考点压缩
人工智能·机器学习·优化器·sgd·adam·rmsprop
qcx2315 小时前
Agentic RAG不止能回答问题,已经能自动修复真实CVE漏洞了
人工智能·机器学习·ai·llm·脑信号
jaychouchannel15 小时前
RecursiveCharacterTextSplitter 中文切分隐形缺陷:重叠、断语义、列表割裂完整复现与修复
人工智能·机器学习
天佑木枫16 小时前
AI:AI 开车撞了人,谁赔钱?——自动驾驶的法律黑洞
人工智能·机器学习·自动驾驶
zhiSiBuYu051716 小时前
混合检索实战指南:关键词与向量的完美融合
人工智能·python·机器学习
2601_9623446217 小时前
计算机毕业设计之基于大数据的手机销售数据对比分析系统
大数据·人工智能·深度学习·机器学习·智能手机·数据挖掘·课程设计
烟锁池塘柳017 小时前
【机器学习】万字长文详解集成学习 Ensemble Learning:从 Bagging、Boosting 到 Stacking 的全解析
机器学习·集成学习·boosting