# Cluster documents based on topic similarity

I have set of documents where I have assigned topics per each document.

E.g., Topics of document 1 -> 1.0 Science, 1.0 politics, 0.8 History, 0. 8 Information and Technology

Now I want to cluster these documents and find what are the documents that share similar like topics.

PS: I am interested in something like this -> https://www.quora.com/How-do-I-cluster-documents-using-topic-models However, the topics assigned for my documents varies

• This is not a topic modeling problem. Once you have document embeddings, you can use any clustering algorithm you like. Try a few. – Emre Jun 27 '17 at 7:58
• I am interested in something like this. quora.com/How-do-I-cluster-documents-using-topic-models However, unlike this, my topic assigned for each document varies – Smith Jun 27 '17 at 9:54
• Aren't the topics common across documents? If not, how are you obtaining them? It's the weights that should differ. Some of them might be zero. – Emre Jun 27 '17 at 15:22

As @Emre suggested, if you already have the distribution of topics in each document, you can represent each document as a vector $x_d \in \mathbb{R}^N$, where $N$ is the number of the unique topics in your collection. For documents, not exhibiting specific topics just fill the specific cells in each feature vector with zeros. Then, you can use some clustering algorithm such as nearest neigbors, using those feature vectors.

Example usage code in python below:

import pandas as pd
import numpy as np
from sklearn.metrics import pairwise_distances

# Initialize some documents
doc1 = {'Science':0.7, 'History':0.05, 'Politics':0.15, 'Sports':0.1}
doc2 = {'News':0.3, 'Art':0.5, 'Politics':0.1, 'Sports':0.1}
doc3 = {'Science':0.8, 'History':0.1, 'Politics':0.05, 'News':0.1}
doc4 = {'Science':0.2, 'Weather':0.2, 'Art':0.6, 'Sports':0.1}
collection = [doc1, doc2, doc3, doc4]
df = pd.DataFrame(collection)
# Fill missing values with zeros
df.fillna(0, inplace=True)
# Get Feature Vectors
feature_matrix = df.as_matrix()

# Get cosine similarity (i.e. 1 - cosine_distance) between pairs
sims = 1-pairwise_distances(feature_matrix, metric='cosine')

# Get the ranking of the documents given document 0
# from most similar to least similar. Don't take into account
# the first document, because it will be the same that the query was about
ranking_1 = np.argsort(sims[0,:])[::-1][1:2]
print ranking_1

ranking_2 = np.argsort(sims[1,:])[::-1][1:2]
print ranking_2


This takes 4 documents with $N=7$ unique topics, fills missing values with zeros and creates a similarity matrix between all documents. Then querying for documents 1(Science=0.7) and 2(Art:0.5) the most similar other document in the collection, we surely get documents 3(Science:0.8) and 4(Art:0.6) correspondingly.

You can try more sophisticated approaches regarding clustering and other distance metrics.

### Topics are clusters

There is next to no difference between subspace clustering and topic modeling, except maybe that text is sparse and integer while subspace clusterers usually assume dense and continuous data.

So rather than trying to cluster again, just use your topics.

Yes, documents can belong to multiple topics. That is because text usually is this way, and forcing everything to have a unique label reduces the quality, because it cannot reflect reality anymore.

If you insist every document should have a unique cluster, just use argmax(topic weights).