算法-入门篇(欧式距离)

概述

在数学中,欧几里得距离欧几里得度量是欧几里得空间中两点间“普通”(即直线)距离。使用这个距离,欧氏空间成为度量空间。
详见 百度百科:https://baike.baidu.com/item/%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E5%BA%A6%E9%87%8F/1274107?fromtitle=%E6%AC%A7%E5%BC%8F%E8%B7%9D%E7%A6%BB&fromid=2809635&fr=aladdin

计算公式

算法-入门篇(欧式距离)_第1张图片

使用

  • 欧式距离在数学上,一般用在求任意维度空间的2点之间的距离。
  • 开发中,多用在,判端某些数据的摇摆幅度,并剔除一些差异化较大的数据。例如:风控系统中,用户输入特性的判定上

本文将根据用户输入特征的数据模型,对欧式距离的应用进行简单的介绍。

总思路: 根据用户的历史登录的输入特征,建立 圆形 的数据模型,取落入此圆内的数据,作为正常值,落到圆外部的数据将被判定为风险数据。

  • 建模 :根据历史的输入特性,建立多维度的几何模型。(一般为2~3维)
  • 计算圆心:跟据历史数据的每个轴的对应数据长度,根据公式 一条直线上任意点的距离中点=点与初始点(即 坐标轴心)的长度之和/点个数,计算出圆心的位置。
  • 计算半径: 根据欧式距离公式,计算出各个点之间的距离,按照由小到大排序后,取其大于1/2处的数据作为半径。
  • 计算当前请求的特征点是否落在圆内: 根据欧式距离公式,计算出,圆心到请求点的距离,判断是否落在圆内(即距离是否小于半径)。

代码实现

 public boolean doEval(Double[] inputFeatures, List<Double[]> historyInputFeatures){
        //如果特征不足2次,不进行验证
        if(historyInputFeatures.size()<2){
            return false;
        }
        //已经足够2次
        /**
         * 第一步,计算圆心
         */

        //计算出圆心,所有点的同一轴下的坐标长度相加/点的数量
        Double[] centerOfCircle = historyInputFeatures.stream().reduce((x, y) -> {
            //创建一个double 数组,用于接收圆心数据,数组长度为历史数据的维度
            Double[] centerOfCircles = new Double[historyInputFeatures.get(0).length];
            //获取每个轴下对应数据的总和
            for (int i = 0; i < historyInputFeatures.get(0).length; i++) {
                if (centerOfCircles[i] == null) {
                    centerOfCircles[i] = 0.0;
                }
                centerOfCircles[i] += x[i] + y[i];
            }
            return centerOfCircles;
        }).get();
        //计算最终的圆心结果
        for (int i = 0; i < centerOfCircle.length; i++) {
            centerOfCircle[i] = centerOfCircle[i]/historyInputFeatures.size();
        }
        System.out.println("计算的圆心位置是\t"+ Arrays.stream(centerOfCircle).map(x->x+"").reduce((v1,v2)->v1+","+v2).get());
        /**
         * 第二步,进行半径的计算,求出所有2点之间的半径,排序后取2/3的位置作为半径阈值
         */
        //创建一个接收所有距离的数组,长度是 (设历史点个数为n)(n*n-1)/2
        //确定数组长度
        int size = ((historyInputFeatures.size())*(historyInputFeatures.size()-1))/2;
        List<Double> allDistance = new ArrayList<Double>();
        for (int i = 0; i < historyInputFeatures.size(); i++) {
            //每次,拿1个历史数据点,和其他的数据进行距离计算
            for (int j = i+1; j < historyInputFeatures.size(); j++) {
                //计算每2个点的距离,并存入集合中
                allDistance.add(getDistance(historyInputFeatures.get(i),historyInputFeatures.get(j)));
            }
        }
        //排序,求出2/3位置的长度,作为半径
        allDistance.sort((a,b)->{
            if(a==b){
                return 0;
            }else{
                return a>b?1:-1;
            }
        });
        //得出半径
        Double radius = allDistance.get((allDistance.size() * 2) / 3);
        System.out.println("计算的半径是\t"+radius);
        /**
         * 第三步,判断当前特征的模型点到圆心的距离是否小于半径,是就无风险,否则有风险
         */
        //获取当前的点的距离圆心的长度
        Double result = getDistance(inputFeatures,centerOfCircle);
        System.out.println("当前的点距离圆心的长度为"+result);
        return result > radius;


    }

    //提供一个计算2点之间距离的方法 ∑(Xi-Yi)^2
    private Double getDistance(Double[] point1,Double[] point2){
        //创建一个变量,用于接收,每次求和之后的值
        Double sum = 0.0;
        for (int i = 0; i < point1.length; i++) {
            sum += Math.pow(point1[i]-point2[i],2);
        }
        //最后返回计算结果
        return Math.sqrt(sum);

    }

测试

    public static void main(String[] args) {
        InputFeatureEvaluate inputFeatureEvaluate = new InputFeatureEvaluate();
        ArrayList<Double[]> latestInputFeatures = new ArrayList<>();
        latestInputFeatures.add(new Double[]{1000.0,1100.0,1800.0});
        latestInputFeatures.add(new Double[]{1100.0,1120.0,1750.0});
        latestInputFeatures.add(new Double[]{950.0,1250.0,2000.0});
        latestInputFeatures.add(new Double[]{1200.0,1050.0,1900.0});
        latestInputFeatures.add(new Double[]{1400.0,800.0,2500.0});

        inputFeatureEvaluate.doEval(new Double[]{1100.0,1000.0,1750.0},latestInputFeatures);

    }

你可能感兴趣的:(算法)