2012-05-27 36 views
2

目前,我從一個數據集一次複製一個實例到另一個。有沒有辦法做到這一點,使字符串映射保持完好? mergeInstances水平工作,是否有一個等效的垂直合併?如何合併兩組weka實例在一起

這是我用來從多個arff文件讀取同一結構的數據集到一個大型數據集的循環的一個步驟。必須有一個更簡單的方法。

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

回答

1

爲什麼不製作一個新的ARFF文件,其中包含來自兩個原件的數據?一個簡單的

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

其中20由然而,許多線路更換渴望你的ARFF頭球。那麼這將產生所有期望的情況下的一個新的ARFF文件,你可以與你現有的代碼讀取這個新文件:http://old.nabble.com/how-to-merge-two-data-file-a.arff-and-b.arff-into-one-data-list--td22890856.html

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

你也可以使用此文件調用命令行上秧雞

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,即追加2個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的本身只是遍歷所有實例的數據集中並打印它們,同樣的過程代碼使用。

+0

我最終迭代了所有實例自己...似乎最簡單。 – fodon

4

如果你想有一個完全的全自動的方法也複製正確的字符串和名義屬性,可以使用以下功能:

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匹配數據1的那些標稱屬性的值修改,您可以使用:

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

這個效果很好。謝謝 – xro7

1

另一種可能的解決方案是使用java.util.AbstractCollection中的addAll,因爲Instances實現它。

instances1.addAll(instances2); 
+0

只需注意,在版本3.6.9實例中不再有該方法,因爲它不從AbstractCollection擴展。 –

+0

如果您使用過濾器,此方法並不總是有效。更多信息:http://stackoverflow.com/q/38460698/3923800 – xro7

0

我剛剛共享的擴展weka.core.Instaces類像innerJoinleftJoinfullJoinupdateunion方法。

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

實例可以有不同數量的屬性,NOMINALSTRING變量的水平合併在一起,如果neccesary。

來源和一些例子在這裏GitHub:weka.join