zoukankan      html  css  js  c++  java
  • 数据预处理和weka.filters的使用数据挖掘学习和weka使用(三)

    上一篇介绍了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.huangyunkun.com/
    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    支持: 新浪微博

  • 相关阅读:
    (并查集)小希的迷宫 --HDU -- 1272
    (并查集)Connections in Galaxy War -- zoj --3261 还没写
    (并查集)A Bug's Life -- POJ -- 2492
    LINQ 图解 LINQ学习第三篇 [转]
    C# 4.0 新特性-dynamic 【转】
    C#编程规范
    C#中关于DateTime的最大值和最小值
    .NET,你忘记了么?(八)—— 从dynamic到特性误用 [转]
    C#中dynamic的正确用法【转】
    ASP.NET MVC 中将FormCollection与实体间转换方法【转】
  • 原文地址:https://www.cnblogs.com/htynkn/p/weka_3.html
Copyright © 2011-2022 走看看