• weka数据挖掘拾遗(一)---- 生成Arff格式文件


    一、什么是arff格式文件

      1、arff是Attribute-Relation File Format缩写,从英文字面也能大概看出什么意思。它是weka数据挖掘开源程序使用的一种文件模式。由于weka是个很出色的数据挖掘开源项目,所以使用的比较广,这也无形中推广了它的数据存储格式。

      2、下面是weka自带的一个arff文件例子(weather.arff)

     1 @relation weather
     2 
     3 @attribute outlook {sunny, overcast, rainy}
     4 @attribute temperature real
     5 @attribute humidity real
     6 @attribute windy {TRUE, FALSE}
     7 @attribute play {yes, no}
     8 
     9 @data
    10 sunny,85,85,FALSE,no
    11 sunny,80,90,TRUE,no
    12 overcast,83,86,FALSE,yes
    13 rainy,70,96,FALSE,yes
    14 rainy,68,80,FALSE,yes
    15 rainy,65,70,TRUE,no
    16 overcast,64,65,TRUE,yes
    17 sunny,72,95,FALSE,no
    18 sunny,69,70,FALSE,yes
    19 rainy,75,80,FALSE,yes
    20 sunny,75,70,TRUE,yes
    21 overcast,72,90,TRUE,yes
    22 overcast,81,75,FALSE,yes
    23 rainy,71,91,TRUE,no

       a) 第1行,是关系名称,这个自己随便起,不过写的最好要有意义。

       b) 第3~7行是特征列表,其中第1列是特征说明,不可缺少,第2列是特征名称,第3列是特征类型或特征取值范围。

       c) @data(第9行)是数据域说明,在它下面的全是数据。其中每一行体表一条数据。

       d) 例子中给出的数据域是最基本的表示方法,实际应用中,一般都是用稀疏表示法。

       e) 此处对于arff文件格式不做进一步解释,不懂的地方可以给我留言。 

    二、总体思路

      1、生成特征文件

      2、文件格式转换

    三、具体实现

      1、特征的生成

        这里假设我们已经生成了特征。(因为特征选择我会另写一篇文章单独介绍)

      2、arff文件生成

        a) 生成文件的接口

     1 package com.lvxinjian.alg.models.generatefile;
     2 
     3 /**
     4  * @Descriptin : 生成指定格式文件的接口
     5  * @author :Lv Xinjian
     6  *
     7  */
     8 public interface GenerateFile {
     9     /**
    10      * @function 生成文件
    11      * @param obj 输入数据
    12      * @param option 参数
    13      * @return 是否生成成功
    14      */
    15     abstract public boolean GenerFile(Object obj , String option);
    16 }
    View Code

          b) 生成arff的主文件

      1 package com.lvxinjian.alg.models.generatefile;
      2 
      3 import java.io.IOException;
      4 import java.nio.charset.Charset;
      5 import java.util.ArrayList;
      6 import java.util.HashSet;
      7 import java.util.concurrent.ExecutorService;
      8 import java.util.concurrent.Executors;
      9 import java.util.concurrent.Future;
     10 
     11 import weka.core.FastVector;
     12 import weka.core.Instance;
     13 import weka.core.Instances;
     14 
     15 import com.iminer.alg.models.sampling.SVMSampleBean;
     16 import com.iminer.alg.models.sampling.SampleBean;
     17 import com.iminer.alg.models.sampling.SampleUtils;
     18 import com.iminer.tool.common.util.FileTool;
     19 
     20 /**
     21  * @Description : 生成arff格式的文件
     22  * @author : Lv Xinjian
     23  *
     24  */
     25 public class GenerateArffFile implements GenerateFile {
     26     
     27     /**
     28      * 保存arff文件
     29      */
     30     private static Instances data = null;
     31     /**
     32      * 分类标签
     33      */
     34     private ClassifyAttribute classifyAttribute = new ClassifyAttribute();
     35     /**
     36      * Instance name
     37      */
     38     public final String InstanceName = "MyRelation";
     39     /**
     40      * 抽取instance的方法 ,默认为方法一
     41      */
     42     private String getInstancesMothed = "one";
     43     /**
     44      * 保存转换后的SVM数据
     45      */
     46     private ArrayList<SVMSampleBean> listSVMBean = new ArrayList<SVMSampleBean>();
     47     /**
     48      * 生成arff文件时使用的词表路径
     49      */
     50     private String lexPath = null;
     51     /**
     52      * 保存arff文件的路径
     53      */
     54     private String outputPath = null;
     55     /**
     56      * 生成arff文件的主函数
     57      */
     58     private int threadNum = 5;
     59     @Override
     60     public boolean GenerFile(Object obj, String option) {    
     61         String  [] paramArray = option.split(" ");
     62         return GenerFile(obj,paramArray);
     63     }
     64     /**
     65      * 生成arff文件的主函数
     66      */
     67     public boolean GenerFile(Object obj, String [] paramArray) {    
     68         try {            
     69             if(!Initialization(obj , paramArray))
     70                 return false;
     71             GenerateData();
     72         } catch (IOException e) {            
     73             e.printStackTrace();
     74             return false;
     75         }
     76         return true;
     77     }
     78     /**
     79      * @function 解析命令行,初始化参数
     80      * @param obj 传入的数据
     81      * @param paramArrayOfString 命令行
     82      * @return 初始化是否生成成功,true:成功    false:失败
     83      */
     84     private boolean Initialization(Object obj, String [] paramArrayOfString){            
     85         try{
     86             ArrayList<?> list = (ArrayList<?>)obj;
     87             for(Object s : list){                
     88                 listSVMBean.add((SVMSampleBean)s);
     89             }    
     90             //初始化词表路径
     91             String lexPath = ParameterUtils.getOption("lexPath", paramArrayOfString);
     92             if(lexPath.length() != 0)
     93                 this.lexPath = lexPath;
     94             //初始化arff文件保存路径
     95             String outputPath = ParameterUtils.getOption("output", paramArrayOfString);
     96             if(outputPath.length() != 0)
     97                 this.outputPath = outputPath;        
     98             //初始化instance抽取方法,默认为方法一
     99             String getInstanceMothed = ParameterUtils.getOption("mothed", paramArrayOfString);
    100             if(getInstanceMothed.length() != 0)
    101                 this.getInstancesMothed = getInstanceMothed;
    102             String threadNum = ParameterUtils.getOption("thread", paramArrayOfString);
    103             if(threadNum.length() != 0){
    104                 this.threadNum = Integer.parseInt(threadNum);
    105                 System.out.println("线程数 :" + this.threadNum);
    106             }else{
    107                 System.out.println("使用默认线程数:5");
    108             }
    109             //初始化类别名称,不可省略
    110             String className = ParameterUtils.getOption("class", paramArrayOfString);
    111             if(className.length() != 0)
    112                 classifyAttribute.setClassname(className);
    113             //初始化类别标签
    114             String labels = ParameterUtils.getOption("label", paramArrayOfString);
    115             if(labels.length() != 0){                
    116                 classifyAttribute.setClassLabel(labels.split(","));                    
    117             }
    118             else{
    119                 System.out.println("please Initialize classify labels!");
    120                 return false;
    121             }            
    122         }
    123         catch(Exception e){
    124             e.printStackTrace();
    125         }
    126         
    127         return true;
    128     }
    129     /**
    130      * @function 生成arff的主函数
    131      * @throws IOException
    132      */
    133     public void GenerateData() throws IOException {        
    134         ArrayList<String> words = new ArrayList<String>();
    135         FastVector atts = ArffFileUtils.GetAttributes(this.lexPath , words ,this.classifyAttribute );
    136         
    137         data = new Instances(this.InstanceName, atts, 0);    
    138 
    139         ExecutorService service = Executors.newFixedThreadPool(this.threadNum);    
    140         int count = 0;
    141         for (SVMSampleBean it : listSVMBean) {
    142             if (count++ % 1000 == 0)
    143                 System.out.println("processed " + count + " recoreds");    
    144             
    145             //获取类别标签的下标
    146             double labelVal = data.attribute(classifyAttribute.getClassname()).indexOfValue(it.getLabel());
    147             
    148             MyCallableClass task = new MyCallableClass(labelVal, it.getContent(), words ,this.getInstancesMothed);
    149             Future is =  service.submit(task);
    150             try{
    151                 if(is.get() != null)            
    152                     data.add((Instance) is.get());
    153             }catch(Exception e){
    154                 e.printStackTrace();
    155             }                    
    156         }
    157         service.shutdown();
    158         //保存data中的数据    
    159         ArffFileUtils.savaInstances(data,this.outputPath);
    160         //清空data中的数据
    161         data.delete();
    162     }
    163     /**
    164      * @function 
    165      * @param lstContent
    166      * @param lexPath
    167      * @param labels
    168      * @param outputPath
    169      * @return
    170      */
    171     public static boolean generateArff(ArrayList<String> lstContent ,String lexPath , String labels, String outputPath){
    172         try{
    173             ArrayList<SampleBean> list = new ArrayList<SampleBean>();    
    174             HashSet<String> lstLabel = new HashSet<String>();
    175             for(String str : lstContent){
    176                 SVMSampleBean svmBean = new SVMSampleBean(str.replace("	", SampleUtils.SPECIAL_CHAR));
    177                 list.add(svmBean);
    178                 lstLabel.add(svmBean.label);
    179             }
    180             if(labels == null){
    181                 labels = "";
    182                 for(String label : lstLabel){
    183                     if(labels != "")
    184                         labels += ",";
    185                     labels += label;
    186                 }
    187             }
    188             String [] options = new String[]{"-lexPath" , lexPath,
    189                                             "-output" , outputPath,
    190                                             "-mothed" , "one",
    191                                             "-class" , "CLASS",
    192                                             "-label" , labels};
    193             GenerateArffFile genArff =new GenerateArffFile();
    194             genArff.GenerFile(list, options);
    195             return true;
    196         }catch(Exception e){
    197             e.printStackTrace();
    198             return false;
    199         }
    200         
    201     }
    202     public static void main(String [] args){
    203         try{
    204         String root = "C:\Users\Administrator\Desktop\12_05\模型训练\1219\";
    205         ArrayList<SampleBean> list = new ArrayList<SampleBean>();            
    206         ArrayList<String> lstContent = FileTool.LoadListFromFile(root + "不重合的部分.23.txt", 0 , Charset.forName("utf8"));
    207         for(String str : lstContent){
    208             
    209             SVMSampleBean svmBean = new SVMSampleBean(str.replace("	", SampleUtils.SPECIAL_CHAR));
    210             list.add(svmBean);
    211         }
    212 //        DFFeatureSelector selector = new DFFeatureSelector();
    213 //        String options = "-maxFeatureNum 1000 -outputPath "+root + "lex.txt";
    214 //        selector.selectFeature(list, options);
    215         
    216 //        options = "-lexPath "+root +"lex.txt -output genArffTest.arff -mothed one -class CLASS -label -1,1,2";
    217         
    218         
    219         String [] options = new String[]{"-lexPath" , root + "temp/temp.lex",
    220                                         "-output" , root + "不重合的部分.23.arff",
    221                                         "-mothed" , "one",
    222                                         "-class" , "CLASS",
    223                                         "-label" , "2,1,-1",
    224                                         "-thread","10"};
    225         GenerateArffFile genArff =new GenerateArffFile();
    226         genArff.GenerFile(list, options);
    227         CalcAttributeFromArffFile.calcAttribute(root + "不重合的部分.23.arff" , root + "calc.txt");
    228         }catch(Exception e){
    229             e.printStackTrace();
    230         }
    231     
    232     }
    233 }
    View Code

        c) 命令行解析工具

      1 package com.lvxinjian.alg.models.generatefile;
      2 
      3 /**
      4  * @Description : 抽取参数
      5  * @author : Lv Xinjian
      6  */
      7 public class ParameterUtils {
      8 
      9     static public void main(String [] args){
     10         String option = "-min 1 -max 100 -w 1.2,1.3  -filter  g";
     11         try {
     12             boolean r = getFlag("filter", option.split(" "));
     13             System.out.println(r);
     14             
     15         } catch (Exception e) {            
     16             e.printStackTrace();
     17         }
     18     }    
     19     /**
     20      * @function 抽取字符类的布尔型参数
     21      * @param flag 字符
     22      * @param options 参数数组
     23      * @return 
     24      * @throws Exception
     25      */
     26     public static boolean getFlag(char flag, String[] options) throws Exception
     27     {
     28       return getFlag("" + flag, options);
     29     }
     30     /**
     31      * @function 抽取字符串类的布尔型参数
     32      * @param flag 字符
     33      * @param options 参数数组
     34      * @return 
     35      * @throws Exception
     36      */         
     37     public static boolean getFlag(String flag, String[] options) throws Exception
     38     {
     39       int pos = getOptionPos(flag, options);
     40     
     41       if (pos > -1) {
     42         options[pos] = "";
     43       }
     44       return (pos > -1);
     45     }
     46     /**
     47      * @function 抽取字符串类的字符串型参数
     48      * @param flag 字符串
     49      * @param options 参数数组
     50      * @return 
     51      * @throws Exception
     52      */
     53     public static String getOption(String flag, String[] options)throws Exception {
     54         int i = getOptionPos(flag, options);
     55         if (i > -1) {
     56             if (options[i].equals("-" + flag)) {
     57                 if (i + 1 == options.length) {
     58                     throw new Exception("No value given for -" + flag
     59                             + " option.");
     60                 }
     61                 options[i] = "";
     62                 String newString = new String(options[(i + 1)]);
     63                 options[(i + 1)] = "";
     64                 return newString;
     65             }
     66             if (options[i].charAt(1) == '-') {
     67                 return "";
     68             }
     69         }
     70 
     71         return "";
     72     }
     73     /**
     74      * @function 抽取字符类的短整型参数
     75      * @param flag 字符
     76      * @param options 参数数组
     77      * @return 
     78      * @throws Exception
     79      */
     80     public static int getOptionPos(char flag, String[] options)
     81     {
     82       return getOptionPos("" + flag, options);
     83     }
     84     /**
     85      * @function 抽取字符串类的短整型参数
     86      * @param flag 字符
     87      * @param options 参数数组
     88      * @return 
     89      * @throws Exception
     90      */
     91     public static int getOptionPos(String flag, String[] options) {
     92         if (options == null) {
     93             return -1;
     94         }
     95         for (int i = 0; i < options.length; ++i) {
     96             if ((options[i].length() <= 0) || (options[i].charAt(0) != '-'))
     97                 continue;
     98             try {
     99                 Double.valueOf(options[i]);
    100             } catch (NumberFormatException e) {
    101                 if (options[i].equals("-" + flag)) {
    102                     return i;
    103                 }
    104                 if (options[i].charAt(1) == '-') {
    105                     return -1;
    106                 }
    107             }
    108         }
    109 
    110         return -1;
    111     }
    112     /**
    113      * @function 把数据转换成字符串
    114      * @param array
    115      * @param splitPunc
    116      * @return
    117      */
    118     public static String array2String(String [] array , String splitPunc){
    119         try{
    120             StringBuilder sb = new StringBuilder();
    121             for(String para : array){
    122                 if(sb.length() != 0)
    123                     sb.append(splitPunc);
    124                 sb.append(para);
    125             }
    126             return sb.toString();
    127         }catch(Exception e){
    128             e.printStackTrace();
    129             return null;
    130         }
    131     }
    132     public static String [] String2Array(String para , String splitPunc){
    133         try{
    134             return para.split(splitPunc);
    135         }catch(Exception e){
    136             e.printStackTrace();
    137             return null;
    138         }
    139     }
    140     /**
    141      * @替换字符串中的某个参数
    142      * @param para 参数字符串
    143      * @param splitPunc 参数分隔符
    144      * @param key 参数名称
    145      * @param value 新参数值
    146      * @return
    147      */
    148     public static String replacePara(String para , String splitPunc , String key , String value){
    149         try{
    150             String [] parameter = String2Array(para,splitPunc);
    151             replacePara(parameter, key, value);
    152             return array2String(parameter, splitPunc);
    153         }catch(Exception e){
    154             e.printStackTrace();
    155             return null;
    156         }
    157     }
    158     /**
    159      * @function 替换一个参数
    160      * @param para 参数数组
    161      * @param key 参数名称
    162      * @param value 新参数值
    163      * @return
    164      */
    165     public static String [] replacePara(String [] para , String key , String value){
    166         try{
    167             for(int i = 0 ; i < para.length ; i++){
    168                 String paraName = para[i];
    169                 if(paraName.contains(key)){
    170                     int nextIndex = i + 1;
    171                     if(nextIndex < para.length){
    172                         if(!para[nextIndex].contains("-"))
    173                             para[nextIndex] = value;
    174                     }
    175                 }
    176             }
    177             return para;
    178         }catch(Exception e){
    179             e.printStackTrace();
    180             return null;
    181         }
    182     }
    183 }
    View Code

        d) 生成arff文件的辅助类

      1 package com.lvxinjian.alg.models.generatefile;
      2 
      3 import java.io.BufferedWriter;
      4 import java.io.FileOutputStream;
      5 import java.io.IOException;
      6 import java.io.OutputStreamWriter;
      7 import java.nio.charset.Charset;
      8 import java.util.HashMap;
      9 import java.util.List;
     10 import java.util.concurrent.Callable;
     11 
     12 import weka.core.Attribute;
     13 import weka.core.FastVector;
     14 import weka.core.Instance;
     15 import weka.core.Instances;
     16 import weka.core.SparseInstance;
     17 
     18 import com.iminer.alg.models.getInstance.InstanceFactory;
     19 import com.iminer.tool.common.util.FileTool;
     20 
     21 
     22 /**
     23  * @Description : 生成arff文件的工具类
     24  * @author : Lv Xinjian
     25  */
     26 public class ArffFileUtils {
     27     
     28     /**
     29      * @function 生成特征向量
     30      * @param lexDataPath 特征文件路径
     31      * @param words    保存特征词
     32      * @param classifyAttribute 类别特征
     33      * @return    特征向量
     34      * @throws IOException 文件读取异常
     35      */
     36     public static FastVector GetAttributes(String lexDataPath , List<String> words ,ClassifyAttribute classifyAttribute)
     37             throws IOException {
     38         HashMap<Integer, String> termId_term = FileTool.LoadIdStrFromFile(
     39                 lexDataPath, 0, 0, 1, "	", Charset.forName("utf8"));
     40         FastVector atts = new FastVector();
     41         // - numeric        
     42         for (int tid = 0; tid < termId_term.size(); tid++) {        
     43             atts.addElement(new Attribute(termId_term.get(tid)));    
     44             words.add(termId_term.get(tid));
     45         }                
     46         atts.addElement(new Attribute(classifyAttribute.getClassname(), classifyAttribute.getAttClassLabel()));
     47                 
     48         System.out.println("atribute size :" + atts.size());
     49         return atts;
     50     }
     51     /**
     52      * @function 保存Arff文件
     53      * @param data arff格式的数据
     54      * @param outputPath 数据保存路径
     55      * @return
     56      */
     57     public static boolean savaInstances(Instances data , String outputPath)
     58     {
     59         try{
     60             BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
     61                     new FileOutputStream(outputPath), Charset.forName("utf-8")));
     62 
     63             bw.write(data.toString());
     64             bw.close();
     65         }catch(Exception e){
     66             e.printStackTrace();
     67             return false;
     68         }
     69         return true;
     70     }
     71 }
     72 /**
     73  * @Description 分类器 类别特征
     74  * @author Administrator
     75  *
     76  */
     77 class ClassifyAttribute{
     78     /**
     79      * 分类特征名 , 默认为"CLASS"
     80      */
     81     private String classname = "CLASS";
     82     private FastVector attClassLabel = new FastVector();
     83     public ClassifyAttribute(String [] labels){
     84         for(String label: labels){
     85             this.attClassLabel.addElement(label);
     86         }
     87     }
     88     public ClassifyAttribute(){}
     89     /**
     90      * @function 获取类别特征名
     91      * @return
     92      */
     93     public String getClassname() {
     94         return classname;
     95     }
     96     /**
     97      * @functoin 设置类别特征名
     98      * @param classname
     99      */
    100     public void setClassname(String classname) {
    101         this.classname = classname;
    102     }
    103     /**
    104      * @function 获取类别特征
    105      * @return 类别特征
    106      */
    107     public FastVector getAttClassLabel() {
    108         return attClassLabel;
    109     }
    110     /**
    111      * @function 设置类别特征
    112      * @param attClassLabel
    113      */
    114     public void setClassLabel(FastVector attClassLabel) {
    115         this.attClassLabel = attClassLabel;
    116     }    
    117     /**
    118      * @function 设置类别特征分类标签
    119      * @param labels
    120      */
    121     public void setClassLabel(String [] labels) {
    122         for(String label: labels){
    123             this.attClassLabel.addElement(label);
    124         }
    125     }    
    126     
    127 }
    128 
    129 /**
    130  * @Description 把字符串转化成 instance实例
    131  * @author Administrator
    132  *
    133  */
    134 class MyCallableClass implements Callable{    
    135     /**
    136      * 输入的文本
    137      */
    138     private String _text;
    139     /**
    140      * 文本的极性标签
    141      */
    142     private double _labelVal;
    143     /**
    144      * 生成instance的方法
    145      */
    146     private String _getInstancesMothed = null;    
    147     /**
    148      * 获取instance方法 的 初始化词表
    149      */
    150     private List<String> _set = null;
    151     /**
    152      * @function 构造函数,初始化参数
    153      * @param labelVal 极性类别标签
    154      * @param text 输入的文本内容
    155      * @param set 获取instance方法 的 初始化词表
    156      * @param getInstancesMothed 生成instance的方法
    157      */
    158     public MyCallableClass(final double labelVal, String text ,List<String> set ,String getInstancesMothed)
    159     {
    160         this._text = text;                
    161         this._labelVal = labelVal;
    162         this._getInstancesMothed = getInstancesMothed;            
    163         this._set = set;
    164         
    165     }    
    166     public Instance call() throws Exception{
    167         double[] vals;
    168         try {
    169             //获取instance的double 数组
    170             vals = InstanceFactory.getInstance(this._getInstancesMothed, this._set ).getInstanceFromText(this._text );
    171             if (vals != null) {
    172                 vals[vals.length - 1] = _labelVal;
    173                 SparseInstance si = new SparseInstance(1.0, vals);    
    174                 return si;
    175             }    
    176 
    177         } catch (Exception e) {        
    178             e.printStackTrace();
    179         }
    180         return null;     
    181        
    182     }     
    183 } 
    View Code

        e) 以上代码缺少了几个类,但由于涉及到公司的保密制度,所以不方便上传。如有疑问,可以给我留言。(其实就是一个生成instance的方法,不过我的方法中揉了些东西进去,方法本身很简单,几行代码的事儿,有空我会补上)

    四、小结

        1、考虑到抽取instance可能会有不同的需求,所以用了一个工厂类,这样方便 使用和新方法的添加。

        2、考虑到效率问题,所以使用了多线程进行生成。

        3、代码的结构、风格以及变量命名是硬伤,希望多多批评、指点。

  • 相关阅读:
    字节流与字符流,字节流和字符流的使用哪个多?
    java 读写操作大文件 BufferedReader和RandomAccessFile
    hibernate官网文档
    阿里云centos怎么用xshell5登陆
    STM8L使用外部8M HSE
    vscode函数注释添加【转载】
    某个通信的异常判断存在于两个任务中时计算通信超时的一种思路
    STM32F0芯片读保护
    FrameworkCubeMX.gpdsc missing的问题
    git忽略已经提交的文件【转载】
  • 原文地址:https://www.cnblogs.com/nocml/p/3545373.html
Copyright © 2020-2023  润新知