每次运行代码时,我都会得到不同的结果

时间:2016-03-10 12:20:49

标签: java cluster-analysis elki

我正在使用ELKI对我使用KMeansLloyd<NumberVector> with k=3的数据进行聚类每次运行我的java代码我都会得到完全不同的聚类结果,这是正常的还是有的我应该做些什么来使我的输出几乎稳定?这里是我从elki教程获得的代码

DatabaseConnection dbc = new ArrayAdapterDatabaseConnection(a);
    // Create a database (which may contain multiple relations!)
    Database db = new StaticArrayDatabase(dbc, null);
    // Load the data into the database (do NOT forget to initialize...)
    db.initialize();
    // Relation containing the number vectors:
    Relation<NumberVector> rel = db.getRelation(TypeUtil.NUMBER_VECTOR_FIELD);
    // We know that the ids must be a continuous range:
    DBIDRange ids = (DBIDRange) rel.getDBIDs();

    // K-means should be used with squared Euclidean (least squares):
    //SquaredEuclideanDistanceFunction dist = SquaredEuclideanDistanceFunction.STATIC;
    CosineDistanceFunction dist= CosineDistanceFunction.STATIC;

    // Default initialization, using global random:
    // To fix the random seed, use: new RandomFactory(seed);
    RandomlyGeneratedInitialMeans init = new RandomlyGeneratedInitialMeans(RandomFactory.DEFAULT);

    // Textbook k-means clustering:
    KMeansLloyd<NumberVector> km = new KMeansLloyd<>(dist, //
    3 /* k - number of partitions */, //
    0 /* maximum number of iterations: no limit */, init);

    // K-means will automatically choose a numerical relation from the data set:
    // But we could make it explicit (if there were more than one numeric
    // relation!): km.run(db, rel);
    Clustering<KMeansModel> c = km.run(db);

    // Output all clusters:
    int i = 0;
    for(Cluster<KMeansModel> clu : c.getAllClusters()) {
      // K-means will name all clusters "Cluster" in lack of noise support:
      System.out.println("#" + i + ": " + clu.getNameAutomatic());
      System.out.println("Size: " + clu.size());
      System.out.println("Center: " + clu.getModel().getPrototype().toString());
      // Iterate over objects:
      System.out.print("Objects: ");

      for(DBIDIter it = clu.getIDs().iter(); it.valid(); it.advance()) {
        // To get the vector use:
         NumberVector v = rel.get(it);

        // Offset within our DBID range: "line number"
        final int offset = ids.getOffset(it);
        System.out.print(v+" " + offset);
        // Do NOT rely on using "internalGetIndex()" directly!
      }
      System.out.println();
      ++i;
    } 

3 个答案:

答案 0 :(得分:5)

我会说,因为你正在使用RandomlyGeneratedInitialMeans

  

通过生成随机向量(在数据集值范围内)初始化k均值。

RandomlyGeneratedInitialMeans init = new RandomlyGeneratedInitialMeans(RandomFactory.DEFAULT);

是的,这是正常的。

答案 1 :(得分:2)

K-Means 假定随机初始化。在多次运行时获得不同的结果是理想

如果您不想这样,使用固定的随机种子

从您复制和粘贴的代码:

// To fix the random seed, use: new RandomFactory(seed);

这正是你应该做的......

long seed = 0;
RandomlyGeneratedInitialMeans init = new RandomlyGeneratedInitialMeans(
  new RandomFactory(seed));

答案 2 :(得分:0)

评论太长了。正如@Idos所说,您正在随机初始化您的数据;这就是为什么你得到随机结果的原因。现在的问题是,您如何确保结果稳健?试试这个:

运行算法N次。每次都记录每次观察的集群成员资格。完成后,将观察分类到最常包含它的群集中。例如,假设您有3个观察值,3个类,并运行算法3次:

obs R1  R2  R3
1   A   A   B
2   B   B   B
3   C   B   B

然后,您应将obs1归类为A,因为它通常被归类为A。将obs2归类为B,因为它始终归类为B。并将obs3归类为B,因为它通常被算法归类为B。运行算法的次数越多,结果就越稳定。