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种属性进行遍历。最后得到规则,我们以约简颜色属性为例,我们可以得出的规则是大三角的稳定,圆小的不稳定等等。大体原理就是如此,也许从某些方面来说还有欠妥的地方。

算法的代码实现

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

Element Color Shape Size Stability
x1 Red Triangle Large Stable
x2 Red Triangle Large Stable
x3 Yellow Circle Small UnStable
x4 Yellow Circle Small UnStable
x5 Blue Rectangle Large Stable
x6 Red Circle Middle UnStable
x7 Blue Circle Small UnStable
x8 Blue Rectangle Middle UnStable

程序写的会有些复杂,里面很多都是集合的交并运算,之所以不采用直接的数组的运算,是为了更加突出集合的概念。

Record.java:

package DataMining_RoughSets;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 数据记录,包含这条记录所有属性
 *
 * @author lyq
 *
 */
public class Record {
	// 记录名称
	private String name;
	// 记录属性键值对
	private HashMap<String, String> attrValues;

	public Record(String name, HashMap<String, String> attrValues) {
		this.name = name;
		this.attrValues = attrValues;
	}

	public String getName() {
		return this.name;
	}

	/**
	 * 此数据是否包含此属性值
	 *
	 * @param attr
	 *            待判断属性值
	 * @return
	 */
	public boolean isContainedAttr(String attr) {
		boolean isContained = false;

		if (attrValues.containsValue(attr)) {
			isContained = true;
		}

		return isContained;
	}

	/**
	 * 判断数据记录是否是同一条记录,根据数据名称来判断
	 *
	 * @param record
	 *            目标比较对象
	 * @return
	 */
	public boolean isRecordSame(Record record) {
		boolean isSame = false;

		if (this.name.equals(record.name)) {
			isSame = true;
		}

		return isSame;
	}

	/**
	 * 数据的决策属性分类
	 *
	 * @return
	 */
	public String getRecordDecisionClass() {
		String value = null;

		value = attrValues.get(RoughSetsTool.DECISION_ATTR_NAME);

		return value;
	}

	/**
	 * 根据约简属性输出决策规则
	 *
	 * @param reductAttr
	 *            约简属性集合
	 */
	public String getDecisionRule(ArrayList<String> reductAttr) {
		String ruleStr = "";
		String attrName = null;
		String value = null;
		String decisionValue;

		decisionValue = attrValues.get(RoughSetsTool.DECISION_ATTR_NAME);
		ruleStr += "属性";
		for (Map.Entry entry : this.attrValues.entrySet()) {
			attrName = (String) entry.getKey();
			value = (String) entry.getValue();

			if (attrName.equals(RoughSetsTool.DECISION_ATTR_NAME)
					|| reductAttr.contains(attrName) || value.equals(name)) {
				continue;
			}

			ruleStr += MessageFormat.format("{0}={1},", attrName, value);
		}
		ruleStr += "他的分类为" + decisionValue;

		return ruleStr;
	}
}
</pre><p></p><p><span style="color:rgb(51,51,51); font-family:arial,宋体,sans-serif; font-size:14px; line-height:24px; text-indent:28px"><span style="color:rgb(51,51,51); font-family:arial,宋体,sans-serif; font-size:14px; line-height:24px; text-indent:28px">RecordCollection.java:</span></span></p><p><span style="color:rgb(51,51,51); font-family:arial,宋体,sans-serif; font-size:14px; line-height:24px; text-indent:28px"><span style="color:rgb(51,51,51); font-family:arial,宋体,sans-serif; font-size:14px; line-height:24px; text-indent:28px"></span></span></p><pre name="code" class="java">package DataMining_RoughSets;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 数据记录集合,包含一些共同的属性
 *
 * @author lyq
 *
 */
public class RecordCollection {
	// 集合包含的属性
	private HashMap<String, String> attrValues;
	// 数据记录列表
	private ArrayList<Record> recordList;

	public RecordCollection() {
		this.attrValues = new HashMap<>();
		this.recordList = new ArrayList<>();
	}

	public RecordCollection(HashMap<String, String> attrValues,
			ArrayList<Record> recordList) {
		this.attrValues = attrValues;
		this.recordList = recordList;
	}

	public ArrayList<Record> getRecord() {
		return this.recordList;
	}

	/**
	 * 返回集合的字符名称数组
	 *
	 * @return
	 */
	public ArrayList<String> getRecordNames() {
		ArrayList<String> names = new ArrayList<>();

		for (int i = 0; i < recordList.size(); i++) {
			names.add(recordList.get(i).getName());
		}

		return names;
	}

	/**
	 * 判断集合是否包含此属性名称对应的属性值
	 *
	 * @param attrName
	 *            属性名
	 * @return
	 */
	public boolean isContainedAttrName(String attrName) {
		boolean isContained = false;

		if (this.attrValues.containsKey(attrName)) {
			isContained = true;
		}

		return isContained;
	}

	/**
	 * 判断2个集合是否相等,比较包含的数据记录是否完全一致
	 *
	 * @param rc
	 *            待比较集合
	 * @return
	 */
	public boolean isCollectionSame(RecordCollection rc) {
		boolean isSame = false;

		for (Record r : recordList) {
			isSame = false;

			for (Record r2 : rc.recordList) {
				if (r.isRecordSame(r2)) {
					isSame = true;
					break;
				}
			}

			// 如果有1个记录不包含,就算集合不相等
			if (!isSame) {
				break;
			}
		}

		return isSame;
	}

	/**
	 * 集合之间的交运算
	 *
	 * @param rc
	 *            交运算的参与运算的另外一集合
	 * @return
	 */
	public RecordCollection overlapCalculate(RecordCollection rc) {
		String key;
		String value;
		RecordCollection resultCollection = null;
		HashMap<String, String> resultAttrValues = new HashMap<>();
		ArrayList<Record> resultRecords = new ArrayList<>();

		// 进行集合的交运算,有相同的记录的则进行添加
		for (Record record : this.recordList) {
			for (Record record2 : rc.recordList) {
				if (record.isRecordSame(record2)) {
					resultRecords.add(record);
					break;
				}
			}
		}

		// 如果没有交集,则直接返回
		if (resultRecords.size() == 0) {
			return null;
		}

		// 将2个集合的属性进行合并
		for (Map.Entry entry : this.attrValues.entrySet()) {
			key = (String) entry.getKey();
			value = (String) entry.getValue();

			resultAttrValues.put(key, value);
		}

		for (Map.Entry entry : rc.attrValues.entrySet()) {
			key = (String) entry.getKey();
			value = (String) entry.getValue();

			resultAttrValues.put(key, value);
		}

		resultCollection = new RecordCollection(resultAttrValues, resultRecords);
		return resultCollection;
	}

	/**
	 * 求集合的并集,各自保留各自的属性
	 *
	 * @param rc
	 *            待合并的集合
	 * @return
	 */
	public RecordCollection unionCal(RecordCollection rc) {
		RecordCollection resultRc = null;
		ArrayList<Record> records = new ArrayList<>();

		for (Record r1 : this.recordList) {
			records.add(r1);
		}

		for (Record r2 : rc.recordList) {
			records.add(r2);
		}

		resultRc = new RecordCollection(null, records);
		return resultRc;
	}

	/**
	 * 输出集合中包含的元素
	 */
	public void printRc(){
		System.out.print("{");
		for (Record r : this.getRecord()) {
			System.out.print(r.getName() + ", ");
		}
		System.out.println("}");
	}
}

KnowledgeSystem.java:

package DataMining_RoughSets;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * 知识系统
 *
 * @author lyq
 *
 */
public class KnowledgeSystem {
	// 知识系统内的集合
	ArrayList<RecordCollection> ksCollections;

	public KnowledgeSystem(ArrayList<RecordCollection> ksCollections) {
		this.ksCollections = ksCollections;
	}

	/**
	 * 获取集合的上近似集合
	 *
	 * @param rc
	 *            原始集合
	 * @return
	 */
	public RecordCollection getUpSimilarRC(RecordCollection rc) {
		RecordCollection resultRc = null;
		ArrayList<String> nameArray;
		ArrayList<String> targetArray;
		ArrayList<RecordCollection> copyRcs = new ArrayList<>();
		ArrayList<RecordCollection> deleteRcs = new ArrayList<>();
		targetArray = rc.getRecordNames();

		// 做一个集合拷贝
		for (RecordCollection recordCollection : ksCollections) {
			copyRcs.add(recordCollection);
		}

		for (RecordCollection recordCollection : copyRcs) {
			nameArray = recordCollection.getRecordNames();

			if (strIsContained(targetArray, nameArray)) {
				removeOverLaped(targetArray, nameArray);
				deleteRcs.add(recordCollection);

				if (resultRc == null) {
					resultRc = recordCollection;
				} else {
					// 进行并运算
					resultRc = resultRc.unionCal(recordCollection);
				}

				if (targetArray.size() == 0) {
					break;
				}
			}
		}
		//去除已经添加过的集合
		copyRcs.removeAll(deleteRcs);

		if (targetArray.size() > 0) {
			// 说明已经完全还未找全上近似的集合
			for (RecordCollection recordCollection : copyRcs) {
				nameArray = recordCollection.getRecordNames();

				if (strHasOverlap(targetArray, nameArray)) {
					removeOverLaped(targetArray, nameArray);

					if (resultRc == null) {
						resultRc = recordCollection;
					} else {
						// 进行并运算
						resultRc = resultRc.unionCal(recordCollection);
					}

					if (targetArray.size() == 0) {
						break;
					}
				}
			}
		}

		return resultRc;
	}

	/**
	 * 获取集合的下近似集合
	 *
	 * @param rc
	 *            原始集合
	 * @return
	 */
	public RecordCollection getDownSimilarRC(RecordCollection rc) {
		RecordCollection resultRc = null;
		ArrayList<String> nameArray;
		ArrayList<String> targetArray;
		targetArray = rc.getRecordNames();

		for (RecordCollection recordCollection : ksCollections) {
			nameArray = recordCollection.getRecordNames();

			if (strIsContained(targetArray, nameArray)) {
				removeOverLaped(targetArray, nameArray);

				if (resultRc == null) {
					resultRc = recordCollection;
				} else {
					// 进行并运算
					resultRc = resultRc.unionCal(recordCollection);
				}

				if (targetArray.size() == 0) {
					break;
				}
			}
		}

		return resultRc;
	}

	/**
	 * 判断2个字符数组之间是否有交集
	 *
	 * @param str1
	 *            字符列表1
	 * @param str2
	 *            字符列表2
	 * @return
	 */
	public boolean strHasOverlap(ArrayList<String> str1, ArrayList<String> str2) {
		boolean hasOverlap = false;

		for (String s1 : str1) {
			for (String s2 : str2) {
				if (s1.equals(s2)) {
					hasOverlap = true;
					break;
				}
			}

			if (hasOverlap) {
				break;
			}
		}

		return hasOverlap;
	}

	/**
	 * 判断字符集str2是否完全包含于str1中
	 *
	 * @param str1
	 * @param str2
	 * @return
	 */
	public boolean strIsContained(ArrayList<String> str1, ArrayList<String> str2) {
		boolean isContained = false;
		int count = 0;

		for (String s : str2) {
			if (str1.contains(s)) {
				count++;
			}
		}

		if (count == str2.size()) {
			isContained = true;
		}

		return isContained;
	}

	/**
	 * 字符列表移除公共元素
	 *
	 * @param str1
	 * @param str2
	 */
	public void removeOverLaped(ArrayList<String> str1, ArrayList<String> str2) {
		ArrayList<String> deleteStrs = new ArrayList<>();

		for (String s1 : str1) {
			for (String s2 : str2) {
				if (s1.equals(s2)) {
					deleteStrs.add(s1);
					break;
				}
			}
		}

		// 进行公共元素的移除
		str1.removeAll(deleteStrs);
	}
}

RoughSetsTool.java:

package DataMining_RoughSets;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 粗糙集属性约简算法工具类
 *
 * @author lyq
 *
 */
public class RoughSetsTool {
	// 决策属性名称
	public static String DECISION_ATTR_NAME;

	// 测试数据文件地址
	private String filePath;
	// 数据属性列名称
	private String[] attrNames;
	// 所有的数据
	private ArrayList<String[]> totalDatas;
	// 所有的数据记录,与上面的区别是记录的属性是可约简的,原始数据是不能变的
	private ArrayList<Record> totalRecords;
	// 条件属性图
	private HashMap<String, ArrayList<String>> conditionAttr;
	// 属性记录集合
	private ArrayList<RecordCollection> collectionList;

	public RoughSetsTool(String filePath) {
		this.filePath = filePath;
		readDataFile();
	}

	/**
	 * 从文件中读取数据
	 */
	private void readDataFile() {
		File file = new File(filePath);
		ArrayList<String[]> dataArray = new ArrayList<String[]>();

		try {
			BufferedReader in = new BufferedReader(new FileReader(file));
			String str;
			String[] tempArray;
			while ((str = in.readLine()) != null) {
				tempArray = str.split(" ");
				dataArray.add(tempArray);
			}
			in.close();
		} catch (IOException e) {
			e.getStackTrace();
		}

		String[] array;
		Record tempRecord;
		HashMap<String, String> attrMap;
		ArrayList<String> attrList;
		totalDatas = new ArrayList<>();
		totalRecords = new ArrayList<>();
		conditionAttr = new HashMap<>();
		// 赋值属性名称行
		attrNames = dataArray.get(0);
		DECISION_ATTR_NAME = attrNames[attrNames.length - 1];
		for (int j = 0; j < dataArray.size(); j++) {
			array = dataArray.get(j);
			totalDatas.add(array);
			if (j == 0) {
				// 过滤掉第一行列名称数据
				continue;
			}

			attrMap = new HashMap<>();
			for (int i = 0; i < attrNames.length; i++) {
				attrMap.put(attrNames[i], array[i]);

				// 寻找条件属性
				if (i > 0 && i < attrNames.length - 1) {
					if (conditionAttr.containsKey(attrNames[i])) {
						attrList = conditionAttr.get(attrNames[i]);
						if (!attrList.contains(array[i])) {
							attrList.add(array[i]);
						}
					} else {
						attrList = new ArrayList<>();
						attrList.add(array[i]);
					}
					conditionAttr.put(attrNames[i], attrList);
				}
			}
			tempRecord = new Record(array[0], attrMap);
			totalRecords.add(tempRecord);
		}
	}

	/**
	 * 将数据记录根据属性分割到集合中
	 */
	private void recordSpiltToCollection() {
		String attrName;
		ArrayList<String> attrList;
		ArrayList<Record> recordList;
		HashMap<String, String> collectionAttrValues;
		RecordCollection collection;
		collectionList = new ArrayList<>();

		for (Map.Entry entry : conditionAttr.entrySet()) {
			attrName = (String) entry.getKey();
			attrList = (ArrayList<String>) entry.getValue();

			for (String s : attrList) {
				recordList = new ArrayList<>();
				// 寻找属性为s的数据记录分入到集合中
				for (Record record : totalRecords) {
					if (record.isContainedAttr(s)) {
						recordList.add(record);
					}
				}
				collectionAttrValues = new HashMap<>();
				collectionAttrValues.put(attrName, s);
				collection = new RecordCollection(collectionAttrValues,
						recordList);

				collectionList.add(collection);
			}
		}
	}

	/**
	 * 构造属性集合图
	 *
	 * @param reductAttr
	 *            需要约简的属性
	 * @return
	 */
	private HashMap<String, ArrayList<RecordCollection>> constructCollectionMap(
			ArrayList<String> reductAttr) {
		String currentAtttrName;
		ArrayList<RecordCollection> cList;
		// 集合属性对应图
		HashMap<String, ArrayList<RecordCollection>> collectionMap = new HashMap<>();

		// 截取出条件属性部分
		for (int i = 1; i < attrNames.length - 1; i++) {
			currentAtttrName = attrNames[i];

			// 判断此属性列是否需要约简
			if (reductAttr != null && reductAttr.contains(currentAtttrName)) {
				continue;
			}

			cList = new ArrayList<>();

			for (RecordCollection c : collectionList) {
				if (c.isContainedAttrName(currentAtttrName)) {
					cList.add(c);
				}
			}

			collectionMap.put(currentAtttrName, cList);
		}

		return collectionMap;
	}

	/**
	 * 根据已有的分裂集合计算知识系统
	 */
	private ArrayList<RecordCollection> computeKnowledgeSystem(
			HashMap<String, ArrayList<RecordCollection>> collectionMap) {
		String attrName = null;
		ArrayList<RecordCollection> cList = null;
		// 知识系统
		ArrayList<RecordCollection> ksCollections;

		ksCollections = new ArrayList<>();

		// 取出1项
		for (Map.Entry entry : collectionMap.entrySet()) {
			attrName = (String) entry.getKey();
			cList = (ArrayList<RecordCollection>) entry.getValue();
			break;
		}
		collectionMap.remove(attrName);

		for (RecordCollection rc : cList) {
			recurrenceComputeKS(ksCollections, collectionMap, rc);
		}

		return ksCollections;
	}

	/**
	 * 递归计算所有的知识系统,通过计算所有集合的交集
	 *
	 * @param ksCollection
	 *            已经求得知识系统的集合
	 * @param map
	 *            还未曾进行过交运算的集合
	 * @param preCollection
	 *            前个步骤中已经通过交运算计算出的集合
	 */
	private void recurrenceComputeKS(ArrayList<RecordCollection> ksCollections,
			HashMap<String, ArrayList<RecordCollection>> map,
			RecordCollection preCollection) {
		String attrName = null;
		RecordCollection tempCollection;
		ArrayList<RecordCollection> cList = null;
		HashMap<String, ArrayList<RecordCollection>> mapCopy = new HashMap<>();

		//如果已经没有数据了,则直接添加
		if(map.size() == 0){
			ksCollections.add(preCollection);
			return;
		}

		for (Map.Entry entry : map.entrySet()) {
			cList = (ArrayList<RecordCollection>) entry.getValue();
			mapCopy.put((String) entry.getKey(), cList);
		}

		// 取出1项
		for (Map.Entry entry : map.entrySet()) {
			attrName = (String) entry.getKey();
			cList = (ArrayList<RecordCollection>) entry.getValue();
			break;
		}

		mapCopy.remove(attrName);
		for (RecordCollection rc : cList) {
			// 挑选此属性的一个集合进行交运算,然后再次递归
			tempCollection = preCollection.overlapCalculate(rc);

			if (tempCollection == null) {
				continue;
			}

			// 如果map中已经没有数据了,说明递归到头了
			if (mapCopy.size() == 0) {
				ksCollections.add(tempCollection);
			} else {
				recurrenceComputeKS(ksCollections, mapCopy, tempCollection);
			}
		}
	}

	/**
	 * 进行粗糙集属性约简算法
	 */
	public void findingReduct() {
		RecordCollection[] sameClassRcs;
		KnowledgeSystem ks;
		ArrayList<RecordCollection> ksCollections;
		// 待约简的属性
		ArrayList<String> reductAttr = null;
		ArrayList<String> attrNameList;
		// 最终可约简的属性组
		ArrayList<ArrayList<String>> canReductAttrs;
		HashMap<String, ArrayList<RecordCollection>> collectionMap;

		sameClassRcs = selectTheSameClassRC();
		// 这里讲数据按照各个分类的小属性划分了9个集合
		recordSpiltToCollection();

		collectionMap = constructCollectionMap(reductAttr);
		ksCollections = computeKnowledgeSystem(collectionMap);
		ks = new KnowledgeSystem(ksCollections);
		System.out.println("原始集合分类的上下近似集合");
		ks.getDownSimilarRC(sameClassRcs[0]).printRc();
		ks.getUpSimilarRC(sameClassRcs[0]).printRc();
		ks.getDownSimilarRC(sameClassRcs[1]).printRc();
		ks.getUpSimilarRC(sameClassRcs[1]).printRc();

		attrNameList = new ArrayList<>();
		for (int i = 1; i < attrNames.length - 1; i++) {
			attrNameList.add(attrNames[i]);
		}

		ArrayList<String> remainAttr;
		canReductAttrs = new ArrayList<>();
		reductAttr = new ArrayList<>();
		// 进行条件属性的递归约简
		for (String s : attrNameList) {
			remainAttr = (ArrayList<String>) attrNameList.clone();
			remainAttr.remove(s);
			reductAttr = new ArrayList<>();
			reductAttr.add(s);
			recurrenceFindingReduct(canReductAttrs, reductAttr, remainAttr,
					sameClassRcs);
		}

		printRules(canReductAttrs);
	}

	/**
	 * 递归进行属性约简
	 *
	 * @param resultAttr
	 *            已经计算出的约简属性组
	 * @param reductAttr
	 *            将要约简的属性组
	 * @param remainAttr
	 *            剩余的属性
	 * @param sameClassRc
	 *            待计算上下近似集合的同类集合
	 */
	private void recurrenceFindingReduct(
			ArrayList<ArrayList<String>> resultAttr,
			ArrayList<String> reductAttr, ArrayList<String> remainAttr,
			RecordCollection[] sameClassRc) {
		KnowledgeSystem ks;
		ArrayList<RecordCollection> ksCollections;
		ArrayList<String> copyRemainAttr;
		ArrayList<String> copyReductAttr;
		HashMap<String, ArrayList<RecordCollection>> collectionMap;
		RecordCollection upRc1;
		RecordCollection downRc1;
		RecordCollection upRc2;
		RecordCollection downRc2;

		collectionMap = constructCollectionMap(reductAttr);
		ksCollections = computeKnowledgeSystem(collectionMap);
		ks = new KnowledgeSystem(ksCollections);

		downRc1 = ks.getDownSimilarRC(sameClassRc[0]);
		upRc1 = ks.getUpSimilarRC(sameClassRc[0]);
		downRc2 = ks.getDownSimilarRC(sameClassRc[1]);
		upRc2 = ks.getUpSimilarRC(sameClassRc[1]);

		// 如果上下近似没有完全拟合原集合则认为属性不能被约简
		if (!upRc1.isCollectionSame(sameClassRc[0])
				|| !downRc1.isCollectionSame(sameClassRc[0])) {
			return;
		}
		//正类和负类都需比较
		if (!upRc2.isCollectionSame(sameClassRc[1])
				|| !downRc2.isCollectionSame(sameClassRc[1])) {
			return;
		}

		// 加入到结果集中
		resultAttr.add(reductAttr);
		//只剩下1个属性不能再约简
		if (remainAttr.size() == 1) {
			return;
		}

		for (String s : remainAttr) {
			copyRemainAttr = (ArrayList<String>) remainAttr.clone();
			copyReductAttr = (ArrayList<String>) reductAttr.clone();
			copyRemainAttr.remove(s);
			copyReductAttr.add(s);
			recurrenceFindingReduct(resultAttr, copyReductAttr, copyRemainAttr,
					sameClassRc);
		}
	}

	/**
	 * 选出决策属性一致的集合
	 *
	 * @return
	 */
	private RecordCollection[] selectTheSameClassRC() {
		RecordCollection[] resultRc = new RecordCollection[2];
		resultRc[0] = new RecordCollection();
		resultRc[1] = new RecordCollection();
		String attrValue;

		// 找出第一个记录的决策属性作为一个分类
		attrValue = totalRecords.get(0).getRecordDecisionClass();
		for (Record r : totalRecords) {
			if (attrValue.equals(r.getRecordDecisionClass())) {
				resultRc[0].getRecord().add(r);
			}else{
				resultRc[1].getRecord().add(r);
			}
		}

		return resultRc;
	}

	/**
	 * 输出决策规则
	 * @param reductAttrArray
	 * 约简属性组
	 */
	public void printRules(ArrayList<ArrayList<String>> reductAttrArray){
		//用来保存已经描述过的规则,避免重复输出
		ArrayList<String> rulesArray;
		String rule;

		for(ArrayList<String> ra: reductAttrArray){
			rulesArray = new ArrayList<>();
			System.out.print("约简的属性:");
			for(String s: ra){
				System.out.print(s + ",");
			}
			System.out.println();

			for(Record r: totalRecords){
				rule = r.getDecisionRule(ra);
				if(!rulesArray.contains(rule)){
					rulesArray.add(rule);
					System.out.println(rule);
				}
			}
			System.out.println();
		}
	}

	/**
	 * 输出记录集合
	 *
	 * @param rcList
	 *            待输出记录集合
	 */
	public void printRecordCollectionList(ArrayList<RecordCollection> rcList) {
		for (RecordCollection rc : rcList) {
			System.out.print("{");
			for (Record r : rc.getRecord()) {
				System.out.print(r.getName() + ", ");
			}
			System.out.println("}");
		}
	}
}

调用类Client.java:

package DataMining_RoughSets;

/**
 * 粗糙集约简算法
 * @author lyq
 *
 */
public class Client {
	public static void main(String[] args){
		String filePath = "C:\\Users\\lyq\\Desktop\\icon\\input.txt";

		RoughSetsTool tool = new RoughSetsTool(filePath);
		tool.findingReduct();
	}
}

结果输出:

原始集合分类的上下近似集合
{x1, x2, x5, }
{x1, x2, x5, }
{x3, x4, x7, x6, x8, }
{x3, x4, x7, x6, x8, }
约简的属性:Color,
属性Shape=Triangle,Size=Large,他的分类为Stable
属性Shape=Circle,Size=Small,他的分类为UnStable
属性Shape=Rectangle,Size=Large,他的分类为Stable
属性Shape=Circle,Size=Middle,他的分类为UnStable
属性Shape=Rectangle,Size=Middle,他的分类为UnStable

约简的属性:Color,Shape,
属性Size=Large,他的分类为Stable
属性Size=Small,他的分类为UnStable
属性Size=Middle,他的分类为UnStable

约简的属性:Shape,
属性Size=Large,Color=Red,他的分类为Stable
属性Size=Small,Color=Yellow,他的分类为UnStable
属性Size=Large,Color=Blue,他的分类为Stable
属性Size=Middle,Color=Red,他的分类为UnStable
属性Size=Small,Color=Blue,他的分类为UnStable
属性Size=Middle,Color=Blue,他的分类为UnStable

约简的属性:Shape,Color,
属性Size=Large,他的分类为Stable
属性Size=Small,他的分类为UnStable
属性Size=Middle,他的分类为UnStable

算法的小问题

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

我对算法的思考

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

算法的适用情况

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

时间: 2024-10-18 19:13:57

RoughSets属性约简算法的相关文章

【机器学习】粗糙集属性约简算法与mRMR算法的本质区别

1. 粗糙集属性约简算法仅仅选出属性重要度大的条件加入约减中,没有考虑约简中条件属性相互之间的冗余性,得到的约简往往不是都必要的,即含有冗余属性. 2. mRMR算法则除了考虑特征与类别之间的相关性,还考虑特征与特征之间的冗余度,约束特征与类别最大相关,特征与特征最小冗余. 3. 根据mRMR算法,将粗糙集约简算法改进为最小相关最大依赖度属性约简的算法如下

Android属性动画简析

简析 大家知道,我们在开发一款产品的时候为了达到良好的用户体验,我们可以在应用中适当的加上一些动画效果,譬如平移.缩放.旋转等等,但是这些常用的动画在Android很早期的版本中就存在了,我们称之为传统动画,传统动画一般分为Tween动画和Frame动画,这也是我们最常用的的动画,统称为Animation.传统的Animation动画实现上是通过不停的调用View的onDraw方法来重新绘制View来实现的. 在Android3.0以后,Google为Android新增了属性动画框架Animat

SKU多维属性状态判断算法

作者:周琪力,前端工程师,网络常用昵称「keelii」.在过去的4年里主要负责京东网站商品详情页的前端系统架构和开发,平时主要写 JavaScript 偶尔写点NodeJS,Python.琪力博客: https://keelii.github.io/. 问题描述 这个问题来源于选择商品属性的场景.比如我们买衣服.鞋子这类物件,一般都需要我们选择合适的颜色.尺码等属性 先了解一下 SKU的学术概念吧 最小库存管理单元(Stock Keeping Unit, SKU)是一个会计学名词,定义为库存管理

分数化简算法

#include<stdio.h>int gcd(int n,int m){int temp,r;if(n<m){temp=n;n=m;m=temp;}while(m!=0){ r=n%m;n=m;m=r; }return n;} void main(){int a,b;//a是分子 b是分母printf("please input a and b:");scanf("%d%d",&a,&b); printf("%d/%d

聊一聊粗糙集(一)

本系列博客将介绍经典粗糙集的相关概念和一个属性约简算法,作为系列博客的开篇之作,先不介绍具体概念,简单认识认识粗糙集. 粗糙集理论简介 粗糙集是波兰理工大学Z.pawlak教授提出用来研究不完整数据,不精确知识的表达.学习,归纳等的一套理论. 它是一种新的处理模糊和不确定性问题的数学工具,已被广泛应用于知识发现.机器学习.决策支持.模式识别.专家系统及归纳推理等领域. 粗糙集理论的特点是能够分析隐藏在数据中的事实,又不需要关于数据附加信息. 其主要思想是在保持分类能力不变的前提下,通过知识约简,

聊一聊粗糙集(六)

本节我们将继续介绍粗糙集有关的概念. 上节我们介绍了知识粒度的矩阵表示形式,本节将介绍基于知识粒度属性约简定义和算法. 基于粗糙特征选择算法亦称为属性约简,其旨在保持数据集分类能力不变的前提下,通过约简冗余属性,最后得到问题的决策或分类规则. 相关定义 设决策信息系统\(S=(U,A=C \bigcup D,V,f)\),\(B \subseteq C\),如果\(B\)为\(S\)的最小属性约简,则: \[ GP_{U}(D \mid B)=GP_{U}(D\mid C) \] \[ \for

18大经典数据挖掘算法小结

18大经典数据挖掘算法小结 本文所有涉及到的数据挖掘代码的都放在了我的github上了. 地址链接: https://github.com/linyiqun/DataMiningAlgorithm 大概花了将近2个月的时间,自己把18大数据挖掘的经典算法进行了学习并且进行了代码实现,涉及到了决策分类,聚类,链接挖掘,关联挖掘,模式挖掘等等方面.也算是对数据挖掘领域的小小入门了吧.下面就做个小小的总结,后面都是我自己相应算法的博文链接,希望能够帮助大家学习. 1.C4.5算法.C4.5算法与ID3

舆情,文本挖掘

MLE,MAP,EM 和 point estimation 之间的关系是怎样的 和点估计相对应的是区间估计,这个一般入门的统计教材里都会讲.直观说,点估计一般就是要找概率密度曲线上值最大的那个点,区间估计则要寻找该曲线上满足某种条件的一个曲线段. 最大似然和最大后验是最常用的两种点估计方法.以最简单的扔硬币游戏为例,一枚硬币扔了五次,有一次是正面.用最大似然估计,就是以这五次结果为依据,判断这枚硬币每次落地时正面朝上的概率(期望值)是多少时,最有可能得到四次反面一次正面的结果.不难计算得到期望概

FNN模糊神经网络——信息系统客户服务感知评价

案例描述 信息系统是否真正减轻业务人员的日常工作量提高工作效率?如何从提供“被动”服务转变为根据客户感知提供“主动”服务,真正实现电网企业对信息系统服务的有效管理?如何构建一套适合企业的信息系统客户服务感知模型,通过模型准确定位信息系统客户服务过程中存在的问题,并通过建立信息系统客户服务管控体系,不断完善和优化运维服务,提高客户服务水平,提升信息系统客户服务满意度?已成为企业有效促进信息化工作水平提高的重要工作. 案例分析 信息系统客户服务感知是指客户对信息系统的体验和感受,反映当前信息系统的质