RoughSets属性约简算法

参考资料:http://baike.baidu.com/link?url=vlCBGoGR0_97l9SQ-WNeRv7oWb-3j7c6oUnyMzQAU3PTo0fx0O5MVXxckgqUlP871xR2Le-puGfFcrA4-zIntq

更多挖掘算法:https://github.com/linyiqun/DataMiningAlgorithm

介绍

RoughSets算法是一种比较新颖的算法,粗糙集理论对于数据的挖掘方面提供了一个新的概念和研究方法。本篇文章我不会去介绍令人厌烦的学术概念,就是简单的聊聊RoughSets算法的作用,直观上做一个了解。此算法的应用场景是,面对一个庞大的数据库系统,如何从里面分析出有效的信息,如果一database中有几十个字段,有我们好受的了,但是一般的在某些情况下有些信息在某些情况下是无用的或者说是无效的,这时候我们假设在不影响最终决策分类结果的情况下,对此属性进行约简。这就是RoughSets所干的事情了。

算法原理

算法的原理其实很简单,所有属性分为2种属性1类为条件属性,1类为决策属性,我们姑且把决策属性设置在数据列的最后一列,算法的步骤依次判断条件属性是否能被约简,如果能被约简,此输出约简属性后的规则,规则的形式大体类似于IF---THEN的规则。下面举1个例子,此例子来自于百度百科上的粗糙集理论。

给定8条记录:

元素 颜色 形状 大小 稳定性
x1 红 三角 大 稳定
x2 红 三角 大 稳定
x3 黄 圆 小 不稳定
x4 黄 圆 小 不稳定
x5 蓝 方块 大 稳定
x6 红 圆 中 不稳定
x7 蓝 圆 小 不稳定
x8 蓝 方块 中 不稳定

在这里还是得介绍几个最基本的一些概念,这里的所有的记录的集合叫做论域,那么这个论域能表达出一些什么知识或者信息呢,比如说蓝色的或者中的积木={X5,X7,X8}U{X6,X8}={X5,X6,X7,X8},同理,通过论域集合内的记录进行交并运算能够表达出不同的信息。在这里总共有3个属性,就可以分成3x3=9个小属性分类,如下:
A/R1={X1,X2,X3}={{x1,x2,x6},{x3,x4},{x5,x7,x8}} (颜色分类)
A/R2={Y1,Y2,Y3}={{x1,x2},{x5,x8},{x3,x4,x6,x7}} (形状分类)
A/R3={Z1,Z2,Z3}={{x1,x2,x5},{x6,x8},{x3,x4,x7}} (大小分类)
我们定义一个知识系统A/R=R1∩R2∩R3,就是3x3x3总共27种可能,每行各取1个做计算组后的结果为

A/R={{x1,x2},{x3,x4},{x5},{x6},{x7},{x8}},所以这个知识系统所决定的知识就是A/R中所有的集合以此这些集合的并集。给定一个集合如何用知识系统中的集合进行表示呢,这就用到了又一对概念,上近似和下近似。比如说给定集合X={X2,X5X7},在知识库中就是下近似{X2.X5},上近似{X1,X2,X5,X7},上下近似的完整定义是下近似集是在那些所有的包含于X的知识库中的集合中求交得到的,而上近似则是将那些包含X的知识库中的集合求并得到的。在后面的例子中我也是以一个集合的上下近似集是否是等于他自身来对知识系统是否是允许的做一个判断。(这只是我自己的判断原则,并不是标准的)

下面是属性约简的过程,从颜色开始,这时知识系统变为了那么知识系统变成A/(R-R1)={{x1,x2},{x3,x4,x7},,,}以及这些子集的并集,此时稳定的集合{X1,X2,X5}的集合上下近似集还是他本身,所有没有改变,说明此属性是可以约简的,然后再此基础上在约简,直到上下近似集的改变。依次3种属性进行遍历。最后得到规则,我们以约简颜色属性为例,我们可以得出的规则是大三角的稳定,圆小的不稳定等等。大体原理就是如此,也许从某些方面来说还有欠妥的地方。

算法的代码实现

同样以上面的数据未例子,不过我把他转成了英文的形式,避免中文的编码问题:

[java]  view plain copy print ?
  1. Element Color Shape Size Stability  
  2. x1 Red Triangle Large Stable  
  3. x2 Red Triangle Large Stable  
  4. x3 Yellow Circle Small UnStable  
  5. x4 Yellow Circle Small UnStable  
  6. x5 Blue Rectangle Large Stable  
  7. x6 Red Circle Middle UnStable  
  8. x7 Blue Circle Small UnStable  
  9. x8 Blue Rectangle Middle UnStable  
程序写的会有些复杂,里面很多都是集合的交并运算,之所以不采用直接的数组的运算,是为了更加突出集合的概念。
Record.java:

[java]  view plain copy print ?
  1. package DataMining_RoughSets;  
  2.   
  3. import java.text.MessageFormat;  
  4. import java.util.ArrayList;  
  5. import java.util.HashMap;  
  6. import java.util.Map;  
  7.   
  8. /** 
  9.  * 数据记录,包含这条记录所有属性 
  10.  *  
  11.  * @author lyq 
  12.  *  
  13.  */  
  14. public class Record {  
  15.     // 记录名称  
  16.     private String name;  
  17.     // 记录属性键值对  
  18.     private HashMap<String, String> attrValues;  
  19.   
  20.     public Record(String name, HashMap<String, String> attrValues) {  
  21.         this.name = name;  
  22.         this.attrValues = attrValues;  
  23.     }  
  24.   
  25.     public String getName() {  
  26.         return this.name;  
  27.     }  
  28.   
  29.     /** 
  30.      * 此数据是否包含此属性值 
  31.      *  
  32.      * @param attr 
  33.      *            待判断属性值 
  34.      * @return 
  35.      */  
  36.     public boolean isContainedAttr(String attr) {  
  37.         boolean isContained = false;  
  38.   
  39.         if (attrValues.containsValue(attr)) {  
  40.             isContained = true;  
  41.         }  
  42.   
  43.         return isContained;  
  44.     }  
  45.   
  46.     /** 
  47.      * 判断数据记录是否是同一条记录,根据数据名称来判断 
  48.      *  
  49.      * @param record 
  50.      *            目标比较对象 
  51.      * @return 
  52.      */  
  53.     public boolean isRecordSame(Record record) {  
  54.         boolean isSame = false;  
  55.   
  56.         if (this.name.equals(record.name)) {  
  57.             isSame = true;  
  58.         }  
  59.   
  60.         return isSame;  
  61.     }  
  62.   
  63.     /** 
  64.      * 数据的决策属性分类 
  65.      *  
  66.      * @return 
  67.      */  
  68.     public String getRecordDecisionClass() {  
  69.         String value = null;  
  70.   
  71.         value = attrValues.get(RoughSetsTool.DECISION_ATTR_NAME);  
  72.   
  73.         return value;  
  74.     }  
  75.   
  76.     /** 
  77.      * 根据约简属性输出决策规则 
  78.      *  
  79.      * @param reductAttr 
  80.      *            约简属性集合 
  81.      */  
  82.     public String getDecisionRule(ArrayList<String> reductAttr) {  
  83.         String ruleStr = "";  
  84.         String attrName = null;  
  85.         String value = null;  
  86.         String decisionValue;  
  87.   
  88.         decisionValue = attrValues.get(RoughSetsTool.DECISION_ATTR_NAME);  
  89.         ruleStr += "属性";  
  90.         for (Map.Entry entry : this.attrValues.entrySet()) {  
  91.             attrName = (String) entry.getKey();  
  92.             value = (String) entry.getValue();  
  93.   
  94.             if (attrName.equals(RoughSetsTool.DECISION_ATTR_NAME)  
  95.                     || reductAttr.contains(attrName) || value.equals(name)) {  
  96.                 continue;  
  97.             }  
  98.   
  99.             ruleStr += MessageFormat.format("{0}={1},", attrName, value);  
  100.         }  
  101.         ruleStr += "他的分类为" + decisionValue;  
  102.           
  103.         return ruleStr;  
  104.     }  
  105. }  

RecordCollection.java:

[java]  view plain copy print ?
  1. package DataMining_RoughSets;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. /** 
  8.  * 数据记录集合,包含一些共同的属性 
  9.  *  
  10.  * @author lyq 
  11.  *  
  12.  */  
  13. public class RecordCollection {  
  14.     // 集合包含的属性  
  15.     private HashMap<String, String> attrValues;  
  16.     // 数据记录列表  
  17.     private ArrayList<Record> recordList;  
  18.   
  19.     public RecordCollection() {  
  20.         this.attrValues = new HashMap<>();  
  21.         this.recordList = new ArrayList<>();  
  22.     }  
  23.   
  24.     public RecordCollection(HashMap<String, String> attrValues,  
  25.             ArrayList<Record> recordList) {  
  26.         this.attrValues = attrValues;  
  27.         this.recordList = recordList;  
  28.     }  
  29.   
  30.     public ArrayList<Record> getRecord() {  
  31.         return this.recordList;  
  32.     }  
  33.   
  34.     /** 
  35.      * 返回集合的字符名称数组 
  36.      *  
  37.      * @return 
  38.      */  
  39.     public ArrayList<String> getRecordNames() {  
  40.         ArrayList<String> names = new ArrayList<>();  
  41.   
  42.         for (int i = 0; i < recordList.size(); i++) {  
  43.             names.add(recordList.get(i).getName());  
  44.         }  
  45.   
  46.         return names;  
  47.     }  
  48.   
  49.     /** 
  50.      * 判断集合是否包含此属性名称对应的属性值 
  51.      *  
  52.      * @param attrName 
  53.      *            属性名 
  54.      * @return 
  55.      */  
  56.     public boolean isContainedAttrName(String attrName) {  
  57.         boolean isContained = false;  
  58.   
  59.         if (this.attrValues.containsKey(attrName)) {  
  60.             isContained = true;  
  61.         }  
  62.   
  63.         return isContained;  
  64.     }  
  65.   
  66.     /** 
  67.      * 判断2个集合是否相等,比较包含的数据记录是否完全一致 
  68.      *  
  69.      * @param rc 
  70.      *            待比较集合 
  71.      * @return 
  72.      */  
  73.     public boolean isCollectionSame(RecordCollection rc) {  
  74.         boolean isSame = false;  
  75.   
  76.         for (Record r : recordList) {  
  77.             isSame = false;  
  78.   
  79.             for (Record r2 : rc.recordList) {  
  80.                 if (r.isRecordSame(r2)) {  
  81.                     isSame = true;  
  82.                     break;  
  83.                 }  
  84.             }  
  85.   
  86.             // 如果有1个记录不包含,就算集合不相等  
  87.             if (!isSame) {  
  88.                 break;  
  89.             }  
  90.         }  
  91.   
  92.         return isSame;  
  93.     }  
  94.   
  95.     /** 
  96.      * 集合之间的交运算 
  97.      *  
  98.      * @param rc 
  99.      *            交运算的参与运算的另外一集合 
  100.      * @return 
  101.      */  
  102.     public RecordCollection overlapCalculate(RecordCollection rc) {  
  103.         String key;  
  104.         String value;  
  105.         RecordCollection resultCollection = null;  
  106.         HashMap<String, String> resultAttrValues = new HashMap<>();  
  107.         ArrayList<Record> resultRecords = new ArrayList<>();  
  108.   
  109.         // 进行集合的交运算,有相同的记录的则进行添加  
  110.         for (Record record : this.recordList) {  
  111.             for (Record record2 : rc.recordList) {  
  112.                 if (record.isRecordSame(record2)) {  
  113.                     resultRecords.add(record);  
  114.                     break;  
  115.                 }  
  116.             }  
  117.         }  
  118.   
  119.         // 如果没有交集,则直接返回  
  120.         if (resultRecords.size() == 0) {  
  121.             return null;  
  122.         }  
  123.   
  124.         // 将2个集合的属性进行合并  
  125.         for (Map.Entry entry : this.attrValues.entrySet()) {  
  126.             key = (String) entry.getKey();  
  127.             value = (String) entry.getValue();  
  128.   
  129.             resultAttrValues.put(key, value);  
  130.         }  
  131.   
  132.         for (Map.Entry entry : rc.attrValues.entrySet()) {  
  133.             key = (String) entry.getKey();  
  134.             value = (String) entry.getValue();  
  135.   
  136.             resultAttrValues.put(key, value);  
  137.         }  
  138.   
  139.         resultCollection = new RecordCollection(resultAttrValues, resultRecords);  
  140.         return resultCollection;  
  141.     }  
  142.   
  143.     /** 
  144.      * 求集合的并集,各自保留各自的属性 
  145.      *  
  146.      * @param rc 
  147.      *            待合并的集合 
  148.      * @return 
  149.      */  
  150.     public RecordCollection unionCal(RecordCollection rc) {  
  151.         RecordCollection resultRc = null;  
  152.         ArrayList<Record> records = new ArrayList<>();  
  153.   
  154.         for (Record r1 : this.recordList) {  
  155.             records.add(r1);  
  156.         }  
  157.   
  158.         for (Record r2 : rc.recordList) {  
  159.             records.add(r2);  
  160.         }  
  161.   
  162.         resultRc = new RecordCollection(null, records);  
  163.         return resultRc;  
  164.     }  
  165.       
  166.     /** 
  167.      * 输出集合中包含的元素 
  168.      */  
  169.     public void printRc(){  
  170.         System.out.print("{");  
  171.         for (Record r : this.getRecord()) {  
  172.             System.out.print(r.getName() + ", ");  
  173.         }  
  174.         System.out.println("}");  
  175.     }  
  176. }  

KnowledgeSystem.java:

[java]  view plain copy print ?
  1. package DataMining_RoughSets;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5.   
  6. /** 
  7.  * 知识系统 
  8.  *  
  9.  * @author lyq 
  10.  *  
  11.  */  
  12. public class KnowledgeSystem {  
  13.     // 知识系统内的集合  
  14.     ArrayList<RecordCollection> ksCollections;  
  15.   
  16.     public KnowledgeSystem(ArrayList<RecordCollection> ksCollections) {  
  17.         this.ksCollections = ksCollections;  
  18.     }  
  19.   
  20.     /** 
  21.      * 获取集合的上近似集合 
  22.      *  
  23.      * @param rc 
  24.      *            原始集合 
  25.      * @return 
  26.      */  
  27.     public RecordCollection getUpSimilarRC(RecordCollection rc) {  
  28.         RecordCollection resultRc = null;  
  29.         ArrayList<String> nameArray;  
  30.         ArrayList<String> targetArray;  
  31.         ArrayList<RecordCollection> copyRcs = new ArrayList<>();  
  32.         ArrayList<RecordCollection> deleteRcs = new ArrayList<>();  
  33.         targetArray = rc.getRecordNames();  
  34.   
  35.         // 做一个集合拷贝  
  36.         for (RecordCollection recordCollection : ksCollections) {  
  37.             copyRcs.add(recordCollection);  
  38.         }  
  39.   
  40.         for (RecordCollection recordCollection : copyRcs) {  
  41.             nameArray = recordCollection.getRecordNames();  
  42.   
  43.             if (strIsContained(targetArray, nameArray)) {  
  44.                 removeOverLaped(targetArray, nameArray);  
  45.                 deleteRcs.add(recordCollection);  
  46.   
  47.                 if (resultRc == null) {  
  48.                     resultRc = recordCollection;  
  49.                 } else {  
  50.                     // 进行并运算  
  51.                     resultRc = resultRc.unionCal(recordCollection);  
  52.                 }  
  53.   
  54.                 if (targetArray.size() == 0) {  
  55.                     break;  
  56.                 }  
  57.             }  
  58.         }  
  59.         //去除已经添加过的集合  
  60.         copyRcs.removeAll(deleteRcs);  
  61.   
  62.         if (targetArray.size() > 0) {  
  63.             // 说明已经完全还未找全上近似的集合  
  64.             for (RecordCollection recordCollection : copyRcs) {  
  65.                 nameArray = recordCollection.getRecordNames();  
  66.   
  67.                 if (strHasOverlap(targetArray, nameArray)) {  
  68.                     removeOverLaped(targetArray, nameArray);  
  69.   
  70.                     if (resultRc == null) {  
  71.                         resultRc = recordCollection;  
  72.                     } else {  
  73.                         // 进行并运算  
  74.                         resultRc = resultRc.unionCal(recordCollection);  
  75.                     }  
  76.   
  77.                     if (targetArray.size() == 0) {  
  78.                         break;  
  79.                     }  
  80.                 }  
  81.             }  
  82.         }  
  83.   
  84.         return resultRc;  
  85.     }  
  86.   
  87.     /** 
  88.      * 获取集合的下近似集合 
  89.      *  
  90.      * @param rc 
  91.      *            原始集合 
  92.      * @return 
  93.      */  
  94.     public RecordCollection getDownSimilarRC(RecordCollection rc) {  
  95.         RecordCollection resultRc = null;  
  96.         ArrayList<String> nameArray;  
  97.         ArrayList<String> targetArray;  
  98.         targetArray = rc.getRecordNames();  
  99.   
  100.         for (RecordCollection recordCollection : ksCollections) {  
  101.             nameArray = recordCollection.getRecordNames();  
  102.   
  103.             if (strIsContained(targetArray, nameArray)) {  
  104.                 removeOverLaped(targetArray, nameArray);  
  105.   
  106.                 if (resultRc == null) {  
  107.                     resultRc = recordCollection;  
  108.                 } else {  
  109.                     // 进行并运算  
  110.                     resultRc = resultRc.unionCal(recordCollection);  
  111.                 }  
  112.   
  113.                 if (targetArray.size() == 0) {  
  114.                     break;  
  115.                 }  
  116.             }  
  117.         }  
  118.   
  119.         return resultRc;  
  120.     }  
  121.   
  122.     /** 
  123.      * 判断2个字符数组之间是否有交集 
  124.      *  
  125.      * @param str1 
  126.      *            字符列表1 
  127.      * @param str2 
  128.      *            字符列表2 
  129.      * @return 
  130.      */  
  131.     public boolean strHasOverlap(ArrayList<String> str1, ArrayList<String> str2) {  
  132.         boolean hasOverlap = false;  
  133.   
  134.         for (String s1 : str1) {  
  135.             for (String s2 : str2) {  
  136.                 if (s1.equals(s2)) {  
  137.                     hasOverlap = true;  
  138.                     break;  
  139.                 }  
  140.             }  
  141.   
  142.             if (hasOverlap) {  
  143.                 break;  
  144.             }  
  145.         }  
  146.   
  147.         return hasOverlap;  
  148.     }  
  149.   
  150.     /** 
  151.      * 判断字符集str2是否完全包含于str1中 
  152.      *  
  153.      * @param str1 
  154.      * @param str2 
  155.      * @return 
  156.      */  
  157.     public boolean strIsContained(ArrayList<String> str1, ArrayList<String> str2) {  
  158.         boolean isContained = false;  
  159.         int count = 0;  
  160.   
  161.         for (String s : str2) {  
  162.             if (str1.contains(s)) {  
  163.                 count++;  
  164.             }  
  165.         }  
  166.   
  167.         if (count == str2.size()) {  
  168.             isContained = true;  
  169.         }  
  170.   
  171.         return isContained;  
  172.     }  
  173.   
  174.     /** 
  175.      * 字符列表移除公共元素 
  176.      *  
  177.      * @param str1 
  178.      * @param str2 
  179.      */  
  180.     public void removeOverLaped(ArrayList<String> str1, ArrayList<String> str2) {  
  181.         ArrayList<String> deleteStrs = new ArrayList<>();  
  182.   
  183.         for (String s1 : str1) {  
  184.             for (String s2 : str2) {  
  185.                 if (s1.equals(s2)) {  
  186.                     deleteStrs.add(s1);  
  187.                     break;  
  188.                 }  
  189.             }  
  190.         }  
  191.   
  192.         // 进行公共元素的移除  
  193.         str1.removeAll(deleteStrs);  
  194.     }  
  195. }  
RoughSetsTool.java:

[java]  view plain copy print ?
  1. package DataMining_RoughSets;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.File;  
  5. import java.io.FileReader;  
  6. import java.io.IOException;  
  7. import java.util.ArrayList;  
  8. import java.util.HashMap;  
  9. import java.util.Map;  
  10.   
  11. /** 
  12.  * 粗糙集属性约简算法工具类 
  13.  *  
  14.  * @author lyq 
  15.  *  
  16.  */  
  17. public class RoughSetsTool {  
  18.     // 决策属性名称  
  19.     public static String DECISION_ATTR_NAME;  
  20.   
  21.     // 测试数据文件地址  
  22.     private String filePath;  
  23.     // 数据属性列名称  
  24.     private String[] attrNames;  
  25.     // 所有的数据  
  26.     private ArrayList<String[]> totalDatas;  
  27.     // 所有的数据记录,与上面的区别是记录的属性是可约简的,原始数据是不能变的  
  28.     private ArrayList<Record> totalRecords;  
  29.     // 条件属性图  
  30.     private HashMap<String, ArrayList<String>> conditionAttr;  
  31.     // 属性记录集合  
  32.     private ArrayList<RecordCollection> collectionList;  
  33.   
  34.     public RoughSetsTool(String filePath) {  
  35.         this.filePath = filePath;  
  36.         readDataFile();  
  37.     }  
  38.   
  39.     /** 
  40.      * 从文件中读取数据 
  41.      */  
  42.     private void readDataFile() {  
  43.         File file = new File(filePath);  
  44.         ArrayList<String[]> dataArray = new ArrayList<String[]>();  
  45.   
  46.         try {  
  47.             BufferedReader in = new BufferedReader(new FileReader(file));  
  48.             String str;  
  49.             String[] tempArray;  
  50.             while ((str = in.readLine()) != null) {  
  51.                 tempArray = str.split(" ");  
  52.                 dataArray.add(tempArray);  
  53.             }  
  54.             in.close();  
  55.         } catch (IOException e) {  
  56.             e.getStackTrace();  
  57.         }  
  58.   
  59.         String[] array;  
  60.         Record tempRecord;  
  61.         HashMap<String, String> attrMap;  
  62.         ArrayList<String> attrList;  
  63.         totalDatas = new ArrayList<>();  
  64.         totalRecords = new ArrayList<>();  
  65.         conditionAttr = new HashMap<>();  
  66.         // 赋值属性名称行  
  67.         attrNames = dataArray.get(0);  
  68.         DECISION_ATTR_NAME = attrNames[attrNames.length - 1];  
  69.         for (int j = 0; j < dataArray.size(); j++) {  
  70.             array = dataArray.get(j);  
  71.             totalDatas.add(array);  
  72.             if (j == 0) {  
  73.                 // 过滤掉第一行列名称数据  
  74.                 continue;  
  75.             }  
  76.   
  77.             attrMap = new HashMap<>();  
  78.             for (int i = 0; i < attrNames.length; i++) {  
  79.                 attrMap.put(attrNames[i], array[i]);  
  80.   
  81.                 // 寻找条件属性  
  82.                 if (i > 0 && i < attrNames.length - 1) {  
  83.                     if (conditionAttr.containsKey(attrNames[i])) {  
  84.                         attrList = conditionAttr.get(attrNames[i]);  
  85.                         if (!attrList.contains(array[i])) {  
  86.                             attrList.add(array[i]);  
  87.                         }  
  88.                     } else {  
  89.                         attrList = new ArrayList<>();  
  90.                         attrList.add(array[i]);  
  91.                     }  
  92.                     conditionAttr.put(attrNames[i], attrList);  
  93.                 }  
  94.             }  
  95.             tempRecord = new Record(array[0], attrMap);  
  96.             totalRecords.add(tempRecord);  
  97.         }  
  98.     }  
  99.   
  100.     /** 
  101.      * 将数据记录根据属性分割到集合中 
  102.      */  
  103.     private void recordSpiltToCollection() {  
  104.         String attrName;  
  105.         ArrayList<String> attrList;  
  106.         ArrayList<Record> recordList;  
  107.         HashMap<String, String> collectionAttrValues;  
  108.         RecordCollection collection;  
  109.         collectionList = new ArrayList<>();  
  110.   
  111.         for (Map.Entry entry : conditionAttr.entrySet()) {  
  112.             attrName = (String) entry.getKey();  
  113.             attrList = (ArrayList<String>) entry.getValue();  
  114.   
  115.             for (String s : attrList) {  
  116.                 recordList = new ArrayList<>();  
  117.                 // 寻找属性为s的数据记录分入到集合中  
  118.                 for (Record record : totalRecords) {  
  119.                     if (record.isContainedAttr(s)) {  
  120.                         recordList.add(record);  
  121.                     }  
  122.                 }  
  123.                 collectionAttrValues = new HashMap<>();  
  124.                 collectionAttrValues.put(attrName, s);  
  125.                 collection = new RecordCollection(collectionAttrValues,  
  126.                         recordList);  
  127.   
  128.                 collectionList.add(collection);  
  129.             }  
  130.         }  
  131.     }  
  132.   
  133.     /** 
  134.      * 构造属性集合图 
  135.      *  
  136.      * @param reductAttr 
  137.      *            需要约简的属性 
  138.      * @return 
  139.      */  
  140.     private HashMap<String, ArrayList<RecordCollection>> constructCollectionMap(  
  141.             ArrayList<String> reductAttr) {  
  142.         String currentAtttrName;  
  143.         ArrayList<RecordCollection> cList;  
  144.         // 集合属性对应图  
  145.         HashMap<String, ArrayList<RecordCollection>> collectionMap = new HashMap<>();  
  146.   
  147.         // 截取出条件属性部分  
  148.         for (int i = 1; i < attrNames.length - 1; i++) {  
  149.             currentAtttrName = attrNames[i];  
  150.   
  151.             // 判断此属性列是否需要约简  
  152.             if (reductAttr != null && reductAttr.contains(currentAtttrName)) {  
  153.                 continue;  
  154.             }  
  155.   
  156.             cList = new ArrayList<>();  
  157.   
  158.             for (RecordCollection c : collectionList) {  
  159.                 if (c.isContainedAttrName(currentAtttrName)) {  
  160.                     cList.add(c);  
  161.                 }  
  162.             }  
  163.   
  164.             collectionMap.put(currentAtttrName, cList);  
  165.         }  
  166.   
  167.         return collectionMap;  
  168.     }  
  169.   
  170.     /** 
  171.      * 根据已有的分裂集合计算知识系统 
  172.      */  
  173.     private ArrayList<RecordCollection> computeKnowledgeSystem(  
  174.             HashMap<String, ArrayList<RecordCollection>> collectionMap) {  
  175.         String attrName = null;  
  176.         ArrayList<RecordCollection> cList = null;  
  177.         // 知识系统  
  178.         ArrayList<RecordCollection> ksCollections;  
  179.   
  180.         ksCollections = new ArrayList<>();  
  181.   
  182.         // 取出1项  
  183.         for (Map.Entry entry : collectionMap.entrySet()) {  
  184.             attrName = (String) entry.getKey();  
  185.             cList = (ArrayList<RecordCollection>) entry.getValue();  
  186.             break;  
  187.         }  
  188.         collectionMap.remove(attrName);  
  189.   
  190.         for (RecordCollection rc : cList) {  
  191.             recurrenceComputeKS(ksCollections, collectionMap, rc);  
  192.         }  
  193.   
  194.         return ksCollections;  
  195.     }  
  196.   
  197.     /** 
  198.      * 递归计算所有的知识系统,通过计算所有集合的交集 
  199.      *  
  200.      * @param ksCollection 
  201.      *            已经求得知识系统的集合 
  202.      * @param map 
  203.      *            还未曾进行过交运算的集合 
  204.      * @param preCollection 
  205.      *            前个步骤中已经通过交运算计算出的集合 
  206.      */  
  207.     private void recurrenceComputeKS(ArrayList<RecordCollection> ksCollections,  
  208.             HashMap<String, ArrayList<RecordCollection>> map,  
  209.             RecordCollection preCollection) {  
  210.         String attrName = null;  
  211.         RecordCollection tempCollection;  
  212.         ArrayList<RecordCollection> cList = null;  
  213.         HashMap<String, ArrayList<RecordCollection>> mapCopy = new HashMap<>();  
  214.           
  215.         //如果已经没有数据了,则直接添加  
  216.         if(map.size() == 0){  
  217.             ksCollections.add(preCollection);  
  218.             return;  
  219.         }  
  220.   
  221.         for (Map.Entry entry : map.entrySet()) {  
  222.             cList = (ArrayList<RecordCollection>) entry.getValue();  
  223.             mapCopy.put((String) entry.getKey(), cList);  
  224.         }  
  225.   
  226.         // 取出1项  
  227.         for (Map.Entry entry : map.entrySet()) {  
  228.             attrName = (String) entry.getKey();  
  229.             cList = (ArrayList<RecordCollection>) entry.getValue();  
  230.             break;  
  231.         }  
  232.   
  233.         mapCopy.remove(attrName);  
  234.         for (RecordCollection rc : cList) {  
  235.             // 挑选此属性的一个集合进行交运算,然后再次递归  
  236.             tempCollection = preCollection.overlapCalculate(rc);  
  237.   
  238.             if (tempCollection == null) {  
  239.                 continue;  
  240.             }  
  241.   
  242.             // 如果map中已经没有数据了,说明递归到头了  
  243.             if (mapCopy.size() == 0) {  
  244.                 ksCollections.add(tempCollection);  
  245.             } else {  
  246.                 recurrenceComputeKS(ksCollections, mapCopy, tempCollection);  
  247.             }  
  248.         }  
  249.     }  
  250.   
  251.     /** 
  252.      * 进行粗糙集属性约简算法 
  253.      */  
  254.     public void findingReduct() {  
  255.         RecordCollection[] sameClassRcs;  
  256.         KnowledgeSystem ks;  
  257.         ArrayList<RecordCollection> ksCollections;  
  258.         // 待约简的属性  
  259.         ArrayList<String> reductAttr = null;  
  260.         ArrayList<String> attrNameList;  
  261.         // 最终可约简的属性组  
  262.         ArrayList<ArrayList<String>> canReductAttrs;  
  263.         HashMap<String, ArrayList<RecordCollection>> collectionMap;  
  264.   
  265.         sameClassRcs = selectTheSameClassRC();  
  266.         // 这里讲数据按照各个分类的小属性划分了9个集合  
  267.         recordSpiltToCollection();  
  268.   
  269.         collectionMap = constructCollectionMap(reductAttr);  
  270.         ksCollections = computeKnowledgeSystem(collectionMap);  
  271.         ks = new KnowledgeSystem(ksCollections);  
  272.         System.out.println("原始集合分类的上下近似集合");  
  273.         ks.getDownSimilarRC(sameClassRcs[0]).printRc();  
  274.         ks.getUpSimilarRC(sameClassRcs[0]).printRc();  
  275.         ks.getDownSimilarRC(sameClassRcs[1]).printRc();  
  276.         ks.getUpSimilarRC(sameClassRcs[1]).printRc();  
  277.   
  278.         attrNameList = new ArrayList<>();  
  279.         for (int i = 1; i < attrNames.length - 1; i++) {  
  280.             attrNameList.add(attrNames[i]);  
  281.         }  
  282.   
  283.         ArrayList<String> remainAttr;  
  284.         canReductAttrs = new ArrayList<>();  
  285.         reductAttr = new ArrayList<>();  
  286.         // 进行条件属性的递归约简  
  287.         for (String s : attrNameList) {  
  288.             remainAttr = (ArrayList<String>) attrNameList.clone();  
  289.             remainAttr.remove(s);  
  290.             reductAttr = new ArrayList<>();  
  291.             reductAttr.add(s);  
  292.             recurrenceFindingReduct(canReductAttrs, reductAttr, remainAttr,  
  293.                     sameClassRcs);  
  294.         }  
  295.           
  296.         printRules(canReductAttrs);  
  297.     }  
  298.   
  299.     /** 
  300.      * 递归进行属性约简 
  301.      *  
  302.      * @param resultAttr 
  303.      *            已经计算出的约简属性组 
  304.      * @param reductAttr 
  305.      *            将要约简的属性组 
  306.      * @param remainAttr 
  307.      *            剩余的属性 
  308.      * @param sameClassRc 
  309.      *            待计算上下近似集合的同类集合 
  310.      */  
  311.     private void recurrenceFindingReduct(  
  312.             ArrayList<ArrayList<String>> resultAttr,  
  313.             ArrayList<String> reductAttr, ArrayList<String> remainAttr,  
  314.             RecordCollection[] sameClassRc) {  
  315.         KnowledgeSystem ks;  
  316.         ArrayList<RecordCollection> ksCollections;  
  317.         ArrayList<String> copyRemainAttr;  
  318.         ArrayList<String> copyReductAttr;  
  319.         HashMap<String, ArrayList<RecordCollection>> collectionMap;  
  320.         RecordCollection upRc1;  
  321.         RecordCollection downRc1;  
  322.         RecordCollection upRc2;  
  323.         RecordCollection downRc2;  
  324.   
  325.         collectionMap = constructCollectionMap(reductAttr);  
  326.         ksCollections = computeKnowledgeSystem(collectionMap);  
  327.         ks = new KnowledgeSystem(ksCollections);  
  328.           
  329.         downRc1 = ks.getDownSimilarRC(sameClassRc[0]);  
  330.         upRc1 = ks.getUpSimilarRC(sameClassRc[0]);  
  331.         downRc2 = ks.getDownSimilarRC(sameClassRc[1]);  
  332.         upRc2 = ks.getUpSimilarRC(sameClassRc[1]);  
  333.   
  334.         // 如果上下近似没有完全拟合原集合则认为属性不能被约简  
  335.         if (!upRc1.isCollectionSame(sameClassRc[0])  
  336.                 || !downRc1.isCollectionSame(sameClassRc[0])) {  
  337.             return;  
  338.         }  
  339.         //正类和负类都需比较  
  340.         if (!upRc2.isCollectionSame(sameClassRc[1])  
  341.                 || !downRc2.isCollectionSame(sameClassRc[1])) {  
  342.             return;  
  343.         }  
  344.   
  345.         // 加入到结果集中  
  346.         resultAttr.add(reductAttr);  
  347.         //只剩下1个属性不能再约简  
  348.         if (remainAttr.size() == 1) {  
  349.             return;  
  350.         }  
  351.   
  352.         for (String s : remainAttr) {  
  353.             copyRemainAttr = (ArrayList<String>) remainAttr.clone();  
  354.             copyReductAttr = (ArrayList<String>) reductAttr.clone();  
  355.             copyRemainAttr.remove(s);  
  356.             copyReductAttr.add(s);  
  357.             recurrenceFindingReduct(resultAttr, copyReductAttr, copyRemainAttr,  
  358.                     sameClassRc);  
  359.         }  
  360.     }  
  361.   
  362.     /** 
  363.      * 选出决策属性一致的集合 
  364.      *  
  365.      * @return 
  366.      */  
  367.     private RecordCollection[] selectTheSameClassRC() {  
  368.         RecordCollection[] resultRc = new RecordCollection[2];  
  369.         resultRc[0] = new RecordCollection();  
  370.         resultRc[1] = new RecordCollection();  
  371.         String attrValue;  
  372.   
  373.         // 找出第一个记录的决策属性作为一个分类  
  374.         attrValue = totalRecords.get(0).getRecordDecisionClass();  
  375.         for (Record r : totalRecords) {  
  376.             if (attrValue.equals(r.getRecordDecisionClass())) {  
  377.                 resultRc[0].getRecord().add(r);  
  378.             }else{  
  379.                 resultRc[1].getRecord().add(r);  
  380.             }  
  381.         }  
  382.   
  383.         return resultRc;  
  384.     }  
  385.       
  386.     /** 
  387.      * 输出决策规则 
  388.      * @param reductAttrArray 
  389.      * 约简属性组 
  390.      */  
  391.     public void printRules(ArrayList<ArrayList<String>> reductAttrArray){  
  392.         //用来保存已经描述过的规则,避免重复输出  
  393.         ArrayList<String> rulesArray;  
  394.         String rule;  
  395.           
  396.         for(ArrayList<String> ra: reductAttrArray){  
  397.             rulesArray = new ArrayList<>();  
  398.             System.out.print("约简的属性:");  
  399.             for(String s: ra){  
  400.                 System.out.print(s + ",");  
  401.             }  
  402.             System.out.println();  
  403.               
  404.             for(Record r: totalRecords){  
  405.                 rule = r.getDecisionRule(ra);  
  406.                 if(!rulesArray.contains(rule)){  
  407.                     rulesArray.add(rule);  
  408.                     System.out.println(rule);  
  409.                 }  
  410.             }  
  411.             System.out.println();  
  412.         }   
  413.     }  
  414.   
  415.     /** 
  416.      * 输出记录集合 
  417.      *  
  418.      * @param rcList 
  419.      *            待输出记录集合 
  420.      */  
  421.     public void printRecordCollectionList(ArrayList<RecordCollection> rcList) {  
  422.         for (RecordCollection rc : rcList) {  
  423.             System.out.print("{");  
  424.             for (Record r : rc.getRecord()) {  
  425.                 System.out.print(r.getName() + ", ");  
  426.             }  
  427.             System.out.println("}");  
  428.         }  
  429.     }  
  430. }  
调用类Client.java:

[java]  view plain copy print ?
  1. package DataMining_RoughSets;  
  2.   
  3. /** 
  4.  * 粗糙集约简算法 
  5.  * @author lyq 
  6.  * 
  7.  */  
  8. public class Client {  
  9.     public static void main(String[] args){  
  10.         String filePath = "C:\\Users\\lyq\\Desktop\\icon\\input.txt";  
  11.           
  12.         RoughSetsTool tool = new RoughSetsTool(filePath);  
  13.         tool.findingReduct();  
  14.     }  
  15. }  

结果输出:

[java]  view plain copy print ?
  1. 原始集合分类的上下近似集合  
  2. {x1, x2, x5, }  
  3. {x1, x2, x5, }  
  4. {x3, x4, x7, x6, x8, }  
  5. {x3, x4, x7, x6, x8, }  
  6. 约简的属性:Color,  
  7. 属性Shape=Triangle,Size=Large,他的分类为Stable  
  8. 属性Shape=Circle,Size=Small,他的分类为UnStable  
  9. 属性Shape=Rectangle,Size=Large,他的分类为Stable  
  10. 属性Shape=Circle,Size=Middle,他的分类为UnStable  
  11. 属性Shape=Rectangle,Size=Middle,他的分类为UnStable  
  12.   
  13. 约简的属性:Color,Shape,  
  14. 属性Size=Large,他的分类为Stable  
  15. 属性Size=Small,他的分类为UnStable  
  16. 属性Size=Middle,他的分类为UnStable  
  17.   
  18. 约简的属性:Shape,  
  19. 属性Size=Large,Color=Red,他的分类为Stable  
  20. 属性Size=Small,Color=Yellow,他的分类为UnStable  
  21. 属性Size=Large,Color=Blue,他的分类为Stable  
  22. 属性Size=Middle,Color=Red,他的分类为UnStable  
  23. 属性Size=Small,Color=Blue,他的分类为UnStable  
  24. 属性Size=Middle,Color=Blue,他的分类为UnStable  
  25.   
  26. 约简的属性:Shape,Color,  
  27. 属性Size=Large,他的分类为Stable  
  28. 属性Size=Small,他的分类为UnStable  
  29. 属性Size=Middle,他的分类为UnStable  

算法的小问题

我在算法实现时很大的问题到不是碰到很多,就是对于上下近似集的计算上自己做了一个修改,下近似集就是知识系统中的集合完全包括在目标集合的目标,而上近似则是在下近似集的基础上添加目标集合中还没有被包含进集合的元素的所属集合,跟题目原先设想的还是有一点点的不一样,但是算法整体思想还是呈现出来了。

我对算法的思考

粗糙集属性约简算法重在约简,至于用什么原则作为约简的标准,其实本身不止一种,当然你可以根本不需要用上下近似集的概念,这样确实使得验证变得非常的繁琐,你可以直接一条条的记录去约简属性,看会不会对分类的最终结果造成影响,然后做出判断,通过对决策影响的判断也仅仅是一种属性约简的情况。

算法的适用情况

RoughSets算法在属性集比较少的情况下能得到一个不错的分类的,也可以降低存储开销,但是属性集比较多的时候,可能准确率无法保证。

你可能感兴趣的:(RoughSets属性约简算法)