上一篇介绍了arff格式,这是weka专有格式,一般情况需要我们从其他数据源抽取或者获得。weka支持从cvs转化,也可以从数据库中抽取,界面如下图
weka安装目录有一个data目录,里面有一些测试数据,可以用于测试和学习。
导入了数据仅仅是一个开始,我们还需要对数据进行预处理。
数据预处理(data preprocessing)是指在主要的处理以前对数据进行的一些处理。
现实世界中数据大体上都是不完整,不一致的脏数据,无法直接进行数据挖掘,或挖掘结果差强人意。
为了提高数据挖掘的质量产生了数据预处理技术。
数据预处理有多种方法:数据清理,数据集成,数据变换,数据归约等。这些数据处理技术在数据挖掘之前使用,大大提高了数据挖掘模式的质量,降低实际挖掘所需要的时间。
数据清理是使用比较频繁的,主要有:
(1)空缺值处理
目前最常用的方法是使用最可能的值填充空缺值,比如可以用回归、贝叶斯形式化方法工具或判定树归纳等确定空缺值.这类方法依靠现有的数据信息来推测空缺值,使空缺值有更大的机会保持与其他属性之间的联系。
还可以用一个全局常量替换空缺值、使用属性的平均值填充空缺值或将所有元组按某些属性分类,然后用同一类中属性的平均值填充空缺值.如果空缺值很多,这些方法可能误导挖掘结果。
(2)噪声数据处理
噪声是一个测量变量中的随机错误或偏差,包括错误的值或偏离期望的孤立点值。常用分箱、回归、计算机检查和人工检查结合、聚类等方法进行噪音处理。
数据变化主要使用平滑聚集,数据概化,规范化等手段使数据换为较利于数据挖掘的格式。
数据归约主要是为了压缩数据量,源数据可以用来得到数据集的归约表示,它接近于保持原数据的完整性,但数据量比原数据小得多.与非归约数据相比,在归约的数据上进行挖掘,所需的时间和内存资源更少,挖掘将更有效,并产生相同或几乎相同的分析结果。常用维归约、数据压缩、数值归约等方法实现。
weka.filters中包含了一些数据预处理的简单实现(其实已经够用了),主要分成两大类,监督过滤(UnsupervisedFilter)和非监督过滤(UnsupervisedFilter)。
如果是使用GUI的话,点击Filter的Choose就可以选择
选择完成后点击选择的Filter本身就可以修改相关参数。
完成参数修正后点击Apply就Ok了。
我平时使用的比较多的还是非监督过滤,下面介绍一些比较常见。
先介绍weka.filters.unsupervised.attribute包下的,这是非监督方法对属性进行预处理。
为数据库添加一个新的属性,新的属性将会包含所有缺失值。可选参数:
attributeIndex:属性位置,从1开始算,last是最后一个,first是第一个
attributeName:属性名称
attributeType:属性类型,一般是4选1
dateFormat:数据格式,参考ISO-8601
nominalLabels:名义标签,多个值用逗号隔开
新增一个属性,该属性由现有属性通过设定的表达式计算得出。支持+, -, *, /, ^, log, abs, cos, exp, sqrt, floor, ceil, rint, tan, sin。现有属性由a+索引值构成。
字面意思,添加一个ID
只对名义属性有效,依照一定比例修改值。
将数值化属性的平均化为0。
修改数据格式
复制制定属性并命名为Copy Of XX
简单划分的离散化处理。参数:
attributeIndices:属性范围,如1-5,first-last
bins:桶的数量
第n个值用n+1项值和n项值的差替换
功能和AddExpression类似,不过支持的运算更多,特别是MAX和MIN的支持特别有用。所有支持运算符如下:+, -, *, /, pow, log,abs, cos, exp, sqrt, tan, sin, ceil, floor, rint, (, ),A,MEAN, MAX, MIN, SD, COUNT, SUM, SUMSQUARED, ifelse
重新排列属性,输入2-last,1可以让第一项排到最后,如果输入1,3,5的话…其他项就没有了
这个和Center功能大致相同,多了一个标准化单位变异数
将String型转化为Nominal型
交换值
然后是weka.filters.unsupervised.instance包下的
将所有输入转为稀疏格式
规范化整个实例集
交叉验证,不支持分层,如果需要的话使用监督学习中的方法
移除制定范围的实例,化为NaN
随机抽样,从现有样本产生新的小样本
根据规则进行过滤,支持逻辑运算,向上取值,取绝对值等等
weka.filters.supervised包中的内容比较少,而且涉及到一些流程原理,这里就不介绍了,后面的文章会慢慢介绍到
weka的使用并不仅仅极限于它自带的GUI或者命令行,我们可以使用weka的java api,在weka的基础架构和已经实现的算法基础上进行开发。
新建一个java项目,添加对weka.jar的引用。这个包一般在安装目录下,我的3.6版本的大小为6316kb。
Instances是最主要的数据集容器,读入arff文件初始化之,如下:
Instances instances=DataSource.read("data/cpu.arff");
System.out.println(instances.toSummaryString());
效果:
使用Filter的一般流程是:实例化过滤器,传入过滤器参数,通过Filter.useFilter使用过滤器
举个例子,我想为这个cpu数据库加入一个ID,使用AddID过滤器。
先实例化AddID
AddID filter = new AddID();
该过滤器需要2个参数,一个是位置,一个是名称。建立一个长为4的字符串数组,填充参数
String[] options = new String[4];
options[0] = "-C";
options[1] = "first";
options[2] = "-N";
options[3] = "ID";
filter.setOptions(options);
filter.setInputFormat(instances);
使用过滤器,然后输出
Instances newInstances = Filter.useFilter(instances, filter); System.out.println(newInstances.toSummaryString());
Instances instances = DataSource.read("data/cpu.arff");
System.out.println(instances.toSummaryString());
AddID filter = new AddID();
String[] options = new String[4];
options[0] = "-C";
options[1] = "first";
options[2] = "-N";
options[3] = "ID";
filter.setOptions(options);
filter.setInputFormat(instances);
Instances newInstances = Filter.useFilter(instances, filter);
System.out.println(newInstances.toSummaryString());
效果:
再演示一个离散化过滤的使用和新数据的保存
Discretize discretize = new Discretize();
options = new String[6];
options[0] = "-B";
options[1] = "8";
options[2] = "-M";
options[3] = "-1.0";
options[4] = "-R";
options[5] = "2-last";
discretize.setOptions(options);
discretize.setInputFormat(newInstances);
Instances newInstances2 = Filter.useFilter(newInstances, discretize);
System.err.println(newInstances2.toSummaryString());
DataSink.write("data/newcpu.arff", newInstances2);
其实可以很明显的看出,java调用weka api并不困难,关键还是对于数据挖掘、weka本身的了解和熟悉,对于使用哪种方法,需要什么参数要有一定概念。
我使用的weka版本是3.6.6,要是版本不同的话可能有些细节有差异。
一切的开始是Filter类,然后是SimpleFilter,一般情况下我们继承SimpleStreamFilter、SimpleBatchFilter。
这两个的本质差别是一个是全部读入,一个是数据流式处理,但是代码可以完全一样,主要是效率和使用空间上的区别。
举个例子,我希望将所有属性都进行向下取整,继承SimpleStreamFilter,实现和重写一下方法
public Capabilities getCapabilities() public String globalInfo() protected Instances determineOutputFormat(Instances inputFormat) protected Instances process(Instances inst)
完整代码:
@Override public Capabilities getCapabilities() { Capabilities capabilities = super.getCapabilities(); capabilities.enableAllAttributes(); capabilities.enableAllClasses(); capabilities.enable(Capability.NO_CLASS); return capabilities; } public String globalInfo() { return "A simple batch filter that adds an additional attribute 'bla' at the end " + "containing the index of the processed instance."; } protected Instances determineOutputFormat(Instances inputFormat) { Instances result = new Instances(inputFormat, 0); return result; } protected Instances process(Instances inst) { Instances result = new Instances(determineOutputFormat(inst), 0); for (int i = 0; i < inst.numInstances(); i++) { double[] values = new double[result.numAttributes()]; for (int n = 0; n < inst.numAttributes(); n++) values[n] = Math.floor(inst.instance(i).value(n)); result.add(new Instance(1, values)); } return result; }
效果: