Я получаю разные результаты каждый раз, когда я запускаю свой код
Я использую 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 ответа
Я бы сказал, так как вы используете RandomlyGeneratedInitialMeans
:
Инициализация k-средних путем генерации случайных векторов (в пределах диапазона значений наборов данных).
RandomlyGeneratedInitialMeans init = new RandomlyGeneratedInitialMeans(RandomFactory.DEFAULT);
Да, это нормально.
Предполагается, что K-Means инициализируется случайным образом. Желательно получать разные результаты при многократном запуске.
Если вы не хотите этого, используйте фиксированное случайное начальное число.
Из кода, который вы копируете и вставляете:
// To fix the random seed, use: new RandomFactory(seed);
Это именно то, что вы должны сделать...
long seed = 0;
RandomlyGeneratedInitialMeans init = new RandomlyGeneratedInitialMeans(
new RandomFactory(seed));
Это было слишком долго для комментария. Как сказал @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
по алгоритму. Результаты должны становиться все более стабильными, чем больше вы запускаете алгоритм.