Constructive Covering Algorithm

来源:互联网 发布:算法工程师的年薪 编辑:程序博客网 时间:2024/06/08 18:39

以前看的一篇paper:A Three-Way Decisions Model Based on Constructive Covering Algorithm,按照自己的理解用java实现了论文的代码。


package ConstructiveCoveringAlgorithm;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class CCA {

public static int num_features=4;//样本属性值

//样本类,存储每个样本的数据
public class Sample
{
private double[] attributes=new double[num_features];//样本属性值
private double[] attr=new double[num_features+1];//升维后的样本属性,即该样本的覆盖中心
private int label;//样本标签
private int prediction;//经过LR得到的决策值
private double radium;//改样本的覆盖半径
Sample(double[] attributes,int label)
{
for(int i=0;i<this.attributes.length;i++)
{
this.attributes[i]=attributes[i];
this.attr[i]=attributes[i];
}
this.label=label;
this.prediction=label;
this.radium=0;
}
public double[] getAttributes()//获得样本的属性
{
return this.attr;
}
public void setAttributes(int i,double value)//设置样本对应的属性值
{
this.attr[i]=value;
}
public int getLabel()//获得样本的标签
{
return this.label;
}
public double getPrediction()//获得样本的决策值
{
return this.prediction;
}
public void setPrediction(int value)//设置样本的决策值
{
this.prediction=value;
}
public double getRadium()//获得样本的覆盖半径
{
return this.radium;
}
public void setRadium(double value)//设置样本的覆盖半径
{
this.radium=value;
}

}

public void load_datas(String path,ArrayList<Sample> sampleSet)
{
String line;//记录从数据集中读取的行数据
String[] s ;//存储从数据集中读出的行数据分割后的样本属性和标签
double[] attributes=new double[num_features];//存储每个样本的属性值
FileReader fr =null;
BufferedReader bufr = null ;
try
{
fr = new FileReader(path);
bufr= new BufferedReader(fr);
//读取训练样本
while((line = bufr.readLine())!=null)
{
s = line.split(",");
for(int i=0;i<num_features;i++)//将获得的样本属性值转为double类型
{
attributes[i]=Double.parseDouble(s[i]);
}
sampleSet.add(new Sample(attributes,Integer.parseInt(s[s.length-1].trim())));
}
}
catch(IOException e){}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch(IOException e){

}
}
}

//将原始数据集划分为训练集和测试集
public void divid_dataSet(ArrayList<Sample> sampleSet,ArrayList<Sample> trainSet,ArrayList<Sample> testSet)
{
ArrayList<Sample> posSet = new ArrayList<Sample>();// 正样本集
ArrayList<Sample> negSet = new ArrayList<Sample>();// 负样本集
int pos = 0;// 正样本个数
int neg = 0;// 负样本个数
int train_instances = 0;// 训练样本个数
int train_instances_pos = 0;// 训练集中正 个数
int i=0;
Iterator<Sample> it_sampleSet= sampleSet.iterator();

Collections.shuffle(sampleSet);//打乱原始数据集,重新随机排列
while(it_sampleSet.hasNext())//迭代遍历原始样本集,计算其中正,负样本数目
{
Sample s=it_sampleSet.next();
if(s.getLabel()==1)
{
posSet.add(s);//标签为1的样本加入正样本集
pos++;
}
else
{
negSet.add(s);//标签为0的样本加入负样本集
neg++;
}
}

train_instances =(int)(sampleSet.size()*0.8);//取原始数据集的80%作为训练集
train_instances_pos = (int)(train_instances * ((pos*(1.0)) / (pos + neg)));//采用分层抽样,获取训练集中相应的正样本数

i=0;
Iterator<Sample> it_posSet= posSet.iterator();
while(it_posSet.hasNext())//迭代遍历正样本集
{
Sample s= it_posSet.next();
if (i< train_instances_pos) {// 选择正样本加入训练集
trainSet.add(s);
i++;
}
else// 选择正样本加入测试集
{
testSet.add(s);
}
}

i=0;
Iterator<Sample> it_negSet= negSet.iterator();
while(it_negSet.hasNext())//迭代遍历负样本集
{
Sample s= it_negSet.next();
if (i < train_instances - train_instances_pos) {// 选择负样本加入训练集
trainSet.add(s);
i++;
}
else// 选择负样本加入测试集
{
testSet.add(s);
}
}
}

//计算两个样本的欧式距离
    public double distance(double[] attr1,double[] attr2)
    {
    double distance=0;
    for(int i=0;i<attr1.length;i++)
    {
    distance +=Math.pow(attr1[i]-attr2[i], 2);
    }
    return Math.pow(distance, 0.5);
    }
    
   //对样本的每一个属性进行归一化
    public void normalization(ArrayList<Sample> sampleSet)
    {
    int i;
    Sample s;
    double[][] max_min=new double[num_features][2];//每一行存储所有样本对应某一属性的最大值和最小值
    double max=-999,min=999,temp=0,value=0;
    for(i=0;i<num_features;i++)//找出所有样本对应4个属性的最大值和最小值
    {
    max=-999;
    min=999;
    temp=0;
    Iterator<Sample> it_sampleSet=sampleSet.iterator();
    while(it_sampleSet.hasNext())
    {
    s=it_sampleSet.next();
    temp=s.getAttributes()[i];
    if(temp>max)
    max=temp;
    if(temp<min)
    min=temp;
    }
    max_min[i][0]=max;
    max_min[i][1]=min;
    }
   
    Iterator<Sample> it_sampleSet=sampleSet.iterator();
    while(it_sampleSet.hasNext())//归一化处理
    {
    s=it_sampleSet.next();
       for(i=0;i<num_features;i++)
       {
        value=(s.getAttributes()[i]-max_min[i][1])/(max_min[i][0]-max_min[i][1]);
        s.setAttributes(i, value);//设置样本属性归一化后的值
       }
   
    }
   
    }
    
    //将n(4)维样本投影到n+1(5)维空间,即升维。
    public void projection(ArrayList<Sample> sampleSet)
    {
    double max=0,sum=0;
    Sample s;
    Iterator<Sample> it_set=sampleSet.iterator();
    while(it_set.hasNext())//找出所有样本中n(4)个属性值平方和得最大值
    {
    sum=0;
    s=it_set.next();
    for(int i=0;i<s.getAttributes().length;i++)
    {
    sum +=Math.pow(s.getAttributes()[i], 2);
    }
    if(max<sum)
    max=sum;
    }
    Iterator<Sample> it_set1=sampleSet.iterator();
    while(it_set1.hasNext())//利用所有样本中4个属性值平方和得最大值减去每个样本的n(4)个属性平方和,得n+1(5)维
    {
    sum=0;
    s=it_set1.next();
    for(int i=0;i<s.getAttributes().length;i++)
    {
    sum +=Math.pow(s.getAttributes()[i], 2);
    }
    s.attr[4]=Math.pow(Math.pow(max, 2)-Math.pow(sum, 2),0.5);
    }
   
    }
    
    //训练数据,形成覆盖
    public void train(ArrayList<Sample> trainSet,ArrayList<ArrayList<Sample>> coverings)
    {
    Sample s1,s2;
    double max_radium,min_radium,radium=0,distance=0;
    ArrayList<Sample> covering_pos =coverings.get(0);//正样本的覆盖集合
    ArrayList<Sample> covering_neg =coverings.get(1);//负样本的覆盖集合
   
    Iterator<Sample> it_trainSet1=trainSet.iterator();
    while(it_trainSet1.hasNext())//计算相应样本距离训练集中同类样本的最大距离,异类样本的最小距离,形成覆盖中心
    {
    s1=it_trainSet1.next();
    max_radium=0;//同类样本的最大距离
    min_radium=99999;//异类样本的最小距离
    Iterator<Sample> it_trainSet2=trainSet.iterator();
    while(it_trainSet2.hasNext())
    {
    s2=it_trainSet2.next();
    distance=distance(s1.getAttributes(),s2.getAttributes());
    if(s1.getLabel()==s2.getLabel())
    {
    if(max_radium<distance)
max_radium=distance;
    }
    else
    {
    if(min_radium>distance)
min_radium=distance;
    }
    }
    if(min_radium<max_radium)//距离异类样本的最小距离小于距离同类样本的最大距离时
    max_radium=min_radium-0.00001;
    radium=(max_radium+min_radium)/2.0;//覆盖中心
    s1.setRadium(radium);
    if(s1.getLabel()==1)
    covering_pos.add(s1);
    else
    covering_neg.add(s1);
    }
    coverings.set(0, covering_pos);
    coverings.set(1, covering_neg);
    }
    //测试
    public double[] test(ArrayList<Sample> testSet,ArrayList<Sample> trainSet,ArrayList<ArrayList<Sample>> coverings) throws IOException
    {
    double tp=0,fp=0,tn=0,fn=0;//分类结果混淆矩阵的4个值
double[] perform=new double[4];//存储分类结果混淆矩阵的4个值
    Sample s,s_pos,s_neg,s_trainSample;
    int flag_pos,flag_neg,flag=0,bd_flag=0;
    double distance=0,min;
    ArrayList<Sample> covering_pos =coverings.get(0);//训练形成的正样本覆盖集合
    ArrayList<Sample> covering_neg =coverings.get(1);//训练形成的负样本覆盖集合
    BufferedWriter bufw = new BufferedWriter(new FileWriter("./data/ROC.txt"));//将样本的决策值和真实标签写入文件,在matlab中画ROC
    Iterator<Sample> it_testSet=testSet.iterator();
    while(it_testSet.hasNext())
    {
    s=it_testSet.next();
    flag_pos=0;
    flag_neg=0;
    Iterator<Sample> it_covering_pos=covering_pos.iterator();
        while(it_covering_pos.hasNext())//计算测试样本与正覆盖集合中样本的距离,比较覆盖半径
        {
        s_pos=it_covering_pos.next();
        distance=distance(s.getAttributes(),s_pos.getAttributes());
        if(distance<s_pos.getRadium())//测试样本与正覆盖集合中某个样本的距离小于其覆盖半径
        {
        flag_pos=1;
        break;
        }
        }
       
        Iterator<Sample> it_covering_neg=covering_neg.iterator();
        while(it_covering_neg.hasNext())//计算测试样本与负覆盖集合中样本的距离,比较覆盖半径
        {
        s_neg=it_covering_neg.next();
        distance=distance(s.getAttributes(),s_neg.getAttributes());
        if(distance<s_neg.getRadium())//测试样本与负覆盖集合中某个样本的距离小于其覆盖半径
        {
        flag_neg=1;
        break;
        }
        }
   
        if(flag_pos==1&&flag_neg==0)//测试样本与正覆盖集合中某样本的距离小于覆盖半径,并与负覆盖集合中所有样本的距离大于覆盖半径
        flag=1;
        else if(flag_pos==0&&flag_neg==1)//测试样本与正覆盖集合中所有样本的距离大于覆盖半径,并存在与负覆盖集合中某样本的距离大于覆盖半径
        flag=0;
        else//处于边界域
        flag=2;
       
        if(flag==2)//处于边界域的利用距覆盖中心最近原则进行划分
        {
        min=999;
        Iterator<Sample> it_trainSet=trainSet.iterator();
            while(it_trainSet.hasNext())
            {
            s_trainSample=it_trainSet.next();
            distance=distance(s.getAttributes(),s_trainSample.getAttributes());
            if(distance<min)
            {
            min=distance;
            bd_flag=s_trainSample.getLabel();
            }
            }
            flag=bd_flag;
        }
        bufw.write(s.getLabel()+"  "+flag);
bufw.newLine();
    s.setPrediction(flag);
    if(s.getLabel()==1)
   {
    if(flag==1)
    tp++;
    else
    fn++;
   }
   if(s.getLabel()==0)
   {
    if(flag==1)
    fp++;
    else
    tn++;
   } 
    }
    bufw.close();
    perform[0]=tp;
perform[1]=fp;
perform[2]=tn;
perform[3]=fn;
    return perform;
    }
    
    public void evaluation( double tp,double fp,double tn,double fn)//算法性能表示
{
double accuracy = (tp + tn) / (tp + tn + fp + fn);
double specificity = tn / (fp + tn);
double precision = tp / (tp + fp);
double recall = tp / (tp + fn);
double sensitivity = tp / (tp + fn);
double mcc = (tp * tn - fp * fn)
/ Math.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn));
double f1 = (2 * precision * recall) / (precision + recall);
System.out
.println("*********************************Result*****************************************");
System.out
.println("TP=" + tp + ",FP=" + fp + ",TN=" + tn + ",FN=" + fn);
System.out.println("Accuracy=" + accuracy + ",Specificity="
+ specificity);
System.out.println("Precision=" + precision + ",Recall=" + recall);
System.out.println("Sensitivity=" + sensitivity + ",MCC=" + mcc);
System.out.println("F1-measure=" + f1);
System.out
.println("********************************************************************************");
}

public static void main(String[] args) throws IOException 
{

CCA cca = new CCA();
ArrayList<Sample>  sampleSet= new ArrayList<Sample>();//原始样本集
ArrayList<Sample>  trainSet= new ArrayList<Sample>();//训练样本集
ArrayList<Sample>  testSet= new ArrayList<Sample>();//测试样本集
ArrayList<ArrayList<Sample>> coverings=new ArrayList<ArrayList<Sample>>();
coverings.add(new ArrayList<Sample>());
coverings.add(new ArrayList<Sample>());

cca.load_datas("./data/dataSet.txt",sampleSet);//加载数据集
cca.normalization(sampleSet);//归一化
cca.projection(sampleSet);//投影,升维
cca.divid_dataSet(sampleSet,trainSet,testSet);//将原始数据集划分为训练集和测试集
cca.train(trainSet,coverings);//训练
double[] perform=cca.test(testSet,trainSet,coverings);//测试
cca.evaluation(perform[0],perform[1],perform[2],perform[3]);

}


}


原创粉丝点击