Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1077664
  • 博文数量: 403
  • 博客积分: 10272
  • 博客等级: 上将
  • 技术积分: 4407
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 14:22
文章分类

全部博文(403)

文章存档

2012年(403)

分类: 系统运维

2012-04-04 18:37:17

上一篇介绍了arff格式,这是weka专有格式,一般情况需要我们从其他数据源抽取或者获得。weka支持从cvs转化,也可以从数据库中抽取,界面如下图

weka3_1

weka安装目录有一个data目录,里面有一些测试数据,可以用于测试和学习。

导入了数据仅仅是一个开始,我们还需要对数据进行预处理。

数据预处理(data preprocessing)

数据预处理(data preprocessing)是指在主要的处理以前对数据进行的一些处理。

现实世界中数据大体上都是不完整,不一致的脏数据,无法直接进行数据挖掘,或挖掘结果差强人意。

为了提高数据挖掘的质量产生了数据预处理技术。

数据预处理有多种方法:数据清理,数据集成,数据变换,数据归约等。这些数据处理技术在数据挖掘之前使用,大大提高了数据挖掘模式的质量,降低实际挖掘所需要的时间。

数据清理是使用比较频繁的,主要有:

(1)空缺值处理

目前最常用的方法是使用最可能的值填充空缺值,比如可以用回归、贝叶斯形式化方法工具或判定树归纳等确定空缺值.这类方法依靠现有的数据信息来推测空缺值,使空缺值有更大的机会保持与其他属性之间的联系。

还可以用一个全局常量替换空缺值、使用属性的平均值填充空缺值或将所有元组按某些属性分类,然后用同一类中属性的平均值填充空缺值.如果空缺值很多,这些方法可能误导挖掘结果。

(2)噪声数据处理

噪声是一个测量变量中的随机错误或偏差,包括错误的值或偏离期望的孤立点值。常用分箱、回归、计算机检查和人工检查结合、聚类等方法进行噪音处理。

 

数据变化主要使用平滑聚集,数据概化,规范化等手段使数据换为较利于数据挖掘的格式。

 

数据归约主要是为了压缩数据量,源数据可以用来得到数据集的归约表示,它接近于保持原数据的完整性,但数据量比原数据小得多.与非归约数据相比,在归约的数据上进行挖掘,所需的时间和内存资源更少,挖掘将更有效,并产生相同或几乎相同的分析结果。常用维归约、数据压缩、数值归约等方法实现。

Weka.Filters

weka.filters中包含了一些数据预处理的简单实现(其实已经够用了),主要分成两大类,监督过滤(UnsupervisedFilter)和非监督过滤(UnsupervisedFilter)。

如果是使用GUI的话,点击Filter的Choose就可以选择

weka3_2

选择完成后点击选择的Filter本身就可以修改相关参数。

weka3_3

完成参数修正后点击Apply就Ok了。

我平时使用的比较多的还是非监督过滤,下面介绍一些比较常见。

先介绍weka.filters.unsupervised.attribute包下的,这是非监督方法对属性进行预处理。

1.Add

为数据库添加一个新的属性,新的属性将会包含所有缺失值。可选参数:

attributeIndex:属性位置,从1开始算,last是最后一个,first是第一个

attributeName:属性名称

attributeType:属性类型,一般是4选1

dateFormat:数据格式,参考ISO-8601

nominalLabels:名义标签,多个值用逗号隔开

2.AddExpression

新增一个属性,该属性由现有属性通过设定的表达式计算得出。支持+, -, *, /, ^, log, abs, cos, exp, sqrt, floor, ceil, rint, tan, sin。现有属性由a+索引值构成。

3.AddID

字面意思,添加一个ID

4.AddNoise

只对名义属性有效,依照一定比例修改值。

5.Center

将数值化属性的平均化为0。

6.ChangeDateFormat

修改数据格式

7.Copy

复制制定属性并命名为Copy Of XX

8.Discretize

简单划分的离散化处理。参数:

attributeIndices:属性范围,如1-5,first-last

bins:桶的数量

9.FirstOrder

第n个值用n+1项值和n项值的差替换

10.MathExpression

功能和AddExpression类似,不过支持的运算更多,特别是MAX和MIN的支持特别有用。所有支持运算符如下:+, -, *, /, pow, log,abs, cos, exp, sqrt, tan, sin, ceil, floor, rint, (, ),A,MEAN, MAX, MIN, SD, COUNT, SUM, SUMSQUARED, ifelse

11.Reorder

重新排列属性,输入2-last,1可以让第一项排到最后,如果输入1,3,5的话…其他项就没有了

12.Standardize

这个和Center功能大致相同,多了一个标准化单位变异数

13.StringToNominal

将String型转化为Nominal型

14.SwapValues

交换值

然后是weka.filters.unsupervised.instance包下的

1.NonSparseToSparse

将所有输入转为稀疏格式

2.Normalize

规范化整个实例集

3.RemoveFolds

交叉验证,不支持分层,如果需要的话使用监督学习中的方法

4.RemoveRange

移除制定范围的实例,化为NaN

5.Resample

随机抽样,从现有样本产生新的小样本

6.SubsetByExpression

根据规则进行过滤,支持逻辑运算,向上取值,取绝对值等等

weka.filters.supervised包中的内容比较少,而且涉及到一些流程原理,这里就不介绍了,后面的文章会慢慢介绍到

调用Weka实现数据预处理

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());

效果:

weka3_4

 

使用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());

效果:

weka3_5

再演示一个离散化过滤的使用和新数据的保存

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的扩展,实现自己的过滤器

我使用的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;
}

效果:

weka3_6
图片分享:


作者:黄云坤 
出处:http://www.cnblogs.com/htynkn/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 
支持:  

您的支持是我前进的动力,请猛击
      
阅读(4146) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~