风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法

这篇具有很好参考价值的文章主要介绍了风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview


引用AI对于风控系统的介绍

风控系统是一种用于在线业务的安全管理系统,它帮助企业和平台防范潜在的欺诈、信用风险以及不合规行为。简单来说,它的核心作用就是“保安全、防欺诈、控风险”。

最近也一直在研究风控系统体系、功能等,看了一些有关的文章,并且也在实践尝试中。

其实前一篇可配置“输入参数的接口如何设计”就是实践尝试的一部分,未来还会有更多的。

而本篇文章就风控系统的指标计算,或者说是特征提取做一些探讨,以下统一称呼为“指标”。

指标不仅可以作为风控系统的一部分配合风控规则或是模型/机器学习使用,而且可以用于离线分析、事后追查、用户画像标签等方面。

参考文章

风控笔记06:一个完整的风控引擎,需要有哪些功能?

风控笔记07:最常用的风控工具-特征库

指标分类

指标是由数据流支撑的,指标是时间纬度的数据提取计算。

根据指标分类举几个例子:

  • 次数统计:最近24小时 客户号向 {客户号}向 客户号{银行卡卡号}转账笔数
  • 求和:最近2天 客户号向 {客户号}向 客户号{银行卡卡号}转账金额之和
  • 平均:最近1个月 客户号向 {客户号}向 客户号{银行卡卡号}转账金额的平均数
  • 关联次数:最近72小时 客户号关联 {客户号}关联 客户号关联{设备mac地址}的次数
  • 等等

风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法,redis,数据库,缓存

指标类型枚举

/**
 * @author wnhyang
 * @date 2024/3/13
 **/
@AllArgsConstructor
@Getter
public enum IndicatorType {
    COUNT(0, "count", "次数统计"),
    SUM(1, "sum", "求和"),
    AVG(2, "avg", "平均"),
    MAX(3, "max", "最大值"),
    MIN(4, "min", "最小值"),
    ASS(5, "ass", "关联次数");

    private final Integer code;

    private final String name;

    private final String desc;
}

指标实体类

目前filterScript条件还未确实如何做,使用Groovy脚本还是什么,之后再定吧。

/**
 * @author wnhyang
 * @date 2024/3/13
 **/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("de_indicator")
public class IndicatorPO extends BasePO {

    @Serial
    private static final long serialVersionUID = 1L;

    /**
     * 自增编号
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 指标名
     */
    @TableField("name")
    private String name;

    /**
     * 状态
     */
    @TableField("status")
    private Boolean status;

    /**
     * 类型
     */
    @TableField("type")
    private Integer type;

    /**
     * 计算字段
     */
    @TableField("calc_field")
    private String calcField;

    /**
     * 窗口大小
     */
    @TableField("win_size")
    private String winSize;

    /**
     * 窗口类型
     */
    @TableField("win_type")
    private String winType;

    /**
     * 窗口数量
     */
    @TableField("win_count")
    private Integer winCount;

    /**
     * 时间片
     */
    @TableField("time_slice")
    private Long timeSlice;

    /**
     * 主字段
     */
    @TableField("master_field")
    private String masterField;

    /**
     * 从字段
     */
    @TableField("slave_fields")
    private String slaveFields;

    /**
     * 过滤脚本
     */
    @TableField("filter_script")
    private String filterScript;

    /**
     * 版本号
     */
    @TableField("version")
    private Integer version;

    /**
     * 描述
     */
    @TableField("description")
    private String description;
}

指标窗口枚举

/**
 * @author wnhyang
 * @date 2024/3/13
 **/
@AllArgsConstructor
@Getter
public enum WinType {

    LAST(0, "last", "最近"),
    CUR(1, "cur", "本");

    private final Integer code;

    private final String name;

    private final String desc;
}

指标存储

指标数据如何存储呢?下面是Redis方案。

1、使用Redis的有序集合(Sorted Set)结构,有序集合中的每个元素都有一个分数(score),这里的分数我们可以设置为时间戳。

2、添加数据:每当有新的请求到来时,将当前时间戳作为score,用一个固定的字符串(如"request")或者其他唯一标识符作为member,插入到有序集合中。

3、清理过期数据:每次添加新数据后,通过ZRANGEBYSCORE命令获取并删除窗口范围之外的数据。

4、统计指标:要得到窗口内的请求次数,可以直接使用ZCARD命令获取有序集合中元素的数量。

5、定时任务:为了确保过期数据能够自动清除,可以结合RedisKey空间通知机制(Keyspace Notifications)或者外部定时任务定期执行上述清理操作。

计算类指标

计算类指标比较通用,需要存储的数据很容易分析。

但还是有些差别的,次数统计可以在zset中存储value为${事件id},score为时间戳,计算时为zsetsize,但是对于平均、最大值、最小值、求和不能这么做,因为这些都是有计算字段的,并不是如次数统计那样取size就行,所以对于这类指标数据存储是不一样的。

zsetzset+hash两种方案。

单zset

zset作为时间窗口,value为${事件id}+{计算字段},score为时间戳,变化就是value变为事件id与计算字段的组合,计算字段这样就存储下来了,之后计算平均、最大值、最小值、求和取出来再算就可以了,事件id是为了在zset中存储时防重,另外也方便找到原始数据。

优点:直接从zset中获取计算字段,可以独立手动过期删除。

缺点:value存和取需要设计,数据冗余大。

zset+hash

zset作为时间窗口,value为${事件id},score为时间戳,这里没有变化,另外需要hash存储对应事件下需要计算字段的数据。

优点:hash可以存储多项数据,数据冗余少。

缺点:无法确定事件过期删除时间,每次需要多步查询。

指标计算与查询

指标计算可以简单梳理如下。

风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法,redis,数据库,缓存

以下根据此流程分析,其实编程(也不全是指编程)有趣的地方是设计和实现的过程。

模版方法

设计模式-模版方法可以在这应用,从上面的流程并结合指标的分类来分析,主流程中的判断指标状态、指标条件、获取当前时间戳、获取redis数据设置过期、清理过期数据都是通用的,根据指标类型变化的只有添加事件这个步骤,所以定义模版抽象类如下:

@Setter
@Getter
@Slf4j
public abstract class AbstractIndicator {

    /**
     * 指标
     */
    protected IndicatorPO indicator;

    /**
     * 指标类型
     */
    protected final IndicatorType INDICATOR_TYPE;

    /**
     * redisson客户端
     */
    protected final RedissonClient redissonClient;

    protected AbstractIndicator(IndicatorType indicatorType, RedissonClient redissonClient) {
        INDICATOR_TYPE = indicatorType;
        this.redissonClient = redissonClient;
    }

    /**
     * 获取指标类型
     *
     * @return 指标类型
     */
    public Integer getType() {
        return INDICATOR_TYPE.getCode();
    }

    /**
     * 获取指标状态
     *
     * @return true/false
     */
    public boolean getStatus() {
        return indicator.getStatus();
    }

    /**
     * 指标过滤
     *
     * @return true/false
     */
    public boolean filter(Map<String, String> eventDetail) {
        // 1、主属性、从属性不为空
        if (indicator.getMasterField() != null && eventDetail.get(indicator.getMasterField()) != null) {
            if (indicator.getSlaveFields() != null) {
                String[] split = indicator.getSlaveFields().split(",");
                for (String s : split) {
                    if (eventDetail.get(s) == null) {
                        return false;
                    }
                }
                // 2、过滤脚本
                if (indicator.getFilterScript() == null) {
                    return true;
                } else {
                    // TODO 脚本过滤
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 获取redis key
     *
     * @param eventDetail 事件详情
     * @return redis key
     */
    public String getRedisKey(Map<String, String> eventDetail) {
        return RedisKeys.INDICATOR + indicator.getId() + ":" + INDICATOR_TYPE.getName() + ":" + eventDetail.get(indicator.getMasterField()) + "-" + eventDetail.get(indicator.getSlaveFields());
    }

    /**
     * 获取计算指标结果
     *
     * @param currentTime 当前时间戳
     * @param set         redis set
     * @return 计算指标结果
     */
    public abstract BigDecimal getResult(long currentTime, RScoredSortedSet<String> set);

    /**
     * 获取计算指标结果
     *
     * @param eventDetail 事件详情
     * @return 计算指标结果
     */
    public BigDecimal getResult(Map<String, String> eventDetail) {
        // 1、获取当前时间戳
        long currentTime = System.currentTimeMillis();
        // 2、获取redis中数据
        RScoredSortedSet<String> set = redissonClient.getScoredSortedSet(getRedisKey(eventDetail));
        // 3、清理过期数据
        if ("last".equals(indicator.getWinType())) {
            set.removeRangeByScore(-1, true, currentTime - Duration.ofSeconds(indicator.getTimeSlice()).toMillis(), false);

        } else {
            set.removeRangeByScore(-1, true, calculateEpochMilli(LocalDateTime.now()), false);
        }

        return getResult(currentTime, set);
    }

    /**
     * 计算指标
     *
     * @param indicator   指标
     * @param eventDetail 事件详情
     */
    public void compute(IndicatorPO indicator, Map<String, String> eventDetail) {
        if (indicator == null) {
            return;
        } else {
            this.indicator = indicator;
        }
        // 1、状态检查和过滤
        if (getStatus() && filter(eventDetail)) {

            // 2、获取当前时间戳
            long currentTime = System.currentTimeMillis();
            // 3、获取redis中数据
            log.info("redisKey:{}", getRedisKey(eventDetail));
            RScoredSortedSet<String> set = redissonClient.getScoredSortedSet(getRedisKey(eventDetail));
            if ("last".equals(this.indicator.getWinType())) {
                set.expire(Duration.ofSeconds(this.indicator.getTimeSlice() * this.indicator.getWinCount()));
            } else {
                set.expire(Duration.ofSeconds(this.indicator.getTimeSlice()));
            }

            // 4、添加事件
            addEvent(currentTime, set, eventDetail);

            // 5、清理过期数据
            cleanExpiredDate(currentTime, set);
        }

    }

    /**
     * 添加事件
     *
     * @param currentTime 当前时间戳
     * @param set         redis set
     * @param eventDetail 事件详情
     */
    public abstract void addEvent(long currentTime, RScoredSortedSet<String> set, Map<String, String> eventDetail);

    /**
     * 清理过期数据
     *
     * @param currentTime 当前时间戳
     * @param set         redis set
     */
    public void cleanExpiredDate(long currentTime, RScoredSortedSet<String> set) {
        if ("last".equals(indicator.getWinType())) {
            set.removeRangeByScore(-1, true, currentTime - Duration.ofSeconds(indicator.getTimeSlice()).toMillis(), false);
        } else {
            set.removeRangeByScore(-1, true, calculateEpochMilli(LocalDateTime.now()), false);
        }
    }

    /**
     * 计算时间戳
     *
     * @param now 当前时间
     * @return 时间戳
     */
    public long calculateEpochMilli(LocalDateTime now) {
        ZoneId zoneId = ZoneId.systemDefault();
        // 这个default分支仅处理WindowSize枚举中未包含的情况
        return switch (indicator.getWinSize()) {
            case "M" -> now.withDayOfMonth(1).with(LocalTime.MIN).atZone(zoneId).toInstant().toEpochMilli();
            case "d" -> now.with(LocalTime.MIN).atZone(zoneId).toInstant().toEpochMilli();
            case "H" -> now.withMinute(0).withSecond(0).withNano(0).atZone(zoneId).toInstant().toEpochMilli();
            case "m" -> now.withSecond(0).withNano(0).atZone(zoneId).toInstant().toEpochMilli();
            case "s" -> now.withNano(0).atZone(zoneId).toInstant().toEpochMilli();
            default -> throw new IllegalArgumentException("Unsupported window size: " + indicator.getWinSize());
        };
    }
}

次数统计指标

因为篇幅原因,这里只贴次数统计指标实现类了。

/**
 * @author wnhyang
 * @date 2024/3/11
 **/
@Component
public class CountIndicator extends AbstractIndicator {

    public CountIndicator(RedissonClient redissonClient) {
        super(IndicatorType.COUNT, redissonClient);
    }

    @Override
    public BigDecimal getResult(long currentTime, RScoredSortedSet<String> set) {

        return BigDecimal.valueOf(set.size());
    }

    @Override
    public void addEvent(long currentTime, RScoredSortedSet<String> set, Map<String, String> eventDetail) {

        set.add(currentTime, eventDetail.get("seqId"));
    }

}

总结

先到这里吧,还有其他内容到下次吧。

写在最后

拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。


个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview

风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法,redis,数据库,缓存文章来源地址https://www.toymoban.com/news/detail-839663.html

到了这里,关于风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • opencv特征提取、梯度计算

                                             

    2024年02月11日
    浏览(39)
  • 【计算机视觉、关键点检测、特征提取和匹配】基于SIFT、PCA-SIFT和GLOH算法在不同图像之间建立特征对应关系,并实现点匹配算法和图像匹配(Matlab代码实现)

    💥💥💞💞 欢迎来到本博客 ❤️❤️💥💥 🏆博主优势: 🌞🌞🌞 博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️ 座右铭: 行百里者,半于九十。 📋📋📋 本文目录如下: 🎁🎁🎁 目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码、数据、文章

    2024年03月14日
    浏览(55)
  • Python实现KDJ指标计算:股票技术分析的利器系列(3)

    先看看官方介绍: KDJ(随机指标) 用法 1.D指标80 时,回档机率大;D指标20时,反弹机率大; 2.K在20左右向上交叉D时,视为买进信号; 3.K在80左右向下交叉D时,视为卖出信号; 4.J100 时,股价易反转下跌;J0 时,股价易反转上涨; 5.KDJ 波动于50左右的任何信号,其作用不大。

    2024年02月19日
    浏览(39)
  • 计算机视觉:特征提取与匹配

    目录 1. 特征提取和匹配 1.1 背景知识 1.2 特征匹配基本流程 1.3 局部特征描述子 2. Harris角点检测  2.1 角点(corner points) 2.2 HARRIS角点检测基本思想 2.3 HARRIS检测:数学表达 2.4 角点响应函数 2.5 编程实现 2.5.1 角点检测代码实现  2.5.2 角点检测数据测试 3.  SIFT特征匹配算法

    2024年02月06日
    浏览(42)
  • 计算机视觉之图像特征提取

    图像特征提取是计算机视觉中的重要任务,它有助于识别、分类、检测和跟踪对象。以下是一些常用的图像特征提取算法及其简介: 颜色直方图(Color Histogram) : 简介 :颜色直方图表示图像中各种颜色的分布情况。通过将图像中的像素分成颜色通道(如RGB)并计算每个通道

    2024年02月12日
    浏览(41)
  • AHP中特征向量、权重值、CI值等指标如何计算?

    AHP层次分析法是一种解决多目标复杂问题的定性和定量相结合进行计算决策权重的研究方法。该方法将定量分析与定性分析结合起来,用决策者的经验判断各衡量目标之间能否实现的标准之间的相对重要程度,并合理地给出每个决策方案的每个标准的权数,利用权数求出各方

    2024年02月04日
    浏览(36)
  • 【大数据】文本特征提取与文本相似度分析

    写在博客前的话: 本文主要阐述如何对一段简短的文本做 特征提取 的处理以及如何对文本进行 分析 。 本文主要脉络以一个故事 s t o r y story s t ory 为主线,以该主线逐步延申,涉及到: 文本特征提取 、 词汇频率统计 (TF) , 反文档频率 (IDF) 以及 余弦相似度 计算的概念,

    2023年04月27日
    浏览(42)
  • 计算机图像处理—HOG 特征提取算法

    1. 实验内容 本实验将学习HOG 特征提取算法。 2. 实验要点 HOG 算法 HOG 算法有效的原因 创建 HOG 描述符 HOG 描述符中的元素数量 可视化 HOG 描述符 理解直方图 3. 实验环境 Python 3.6.6 numpy matplotlib cv2 copy 简介 正如在 ORB 算法中看到的,我们可以使用图像中的关键点进行匹配,以检

    2024年02月09日
    浏览(55)
  • python之pyAudioAnalysis:音频特征提取分析文档示例详解

    PyAudioAnalysis是一个开源的Python库,用于从音频文件中提取特征并进行分析。它提供了一系列音频处理函数,可以帮助开发者实现音频分类、情感识别、语音分析等多种任务。在本文中,我们将详细介绍如何使用PyAudioAnalysis进行音频特征提取和分析。 音频特征提取 PyAudioAnalys

    2024年02月16日
    浏览(45)
  • 计算机视觉的应用12-卷积神经网络中图像特征提取的可视化研究,让大家理解特征提取的全过程

    大家好,我是微学AI,今天给大家介绍一下计算机视觉的应用12-卷积神经网络中图像特征提取的可视化研究,让大家理解特征提取的全过程。 要理解卷积神经网络中图像特征提取的全过程,我们可以将其比喻为人脑对视觉信息的处理过程。就像我们看到一个物体时,大脑会通

    2024年02月10日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包