【问题标题】:How to merge two sets of weka Instances together如何将两组weka Instances合并在一起
【发布时间】:2012-06-02 01:09:14
【问题描述】:

目前,我一次将一个实例从一个数据集复制到另一个数据集。有没有办法做到这一点,使字符串映射保持不变? mergeInstances 是横向工作的,有没有等价的纵向合并?

这是我用来从多个 arff 文件中将相同结构的数据集读取到一个大型数据集的循环的一个步骤。一定有更简单的方法。

Instances iNew = new ConverterUtils.DataSource(name).getDataSet();
for (int i = 0; i < iNew.numInstances(); i++) {
    Instance nInst = iNew.instance(i);
    inst.add(nInst);
}

【问题讨论】:

    标签: java merge set weka


    【解决方案1】:

    如果您想要一个完全自动化的方法,也可以正确复制字符串和名义属性,您可以使用以下函数:

    public static Instances merge(Instances data1, Instances data2)
        throws Exception
    {
        // Check where are the string attributes
        int asize = data1.numAttributes();
        boolean strings_pos[] = new boolean[asize];
        for(int i=0; i<asize; i++)
        {
            Attribute att = data1.attribute(i);
            strings_pos[i] = ((att.type() == Attribute.STRING) ||
                              (att.type() == Attribute.NOMINAL));
        }
    
        // Create a new dataset
        Instances dest = new Instances(data1);
        dest.setRelationName(data1.relationName() + "+" + data2.relationName());
    
        DataSource source = new DataSource(data2);
        Instances instances = source.getStructure();
        Instance instance = null;
        while (source.hasMoreElements(instances)) {
            instance = source.nextElement(instances);
            dest.add(instance);
    
            // Copy string attributes
            for(int i=0; i<asize; i++) {
                if(strings_pos[i]) {
                    dest.instance(dest.numInstances()-1)
                        .setValue(i,instance.stringValue(i));
                }
            }
        }
    
        return dest;
    }
    

    请注意以下条件应成立(函数中没有勾选):

    • 数据集必须具有相同的属性结构(属性数量、属性类型)
    • 类索引必须相同
    • 标称值必须完全对应

    要动态修改 data2 的标称属性的值以匹配 data1 的值,您可以使用:

    data2.renameAttributeValue(
        data2.attribute("att_name_in_data2"),
        "att_value_in_data2",
        "att_value_in_data1");
    

    【讨论】:

      【解决方案2】:

      为什么不制作一个包含两个原始数据的新 ARFF 文件?一个简单的

      cat 1.arff > tmp.arff
      tail -n+20 2.arff >> tmp.arff
      

      20 被替换为 arff 标头的长度。这将生成一个包含所有所需实例的新 arff 文件,您可以使用现有代码读取这个新文件:

      Instances iNew = new ConverterUtils.DataSource(name).getDataSet();
      

      您还可以使用以下文档在命令行上调用 weka:http://old.nabble.com/how-to-merge-two-data-file-a.arff-and-b.arff-into-one-data-list--td22890856.html

      java weka.core.Instances append filename1 filename2 > output-file 
      

      但是,http://weka.sourceforge.net/doc.dev/weka/core/Instances.html#main%28java.lang.String 文档中没有允许您在 Java 代码中本地附加多个 arff 文件的功能。从 Weka 3.7.6 开始,附加两个 arff 文件的代码是这样的:

           // read two files, append them and print result to stdout
        else if ((args.length == 3) && (args[0].toLowerCase().equals("append"))) {
      DataSource source1 = new DataSource(args[1]);
      DataSource source2 = new DataSource(args[2]);
      String msg = source1.getStructure().equalHeadersMsg(source2.getStructure());
      if (msg != null)
        throw new Exception("The two datasets have different headers:\n" + msg);
      Instances structure = source1.getStructure();
      System.out.println(source1.getStructure());
      while (source1.hasMoreElements(structure))
        System.out.println(source1.nextElement(structure));
      structure = source2.getStructure();
      while (source2.hasMoreElements(structure))
        System.out.println(source2.nextElement(structure));
        }
      

      因此,看起来 Weka 本身只是简单地遍历数据集中的所有实例并打印它们,这与您的代码使用的过程相同。

      【讨论】:

      • 我最终自己遍历了所有实例......似乎最简单。
      【解决方案3】:

      另一个可能的解决方案是使用 java.util.AbstractCollection 中的 addAll,因为实例实现了它。

      instances1.addAll(instances2);
      

      【讨论】:

      • 请注意,在 3.6.9 版本中,实例不再具有该方法,因为它没有从 AbstractCollection 扩展。
      • 如果您使用过滤器,此方法并不总是有效。更多:stackoverflow.com/q/38460698/3923800
      【解决方案4】:

      我刚刚与 innerJoinleftJoinfullJoinupdateunion 等方法共享了一个扩展的 weka.core.Instaces 类。

      table1.makeIndex(table1.attribute("Continent_ID");
      table2.makeIndex(table2.attribute("Continent_ID");
      Instances result = table1.leftJoin(table2);
      

      实例可以有不同数量的属性,NOMINALSTRING 变量的级别在必要时合并在一起。

      来源和一些示例在 GitHub 上:weka.join

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-11
        • 2011-07-22
        • 1970-01-01
        • 1970-01-01
        • 2022-08-23
        • 2013-05-20
        • 1970-01-01
        相关资源
        最近更新 更多