用java实现基于熵权G1法的CBR相似案例筛选方法,找出历史相似水污染事件

一、

  1. 想要具体了解基于熵权G1法的CBR相似案例筛选方法的,可以去看这篇论文:
    在这里插入图片描述
  2. 这里举一个具体的例子来说明如何计算两件事的相似程度
  • 第一件事的数组[1, 0, 0.5, 0.3, 0.8]
  • 第二件事的数组[1, 1, 0.7, 0.1, 0.8]

那么相似程度是这样算的:

sim=(1-|1-1|)*0.2+(1-|0-1|)*0.2+(1-|0.5-0.7|)*0.2+(1-|0.3-0.1|)*0.2+(1-|0.8-0.8|)*0.2

这里的0.2是权重,由专家讨论得出的,当然是我自己取的。反正所有的0.2加起来等于1就行了,这里有5个0.2,加起来就是1。

用语言去描述公式,就是:
用1减去两者之差,然后乘以权重,对于数组中的每个元素,都进行这样的操作,最后将这些结果加起来就行了。

相似程度的取值范围是零到一:[0,1]

二、

  1. 看了上面的例子,你可能会问,水污染事件怎么和上面的数组关联起来呢?先看下面的两件水污染事件:
    在这里插入图片描述

  2. 这里基本全是文字呀,怎么计算相似度?没错,文字不能用于计算,但是可以把文字和数字映射起来。以污染物毒性为例,文字可以和数字建立如下图的映射方式:
    在这里插入图片描述
    也就是事件一的“中等毒”,可以用0.5表示,事件二的低毒可以用0.3表示。

  3. 那么污染物类型和污染物来源怎么赋值?我们可以以事件一为参考,直接把事件一的污染物类型和污染物来源赋值为1,
    其他事件(事件二),如果污染物类型与事件一的污染物类型相同,就赋值为1,否则赋值为0,同理,如果污染物来源与事件一的污染物来源相同,就赋值为1,否则赋值为0。

  4. 还有污染物超标倍数、与下游取水口方法这两个指标,可以按照(类比)下面的方法赋值:
    在这里插入图片描述

三、代码

  1. 代码实现起来并不难,为一个水污染案例(事件)写一个实体类即可,其中数据库保存有一定数量的案例。
    实体类如下(为了按照相似度排序,需要实现Comparable接口):
package domain;

/**
 * @author laoyingyong
 * @date: 2020-02-05 13:28
 */
public  class Example implements Comparable<Example>
{
    private Integer id;
    private String name;
    private String type;
    private String source;
    private Double multiple;
    private Integer distance;
    private String toxicity;
    private String danger;
    private String stability;
    private String solubility;
    private String volatility;
    private String technology;

    private Double sim;

    public Double getSim() {
        return sim;
    }

    public void setSim(Double sim) {
        this.sim = sim;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public Double getMultiple() {
        return multiple;
    }

    public void setMultiple(Double multiple) {
        this.multiple = multiple;
    }

    public Integer getDistance() {
        return distance;
    }

    public void setDistance(Integer distance) {
        this.distance = distance;
    }

    public String getToxicity() {
        return toxicity;
    }

    public void setToxicity(String toxicity) {
        this.toxicity = toxicity;
    }

    public String getDanger() {
        return danger;
    }

    public void setDanger(String danger) {
        this.danger = danger;
    }

    public String getStability() {
        return stability;
    }

    public void setStability(String stability) {
        this.stability = stability;
    }

    public String getSolubility() {
        return solubility;
    }

    public void setSolubility(String solubility) {
        this.solubility = solubility;
    }

    public String getVolatility() {
        return volatility;
    }

    public void setVolatility(String volatility) {
        this.volatility = volatility;
    }

    public String getTechnology() {
        return technology;
    }

    public void setTechnology(String technology) {
        this.technology = technology;
    }

    @Override
    public String toString() {
        return "Example{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", type='" + type + '\'' +
                ", source='" + source + '\'' +
                ", multiple=" + multiple +
                ", distance=" + distance +
                ", toxicity='" + toxicity + '\'' +
                ", danger='" + danger + '\'' +
                ", stability='" + stability + '\'' +
                ", solubility='" + solubility + '\'' +
                ", volatility='" + volatility + '\'' +
                ", technology='" + technology + '\'' +
                ", sim=" + sim +
                '}';
    }


    @Override
    public int compareTo(Example example)
    {
        return this.sim<example.sim?1:this.sim>example.sim?-1:0;
    }
}

  1. 再写一个工具类(因为用户输入的内容基本是都汉字),把汉字和数字建立起映射关系。当然也可以不写这个工具类,前端直接把数据发送到后台即可。
package util;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

/**
 * @author laoyingyong
 * @date: 2020-02-05 14:32
 */
public class ExampleUtils
{
    public static double getMultipleNum(double n)
    {
        if(n>=100)
        { return 1;}
        else if(n>=90)
        { return 0.9;}
        else if(n>=80)
        {return 0.8;}
        else if(n>=70)
        {return 0.7;}
        else if(n>=60)
        {return 0.6;}
        else if(n>=50)
        {return 0.5;}
        else if(n>=40)
        {return 0.4;}
        else if(n>=30)
        {return 0.3;}
        else if(n>=20)
        {return 0.2;}
        else if(n>=0)
        {return 0.1;}
        else {System.out.println("倍数不能为负数!");return 0;}//倍数不可能为负数
    }


    public static double getDistanceNum(double n)
    {
        if(n>=270)
        { return 1;}
        else if(n>=240)
        { return 0.9;}
        else if(n>=210)
        {return 0.8;}
        else if(n>=180)
        {return 0.7;}
        else if(n>=150)
        {return 0.6;}
        else if(n>=120)
        {return 0.5;}
        else if(n>=90)
        {return 0.4;}
        else if(n>=60)
        {return 0.3;}
        else if(n>=30)
        {return 0.2;}
        else if(n>=0)
        {return 0.1;}
        else {System.out.println("距离不能为负数!");return 0;}//距离不可能为负数
    }

    public static double getToxicityNum(String toxicity)
    {
        if(toxicity.equals("微毒"))
        {
            return 0.1;
        }
        else if(toxicity.equals("低毒"))
        {
            return 0.3;
        }
        else if(toxicity.equals("中等毒"))
        {
            return 0.5;
        }
        else if(toxicity.equals("高毒"))
        {
            return 0.7;
        }
        else if(toxicity.equals("剧毒"))
        {
            return 0.9;
        }
        else
        {
            System.out.println("污染毒性等级有误!");
            return 0;
        }
    }

    public static double getDangerNum(String danger)
    {
        if(danger.equals("可燃"))
        {
            return 0.2;
        }
        else if(danger.equals("易燃"))
        {
            return 0.5;
        }
        else if(danger.equals("易燃易爆"))
        {
            return 0.8;
        }
        else
        {
            System.out.println("污染物危险等级有误!");
            return 0;
        }
    }

    public static double getStabilityNum(String stability)
    {
        if(stability.equals("不稳定"))
        {
            return 0.2;
        }
        else if(stability.equals("中等"))
        {
            return 0.5;
        }
        else if(stability.equals("稳定"))
        {
            return 0.8;
        }
        else
        {
            System.out.println("污染物稳定性等级有误!");
            return 0;
        }
    }


    public static double getSolubilityNum(String solubility)
    {
        if(solubility.equals("不溶于水"))
        {
            return 0.2;
        }
        else if(solubility.equals("微溶于水"))
        {
            return 0.5;
        }
        else if(solubility.equals("易溶于水"))
        {
            return 0.8;
        }
        else
        {
            System.out.println("污染物溶解性等级有误!");
            return 0;
        }
    }

    public static double getVolatilityNum(String volatility)
    {
        if(volatility.equals("不易挥发"))
        {
            return 0.2;
        }
        else if(volatility.equals("中等挥发"))
        {
            return 0.5;
        }
        else if(volatility.equals("易挥发"))
        {
            return 0.8;
        }
        else
        {
            System.out.println("污染物挥发性等级有误!");
            return 0;
        }
    }
}

  1. 业务逻辑层(service层)的代码如下:
package service.impl;

import dao.ExampleDao;
import dao.impl.ExampleDaoImpl;
import domain.Example;
import service.ExampleService;
import util.ExampleUtils;

import java.text.DecimalFormat;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * @author laoyingyong
 * @date: 2020-02-05 13:47
 */
public class ExampleServiceImpl implements ExampleService
{
    ExampleDao dao=new ExampleDaoImpl();


    @Override
    public List<Example> findResembleExamples(String type, String source, double multiple, int distance, String toxicity, String danger, String stability, String solubility, String volatility)
    {
        double [] current=new double[9];//当前污染事件的数组
        //给数组赋值
        current[0]=1;
        current[1]=1;
        current[2]= ExampleUtils.getMultipleNum(multiple);//超标倍数
        current[3]=ExampleUtils.getDistanceNum(distance);
        current[4]=ExampleUtils.getToxicityNum(toxicity);
        current[5]=ExampleUtils.getDangerNum(danger);
        current[6]=ExampleUtils.getStabilityNum(stability);
        current[7]=ExampleUtils.getSolubilityNum(solubility);
        current[8]=ExampleUtils.getVolatilityNum(volatility);


        List<Example> list = dao.findResembleExamples();
        LinkedList<Example> exampleLinkedList=new LinkedList<>();
        for (Example example : list)
        {
            String type1 = example.getType();
            String source1 = example.getSource();
            Double multiple1 = example.getMultiple();
            Integer distance1 = example.getDistance();
            String toxicity1 = example.getToxicity();
            String danger1 = example.getDanger();
            String stability1 = example.getStability();
            String solubility1 = example.getSolubility();
            String volatility1 = example.getVolatility();

            double [] history=new double[9];//历史污染事件的数组
            //给数组赋值
            if(type1.equals(type))//如果污染物类型相同就赋值为1,否则为0
            {
                history[0]=1;
            }
            else
            {
                history[0]=0;
            }
            if(source1.equals(source))//如果污染物来源相同就赋值为1,否则赋值为0
            {
                history[1]=1;
            }
            else
            {
                history[1]=0;
            }
            history[2]= ExampleUtils.getMultipleNum(multiple1);//超标倍数
            history[3]=ExampleUtils.getDistanceNum(distance1);//距离
            history[4]=ExampleUtils.getToxicityNum(toxicity1);//毒性
            history[5]=ExampleUtils.getDangerNum(danger1);//危险程度
            history[6]=ExampleUtils.getStabilityNum(stability1);//稳定性
            history[7]=ExampleUtils.getSolubilityNum(solubility1);//溶解性
            history[8]=ExampleUtils.getVolatilityNum(volatility1);//挥发性

            double sim=(1-Math.abs(current[0]-history[0]))*0.1123+//根据熵权G1法计算当前污染事件与历史污染事件的相似度
            (1-Math.abs(current[1]-history[1]))*0.1123+
            (1-Math.abs(current[2]-history[2]))*0.1123+
            (1-Math.abs(current[3]-history[3]))*0.1123+
            (1-Math.abs(current[4]-history[4]))*0.1112+
            (1-Math.abs(current[5]-history[5]))*0.1112+
            (1-Math.abs(current[6]-history[6]))*0.1109+
            (1-Math.abs(current[7]-history[7]))*0.1088+
            (1-Math.abs(current[8]-history[8]))*0.1088;

            DecimalFormat decimalFormat=new DecimalFormat("0.0000");//保留四位小数
            String format = decimalFormat.format(sim);
            double v = Double.parseDouble(format);
            example.setSim(v);//设置相似度
            if(v>0.5)//如果相似度大于0.5的话,就存入集合中
            {
                exampleLinkedList.add(example);
            }
            
        }
        Collections.sort(exampleLinkedList);//按照相似度从大到小排序,Example这个实体类要实现Comparable接口才行
        System.out.println("排序后"+exampleLinkedList);
        return exampleLinkedList;
    }
}

四、效果展示

  1. 前端用户的输入,大部分都是下拉列表select
    在这里插入图片描述
  2. 后台经过熵权计算,把相似度比较大的数据发送到前台,相似度按照从大到小的顺序进行排序。
    在这里插入图片描述
发布了33 篇原创文章 · 获赞 0 · 访问量 1427

猜你喜欢

转载自blog.csdn.net/Deep_rooted/article/details/104189664