使用Weka进行数据挖掘(Weka教程二)Weka数据之ARFF与多文件格式转换

上一篇博客主要讲解了Weka开发环境的搭建,从本博客开始就正式进入Weka开发。
进行数据挖掘,首先要关注的是数据,这篇博客主要讲解Weka的数据格式和在Weka中如何操作数据。

  • Weka数据格式

    Weka的专有数据格式是ARFF,下面是Weka自带的data文件夹里的一个ARFF文件

% ARFF file for the weather data with some numric features
%

@relation weather

@attribute outlook {sunny, overcast, rainy}
@attribute temperature real
@attribute humidity real @attribute windy {TRUE, FALSE} @attribute play {yes, no}
@data

%
% 14 instances
%
sunny,85,85,FALSE,no
sunny,80,90,TRUE,no
overcast,83,86,FALSE,yes
rainy,70,96,FALSE,yes
rainy,68,80,FALSE,yes
rainy,65,70,TRUE,no
overcast,64,65,TRUE,yes
sunny,72,95,FALSE,no
sunny,69,70,FALSE,yes
rainy,75,80,FALSE,yes
sunny,75,70,TRUE,yes
overcast,72,90,TRUE,yes
overcast,81,75,FALSE,yes
rainy,71,91,TRUE,no

其实不难看出,Weka的专有数据格式和CSV文件非常相似,CSV即为逗号分隔符文件,最大的区别在于,Weka头部有每列数据的属性标识。常见的包头如下所示:

   @RELATION iris

   @ATTRIBUTE sepallength  NUMERIC
   @ATTRIBUTE sepalwidth   NUMERIC
   @ATTRIBUTE petallength  NUMERIC
   @ATTRIBUTE petalwidth   NUMERIC
   @ATTRIBUTE class        {Iris-setosa,Iris-versicolor,Iris-virginica}
  • Weka数据格式分析

① 其中@RELATION后面是关系名,如果你只打开一个文件,就是该文件的文件名。

@relation <relation-name> 
<relation-name>一个字符串
如果这个字符串包含空格,它必须加上引号(指英文标点的单引号或双引号)

② @ATTRIBUTE指的是该列的属性,包括NUMERIC指的是数值型变量等以下四种变量类型:

numeric                           数值型 
           分类(nominal)型 
string                            字符串型 
date [<date-format>]              日期和时间型 

其中NUMERIC一般用于连续型数值变量,nominal一般是离散型类别变量。

③ 对于@class类型。指的是类别变量,其所有的取值被大括号包括,如下所示:

组成的类别名放在花括号中:
{, , , ...} 
实际数据类别只能是花括号中的某一个

④@date指的是日期型变量,在数据挖掘中,日期型变量可以直接相加减以获取时间间隔,

@attribute  date [<date-format>] 
是属性的名称
<date-format>是一个字符串来规定该怎样解析和显示日期或时间的格式
默认的字符串格式是ISO-8601所给的日期时间组合格式“yyyy-MM-ddTHH:mm:ss”。 

⑤除此之外,还有@data标识符,用来表明数据的具体内容:

@data 
sunny,85,85,FALSE,no 
?,78,90,?,yes 

每个实例占一行
实例的各属性值用逗号“,”隔开
缺失值(missing value)用问号“?”表示

⑥ Weka中针对稀疏数据也有更加方便的表示,即稀疏变量格式:有的时候数据集中含有大量的0值,这个时候用稀疏格式的数据存贮更加省空间。
如对于下述数据:

@data 
    0, X, 0, Y, "class A" 
    0, 0, W, 0, "class B" 

可以使用稀疏格式表达为:

@data 
    {1 X, 3 Y, 4 "class A"} 
    {2 W, 4 "class B"} 
实例中每一个非0的属性值用 <空格> 表示

Weka官方关于ARFF文件格式的介绍可以在下面地址找到:
http://weka.wikispaces.com/ARFF+%28book+version%29

Weka专有格式和其他格式之间的相互转换
有时候我们可能有其他格式的数据,想转化为ARFF格式的文件,或者想把ARFF格式的文件转化成其他文件格式,Weka也可以很好的支持。
一种方式是使用GUI,打开文件后另存为,另一种方式是在代码中使用Weka的ConverterUtils工具类直接实现,下面贴出我自己写的JAVA的代码:

   public static void fileTypeConverter(String inputFile, String outputFile) {
        File input = new File(inputFile);
        File output = new File(outputFile);
        AbstractFileLoader loader = ConverterUtils.getLoaderForFile(input);
        AbstractFileSaver saver = ConverterUtils.getSaverForFile(output);
        try {
            loader.setSource(input);
            Instances data = loader.getDataSet();
            System.out.println(data);
            saver.setInstances(data);
            saver.setFile(output);
            saver.setDestination(output);
            saver.writeBatch();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

需要注意的是,在使用转换功能之前,应该使用Weka的Filter指定每一列的属性类别,免得所有列都按照默认的NUMRIC类型处理。对于Filter和Instances的介绍将在接下来几篇博客里面继续讲解。

CSV和LibSVM格式互转JAVA代码:

  1. LIBSVM to CSV
    加上了错误行处理,可以自己写正则表达式匹配不对的行并抓出来:
public static void libsvmToCsv(String inputFile, String outputFile, int numOfAttributes, ArrayList indexOfNominal) {
        BufferedReader br = null;
        BufferedWriter bw = null;
        String s;
        Pattern patternIsNum = Pattern.compile("[0-9.]*");
        Pattern patternIsSciNotation = Pattern.compile("^((\\d+.?\\d+)[E]{1}(\\d+))$");
        long lineNum = 0;

        try {
            br = new BufferedReader(new FileReader(inputFile));
            bw = new BufferedWriter(new FileWriter(outputFile));
            int errorCount = 0;
            do {
                s = br.readLine();
                lineNum++;
                boolean errorFlag = false;
                if (s == null)
                    break;
                String[] result = new String[numOfAttributes + 1];
                StringBuffer sb = new StringBuffer();
                for (int i = 0; i < numOfAttributes; i++) {
                    result[i] = "0,";
                }

                String temp[] = s.split(" ");
                result[numOfAttributes] = temp[0];
                for (int i = 1; i < temp.length; i++) {
                    String[] innerTemp = temp[i].split(":");
                    char[] indexArray = innerTemp[0].toCharArray();
                    if (innerTemp.length > 1) {
                        int attributesIndex = Integer.parseInt(innerTemp[0]);
                        Matcher isSciNotation = patternIsSciNotation.matcher(innerTemp[1]);
                        Matcher isNum = patternIsNum.matcher(innerTemp[1]);

                        if (isSciNotation.matches()) {
                            result[attributesIndex - 1] = new BigDecimal(innerTemp[1]).toPlainString() + ",";
                        } else if (isNum.matches() || indexOfNominal.contains(attributesIndex)) {
                            result[attributesIndex - 1] = innerTemp[1] + ",";
                        } else {
                            errorFlag = true;
                        }
                    }
                }
                if (errorFlag) {
                    errorCount++;
                    System.out.println("第" + errorCount + "条-----第 " + lineNum + "行------ " + s);
                }
                else {
                    for (int j = 0; j < numOfAttributes + 1; j++) {
                        sb.append(result[j]);
                    }
                    bw.write(sb.toString());
                    bw.newLine();
                }
            } while (s != null);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                br.close();
                bw.flush();
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

你可能感兴趣的:(Weka+Java数据挖掘)