⽤户输⼊特性评估
算法推理
传过来的用户输入特性,是用户输入用户名,密码,验证码各自所用的时间,
我们从客户历史登入成功的这些输入特性中利用算法来评估出一个标准范围,来判断以后的输入是否存在非本人之类的风险情况!
我们可以将用户的特性都看作如上图坐标上的一个点,输入特性不同,点的位置也就不同,以一个圆为标准,圆内为正常圆外为异常!(之所以用圆而不用正方形之类的是因为圆从圆心无论到哪个方向的边都是同距离的)
问题来了:一,如何确定圆心
用平均输入时长,历史输入的平均值,中值点
问题二,如何确定半径
1,先计算所有已知点两两间距
如果有N 个点 会有几个间距值为采样点? 为 n(n-1)/ 2 个 符合等差数列
2,对获取到的样本点距离进行排序
3,我们取排序后序列的2/3 作为半径(因为要拿的是客户的输入习惯,所以拿的要大于1/2)也可以用0.618黄金分割点
问题三,我们如何计算当前用户输入与中心的距离
算法捋好了,那就进行代码实现环节喽
package com.baizhi.evaluate.impl;
import com.baizhi.enties.EvaluateData;
import com.baizhi.enties.EvaluateReport;
import com.baizhi.enties.HistoryData;
import com.baizhi.enties.RiskFactor;
import com.baizhi.evaluate.Evaluate;
import com.baizhi.evaluate.EvaluateChain;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class InputFeatureEvaluate extends Evaluate {
public InputFeatureEvaluate() {
super(RiskFactor.INPUTFEATURE);
}
@Override
public void eval(EvaluateData evaluateData, HistoryData historyData, EvaluateReport evaluateReport,
EvaluateChain evaluateChain) {
evaluateReport.signReport(getRiskFactor(),
doInputFeature(evaluateData.getInputFeatures(),historyData.getLatestInputFeatures()));
//往后调
evaluateChain.daChain(evaluateData,historyData,evaluateReport);
}
/**
* 1.计算圆心中点
* 2.计算两两特征距离
* 3.对距离进行排序(升序),取2/3处作为评估距离阈值 - threshold
* 4.计算当前输入的特征距离中心点距离
*/
public boolean doInputFeature(Double[] inputFeatures, List<Double[]> latestInputFeatures){
//如果没有历史证明第一次登,如果历史少于两个则没必要评估和也没法评估
if (latestInputFeatures==null | latestInputFeatures.size()<2) return false;
//圆中心坐标
Double[] doubles = centrePoint(latestInputFeatures);
//圆半径
double radius = radius(latestInputFeatures);
//输入特性到圆心的距离
double distance = distance(inputFeatures, doubles);
return distance>radius;
}
//计算圆中心
public Double[] centrePoint(List<Double[]> latestInputFeatures){
double a=0.0;
double b=0.0;
double c=0.0;
for (Double[] latestInputFeature : latestInputFeatures) {
a+=latestInputFeature[0];
b+=latestInputFeature[1];
c+=latestInputFeature[2];
}
int size = latestInputFeatures.size();
Double[] d={a/size,b/size,c/size};
return d;
}
//计算圆半径
public double radius(List<Double[]> latestInputFeatures){
List<Double> list=new ArrayList<>();
for (int i=0 ;i<latestInputFeatures.size();i++){
Double[] inputFeatures = latestInputFeatures.get(i);
for (int a=i+1;a<latestInputFeatures.size();a++){
double distance = distance(inputFeatures,latestInputFeatures.get(a));
list.add(distance);
}
}
//对集合进行排序然后取2/3 处作为半径
int c= latestInputFeatures.size();
int b= c*(c-1)/3;
Double aDouble = list.stream().sorted().collect(Collectors.toList()).get(b);
return aDouble;
}
//计算 输入特性到圆点的距离
public double distance(Double[] inputFeatures,Double[] doubles){
//使用的是欧式距离公式
double a=0.0;
for(int i=0;i<inputFeatures.length;i++){
a+=(inputFeatures[i]-doubles[i])*(inputFeatures[i]-doubles[i]);
}
//返回开平方的结果
return Math.sqrt(a);
}
//测试下
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});
System.out.println(inputFeatureEvaluate.doInputFeature(new Double[]{100.0, 1000.0, 1750.0}, latestInputFeatures));
}
}