In a good word embedding, the step from a country to its capital points in roughly the same direction for every country. That makes analogies computable: "a is to b as c is to ?" is answered by the word whose vector is closest to b - a + c.
Write analogy(vectors, a, b, c, k) that returns the k best answers as a list of (word, similarity) pairs, best first:
- Normalise every vector to length 1 (divide it by its Euclidean length).
- Compute the target
t = b̂ - â + ĉfrom the normalised vectors of the three question words. - Score every other word
w(nota,borc) by the cosine similarity oftandŵ,t·ŵ / |t|(or0.0iftis all zeros), rounded to 9 decimal places. - Sort by score, highest first, breaking ties by the word in alphabetical order, and return the first
k.
word_vectors(dim, seed) builds the test vocabularies (twelve countries with their capitals and languages, in dim dimensions); it is available in your code.
Examples
Input: vectors = {"cat": [1, 0], "kitten": [1, 1], "dog": [0, 1], "puppy": [-1, 1], "car": [1, -1]},
a = "cat", b = "kitten", c = "dog", k = 2
Output: [("puppy", 0.816496581), ("car", -0.816496581)]
Explanation: with unit vectors the target is [0.7071 - 1 + 0, 0.7071 - 0 + 1] = [-0.2929, 1.7071].
Input: vectors = word_vectors(12, 1), a = "france", b = "paris", c = "italy", k = 3
Output: [("rome", 0.915419548), ("stockholm", 0.779619456), ("ankara", 0.766061459)]
Constraints
- 3 to 500 words, 2 to 50 dimensions,
1 <= k <= 10;a,bandcare different words - no vector is all zeros
Goals
- Normalise embedding vectors so that only their directions count
- Answer an analogy by adding and subtracting embeddings
- Search the vocabulary for the nearest word to the result, excluding the question words