# Machine Learning :: Cosine Similarity for Vector Space Models (Part III)

* It has been a long time since I wrote the TF-IDF tutorial (Part I and Part II) and as I promissed, here is the continuation of the tutorial. Unfortunately I had no time to fix the previous tutorials for the newer versions of the scikit-learn (sklearn) package nor to answer all the questions, but I hope to do that in a close future.

So, on the previous tutorials we learned how a document can be modeled in the Vector Space, how the TF-IDF transformation works and how the TF-IDF is calculated, now what we are going to learn is how to use a well-known similarity measure (Cosine Similarity) to calculate the similarity between different documents.

## The Dot Product

Let’s begin with the definition of the dot product for two vectors: $\vec{a} = (a_1, a_2, a_3, \ldots)$ and $\vec{b} = (b_1, b_2, b_3, \ldots)$, where $a_n$ and $b_n$ are the components of the vector (features of the document, or TF-IDF values for each word of the document in our example) and the $\mathit{n}$ is the dimension of the vectors:

$\vec{a} \cdot \vec{b} = \sum_{i=1}^n a_ib_i = a_1b_1 + a_2b_2 + \cdots + a_nb_n$

As you can see, the definition of the dot product is a simple multiplication of each component from the both vectors added together. See an example of a dot product for two vectors with 2 dimensions each (2D):

$\vec{a} = (0, 3) \\ \vec{b} = (4, 0) \\ \vec{a} \cdot \vec{b} = 0*4 + 3*0 = 0$

The first thing you probably noticed is that the result of a dot product between two vectors isn’t another vector but a single value, a scalar.

This is all very simple and easy to understand, but what is a dot product ? What is the intuitive idea behind it ? What does it mean to have a dot product of zero ? To understand it, we need to understand what is the geometric definition of the dot product:

$\vec{a} \cdot \vec{b} = \|\vec{a}\|\|\vec{b}\|\cos{\theta}$

Rearranging the equation to understand it better using the commutative property, we have:

$\vec{a} \cdot \vec{b} = \|\vec{b}\|\|\vec{a}\|\cos{\theta}$

So, what is the term $\displaystyle \|\vec{a}\|\cos{\theta}$ ? This term is the projection of the vector $\vec{a}$ into the vector $\vec{b}$ as shown on the image below:

Now, what happens when the vector $\vec{a}$ is orthogonal (with an angle of 90 degrees) to the vector $\vec{b}$ like on the image below ?

There will be no adjacent side on the triangle, it will be equivalent to zero, the term $\displaystyle \|\vec{a}\|\cos{\theta}$ will be zero and the resulting multiplication with the magnitude of the vector $\vec{b}$ will also be zero. Now you know that, when the dot product between two different vectors is zero, they are orthogonal to each other (they have an angle of 90 degrees), this is a very neat way to check the orthogonality of different vectors. It is also important to note that we are using 2D examples, but the most amazing fact about it is that we can also calculate angles and similarity between vectors in higher dimensional spaces, and that is why math let us see far than the obvious even when we can’t visualize or imagine what is the angle between two vectors with twelve dimensions for instance.

## The Cosine Similarity

The cosine similarity between two vectors (or two documents on the Vector Space) is a measure that calculates the cosine of the angle between them. This metric is a measurement of orientation and not magnitude, it can be seen as a comparison between documents on a normalized space because we’re not taking into the consideration only the magnitude of each word count (tf-idf) of each document, but the angle between the documents. What we have to do to build the cosine similarity equation is to solve the equation of the dot product for the $\cos{\theta}$:

$\displaystyle \vec{a} \cdot \vec{b} = \|\vec{a}\|\|\vec{b}\|\cos{\theta} \\ \\ \cos{\theta} = \frac{\vec{a} \cdot \vec{b}}{\|\vec{a}\|\|\vec{b}\|}$

And that is it, this is the cosine similarity formula. Cosine Similarity will generate a metric that says how related are two documents by looking at the angle instead of magnitude, like in the examples below:

Note that even if we had a vector pointing to a point far from another vector, they still could have an small angle and that is the central point on the use of Cosine Similarity, the measurement tends to ignore the higher term count on documents. Suppose we have a document with the word “sky” appearing 200 times and another document with the word “sky” appearing 50, the Euclidean distance between them will be higher but the angle will still be small because they are pointing to the same direction, which is what matters when we are comparing documents.

Now that we have a Vector Space Model of documents (like on the image below) modeled as vectors (with TF-IDF counts) and also have a formula to calculate the similarity between different documents in this space, let’s see now how we do it in practice using scikit-learn (sklearn).

## Practice Using Scikit-learn (sklearn)

* In this tutorial I’m using the Python 2.7.5 and Scikit-learn 0.14.1.

The first thing we need to do is to define our set of example documents:

documents = (
"The sky is blue",
"The sun is bright",
"The sun in the sky is bright",
"We can see the shining sun, the bright sun"
)

And then we instantiate the Sklearn TF-IDF Vectorizer and transform our documents into the TF-IDF matrix:

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(documents)
print tfidf_matrix.shape
(4, 11)

Now we have the TF-IDF matrix (tfidf_matrix) for each document (the number of rows of the matrix) with 11 tf-idf terms (the number of columns from the matrix), we can calculate the Cosine Similarity between the first document (“The sky is blue”) with each of the other documents of the set:

from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity(tfidf_matrix[0:1], tfidf_matrix)
array([[ 1.        ,  0.36651513,  0.52305744,  0.13448867]])

The tfidf_matrix[0:1] is the Scipy operation to get the first row of the sparse matrix and the resulting array is the Cosine Similarity between the first document with all documents in the set. Note that the first value of the array is 1.0 because it is the Cosine Similarity between the first document with itself. Also note that due to the presence of similar words on the third document (“The sun in the sky is bright”), it achieved a better score.

If you want, you can also solve the Cosine Similarity for the angle between vectors:

$\cos{\theta} = \frac{\vec{a} \cdot \vec{b}}{\|\vec{a}\|\|\vec{b}\|}$

We only need to isolate the angle ($\theta$) and move the $\cos$ to the right hand of the equation:

$\theta = \arccos{\frac{\vec{a} \cdot \vec{b}}{\|\vec{a}\|\|\vec{b}\|}}$

The $\arccos$ is the same as the inverse of the cosine ($\cos^-1$).

Lets for instance, check the angle between the first and third documents:
import math
# This was already calculated on the previous step, so we just use the value
cos_sim = 0.52305744
58.462437107432784

And that angle of ~58.5 is the angle between the first and the third document of our document set.

That is it, I hope you liked this third tutorial !

## Related Material

Wikipedia: Dot Product

Wikipedia: Cosine Similarity

Scikit-learn (sklearn) – The de facto Machine Learning package for Python

## 29 thoughts on “Machine Learning :: Cosine Similarity for Vector Space Models (Part III)”

1. Melanie says:

Great tutorial, thanks! One comment and one question 🙂
Comment, in case it helps someone else: a custom tokenizer can be passed to TfidfVectorizer, as explained at http://blog.mafr.de/2012/04/15/scikit-learn-feature-extractio/I had a list of keywords (e.g., “blue car”) I didn’t want to have split into “blue” and “car” and it took me a little while to figure it out.
Question: is there a way to get a list of the features ranked by weight?

2. Sean says:

The tutorials are incredible. They’ve taught me quite a bit.

3. Daniel says:

I like your tutorial and approach of measuring the similarity between documents. Have you also tried to apply the same method to find similarity between datasets in the linked data cloud? E.g. finding similar entities between http://dbpedia.org/ and http://www.geonames.org/. Assume you have a location (city) with Zuerich in DBpedia and like to find the same (similar) entity inside geonames.

4. Marcos Vinícius says:

Great tutorial! Thanks for sharing!

5. Ashim says:

print tfidf_matrix.shape returned a matrix of (21488, 12602) size Which caused a MemoryError. How to handle such matrix of such bigger size as my data keeps on growing. Any Solution Would be a great help

1. neeraj says:

the vectorizer takes in a term called max_features. Limit it to a value, say 5000 or lower, though this would reduce the ability of a vector to uniquely represent a document. Or add some RAM to your machine :-).

6. Isura Nirmal says:

Hi, I found your article while I am searching for a simple explanation for cosine similarity but I read the first two articles too when I found that its “tf-idf”. Actually I cant express my feeling after realizing how precisely you have described the concepts both mathematically ans in simple terms. You have explained each and every mathematical notation which is really helpful.

Finally I must thank you for this wonderful tutorial. Please post other machine learning algorithms too in your simple way of expressing them. That would be really helpful.

1. Great thanks for the feedback Isura. I’ll work on newer tutorials in the near future, just need to get some time to write. See you !

1. Pikakshi says:

Hi Christian,

It was a great tutorial and I tried to replicate the things you described in the tutorial. However, I keep getting a consistent error which doesn’t allow me to calculate cosine scores…its something like,

from sklearn.metrics.pairwise import cosine_similarity
ImportError: cannot import name cosine_similarity

The same error for TfidfVectorizer. I figured there might be something wrong with sklearn.metrics perhaps? Any help that you can provide on this?

1. Hello, please note that some parts of the API has changed since I made this tutorial, so check the version you are using.

1. tessy123 says:

Thanks for the explanation. I just stumbled into your tutorial while I was googling how to eradicate zero dot product results in getting distance between documents but I don’t understand your tfidf_matrix[0:1]
Also where are the functions.
Thank you

7. Eman says:

please, this error appear on terminal
raise ValueError(“empty vocabulary; perhaps the documents only”
ValueError: empty vocabulary; perhaps the documents only contain stop words

why ? what is the solution?

8. yan says:

I like ur post, it is pretty clear and detail oriented, thank you for your hard working and sharing!

9. John Janster says:

Excellent tutorials! Very clear and concise, beats the hell out of anything else I’ve read on the topic. Can’t wait until you write more on this topic!

10. Vivek says:

great…………….. tutorial.
Thank You.

11. Thanks for any other informative web site. Where else may just I get that type of information written in such an ideal approach?I have a
challenge that I am simply now operating on, and I’ve been on thee glance out for sudh info.

12. Sajj says:

Great set of tutorials. Thanks for taking the time to and posting it.
I would really be interested to know how to find the cosine between two different datasets. For instance, how would you find the similarity of the documents in a test set to documents in training set? It’ll be really appreciate it if someone can point me in the right direction.

13. Sandhan Sarma says:

I have read all the three tutorials part-I, II, and now III. They are really very good and simple to understand.
Thanks for these great tutorials. i hope to see more similar tutorials on machine learning, which involves python and scikit-learn.

14. vijay says:

I am getting a memory in using TfidVectorizer.please tell me what could be the reason

15. vijay says:

memoryerror

16. |a|cos(th) is not the projection of vector a onto vector b. It is simply the magnitude of the projection on the x-axis. The actual project of vector a onto vector b is |a|cos(th)*B, where B is the unit vector in the direction of B.

17. Sri Kanajan says:

Thanks for the blog. The one fundamental element this blog does not explain is the derivation of the following:
\vec{a} \cdot \vec{b} = \|\vec{a}\|\|\vec{b}\|\cos{\theta}

18. mind_trap says:

Amazing explanation! Sophisticated simplicity.You saved me loads of time!I can’t thank you enough!

19. Guzdeh says:

Hello,

I also like you tutorial but I wonder how to fit in my own stopwords. I created a classifier, based on some linguistic theory and for that I had to modify English stopwords. Before evaluating my classifier I would like to conduct a cosine similarity test but do not know how to sneak in my stopwords. 😀

regards,

Guzdeh

20. CRISTIANO says: