<p>I don't have the code but you could take a look at this archive paper : <a href="https://arxiv.org/abs/1905.05667" rel="nofollow noreferrer">https://arxiv.org/abs/1905.05667</a> and its references</p>

<p>and Demo code for dbscan algorithm on sklearn <a href="https://scikit-learn.org/stable/auto_examples/cluster/plot_dbscan.html" rel="nofollow noreferrer">https://scikit-learn.org/stable/auto_examples/cluster/plot_dbscan.html</a></p>

<p>I came across these while looking for unsupervised clustering evaluation metrics</p>

<p>edit: this post is also useful - <a href="https://stats.stackexchange.com/questions/79028/performance-metrics-to-evaluate-unsupervised-learning">https://stats.stackexchange.com/questions/79028/performance-metrics-to-evaluate-unsupervised-learning</a></p>
Testing unsupervised KMeans
<p>I'm using the <a href="http://scikit-learn.org/stable/auto_examples/text/document_clustering.html#example-text-document-clustering-py" rel="nofollow">sklearn tutorials</a> on text clustering to find any interesting grouping on reviews of beers.  So far it has been working out fine for me, however when it comes to testing, or finding the right parameters I've tried looping through different cluster numbers:</p>

<pre><code>for clusters in range(3, 10):
    km = KMeans(n_clusters = clusters, init="k-means++", max_iter=100, n_init=1)
    km.fit(vectorizer_fit)
    order_centroids = km.cluster_centers_.argsort()[:, ::-1]
    for i in range(clusters):
        print("Cluster %d:" %i, end="")
        for ind in order_centroids[i, :10]:
            print(" %s"%terms[ind],end=",")
        print()
</code></pre>

<p>it helps weed out some obvious choices (clusters 6+) start getting weird, or containing the beer's name:</p>

<pre><code>Cluster 1: julius, th, treehouse, ego, alter, papaya, dipa, melon, canned, dankness
Cluster 7: citra, farmstead, dipa, hf, apa, passion, abner, nelson, mosaic, papaya 
</code></pre>

<p>And then tried using diffrent max/min_df:</p>

<pre><code>for x in range(40):
    tfidf_vector = TfidfVectorizer(max_df = (.8-(x * .01)), min_df = .2, \
                                    stop_words = "english", use_idf = True)
    tfidf_matrix = tfidf_vector.fit_transform(documents)
    km = KMeans(5)
    km.fit(tfidf_matrix)
    order_centroids = km.cluster_centers_.argsort()[:, ::-1]

    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    print("With max_df @ %d% " % ()(.80 - (x*.01))*100))
    for i in range(5):
        print("cluster %d words: " % i, end = "") 
        for ind in order_centroids[i, :10]:               #top N number of words
            print("%s "% vocab.ix[ind].values, end = ",") #lookup centroid number as vocab index
    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
</code></pre>

<p>which helped find good points to eliminate most some stop words:</p>

<pre><code>With max_df @ 80%: ['the'] ,['here'] ,['a'] ,['true'] ,['roasted'] ,['imparted'] ,['some'] ,['through'] ,['beer'] ,['such']
With max_df @ 60%: ['do'] ,['coffee'] ,['is'] ,['alcohol'] ,['retention'] ,['dry'] ['with'] ,['regular'] ,['little'] ,['speedway']
</code></pre>

<p>And I could hypothetically try looping through both at the same time, but at some point reading it and making a human judgement on the best doesn't seem the...computer scientist way.  Is there any way to evaluate unsupervised methods, without an exact business question in mind?</p>