Open a shared family profile on any streaming app and something odd is going on. Your father's watch history is cricket highlights and news debates. Your elder sister's is Korean dramas. Yours is Bollywood action films and stand-up comedy specials. Nobody typed a description of anyone's taste into the app. Yet every profile gets its own "Recommended for You" row, and it is usually right.
Line up everything every person on the platform has watched and rated, and you get one giant table: a row per person, a column per title, a star rating in each cell where that person actually watched and rated that title, and a blank everywhere else. Across millions of users and thousands of titles, any one person has rated a tiny fraction of what exists, so most of that table is blank. The recommendation engine's entire job is to guess the blanks well enough that the guess feels like it knows you personally.
The standard way to do this is called matrix factorization: take one large table of numbers, mostly holes, and rewrite it as the product of two much smaller tables that, multiplied together, reproduce the numbers you already know, and, as a side effect, fill in the ones you don't. This general strategy, inferring what someone will like from patterns in what many other people liked, is called collaborative filtering, and matrix factorization is its most widely used engine.
From Factoring Numbers to Factoring Matrices
You already know factorization from arithmetic. The number 12 breaks down into 3 × 4, or 2 × 6, or 2 × 2 × 3. Factoring a number means writing it as a product of smaller numbers that multiply back to the original. It doesn't create new information; 12 was always 12. It exposes structure that was hiding inside a single value: 12 is divisible by 3, by 4, by 6, and knowing that helps you simplify fractions and reason about the number instead of treating "12" as an indivisible blob.
Matrix factorization does the same thing to a table of numbers. Instead of one large matrix R (rows are users, columns are movies, entries are ratings), you look for two smaller matrices, U and V, whose product reproduces R:
R ≈ U × Vᵀ
If R has m users and n movies, storing it fully needs m × n numbers. But U is only m × k and V is only n × k, where k is a small number you choose: often somewhere between 10 and 200 for a real streaming service, and just 2 in the worked example ahead. When k is far smaller than m and n, you've compressed the table. Because U and V together assign a value to every cell of R, including the ones that were originally blank, you've also built a machine for predicting the blanks.
There's a name for the number of independent directions needed to fully describe a matrix's rows: its rank. A matrix that can be written exactly as a k-factor product has rank k or lower. Real ratings data is never that clean, but it tends to sit close to low-rank, because human taste isn't actually infinite-dimensional. What makes you rate one film high and another low mostly collapses into a handful of underlying preferences: how much you like action, how much you like comedy, how much you like slow romance, and so on. Matrix factorization is a bet that a small number of hidden dimensions, far fewer than the number of movies that exist, explain almost all of the pattern in the ratings. That bet pays off often enough to power a large share of the recommendation systems running today.
Choosing k is a balancing act. Too small, and U and V don't have enough room to capture real differences in taste, so every prediction starts to blur toward a generic average. Too large, and the model has enough free numbers to fit every known rating almost perfectly, including whatever noise and coincidence happens to be sitting in the data, which makes it worse, not better, at guessing the blanks it has never seen. Real systems settle on k by trying several values and checking which one predicts best on ratings deliberately held back for testing, never by chasing zero error on the ratings used for training.
What Hidden Factors Actually Mean
These hidden dimensions are called latent factors, "latent" meaning present but not directly observed. No streaming platform labels its catalogue with an official action score and comedy score; the data it collects is only ratings. Matrix factorization's job is to discover factors like these on its own, purely from the pattern in the ratings, without ever being told what the factors mean.
To see exactly how, build a version of the problem small enough to compute by hand. Three viewers:
- Aisha loves action, and tolerates a little comedy.
- Rohan loves comedy, and tolerates a little action.
- Meera is a fairly even fan of both.
And three movies, scored purely for this illustration on the same two hidden dimensions, action content and comedy content:
- Pathaan, almost pure action.
- 3 Idiots, almost pure comedy-drama with no action.
- Simmba, a genuine action-comedy carrying real amounts of both.
Worked Example: Reconstructing Ratings by Hand
Give each viewer a taste vector, [action preference, comedy preference], and each movie a content vector, [action content, comedy content], on a simple 0–2 scale:
Aisha = [2, 1] Pathaan = [2, 0]
Rohan = [1, 2] 3 Idiots = [0, 2]
Meera = [1, 1] Simmba = [2, 1]
A predicted rating is the dot product of the matching pair of vectors: multiply the two action numbers, multiply the two comedy numbers, and add the results.
predicted rating = (action pref × action content) + (comedy pref × comedy content)
Trace a few by hand. Aisha rating Pathaan: (2 × 2) + (1 × 0) = 4. Aisha rating Simmba: (2 × 2) + (1 × 1) = 5, a full point higher than Pathaan, because Simmba's touch of comedy adds a little credit on top of the action Aisha already loves. Rohan rating 3 Idiots: (1 × 0) + (2 × 2) = 4. And the one that matters most: Meera, who has never watched Simmba, rated anyway: (1 × 2) + (1 × 1) = 2 + 1 = 3.
Stack all nine viewer-movie predictions into one matrix and every rating any of the three actually gave comes back out exactly:
Pathaan 3 Idiots Simmba
Aisha 4 2 5
Rohan 2 4 4
Meera 2 2 3
As code instead of arithmetic, the whole calculation is one matrix multiplication:
import numpy as np
U = np.array([[2, 1], # Aisha: [action, comedy]
[1, 2], # Rohan
[1, 1]]) # Meera
V = np.array([[2, 0], # Pathaan: [action, comedy]
[0, 2], # 3 Idiots
[2, 1]]) # Simmba
print(U @ V.T)
[[4 2 5]
[2 4 4]
[2 2 3]]
Look closely at Meera's Simmba prediction. She never watched it in this scenario, so that cell should be blank, yet the factorization confidently fills in a 3. Compare that to the laziest possible guess: averaging Meera's two known ratings gives (2 + 2) ÷ 2 = 2. The factored prediction lands a full point higher, and the reason is visible right there in the arithmetic: Simmba is the one movie that draws credit from both of Meera's preferences at once, instead of only one.
The Real Problem: Nobody Hands You the Factors
That example cheated in one important way. It started with the taste vectors and content vectors already known. In the real world, no streaming platform measures "how much action content" a movie has as a clean number; it only observes ratings. The two small matrices, U and V, have to be discovered from the ratings themselves, with nobody telling the algorithm what the hidden dimensions represent, or even how many there are.
This turns into a search problem. Start with random guesses for every number in U and V. Multiply them to get predicted ratings. Compare those predictions against the ratings actually known, and measure how wrong the guess is, usually with squared error: (actual − predicted)², summed over every known rating. That total is the loss, a single number describing how badly the current U and V fit the data.
Then improve it. Gradient descent nudges every number in U and V a small step in whichever direction makes the loss a little smaller. Calculus supplies the direction: the gradient of the loss points toward the steepest increase, so stepping the opposite way decreases it. Repeat that nudge thousands of times, and the random starting guess gradually reshapes itself into a pair of matrices that reproduce the known ratings well. One more detail worth knowing: real systems also add a small regularization penalty that discourages the numbers in U and V from growing unnecessarily large, which keeps the model from memorising noise instead of genuine taste patterns.
Crucially, the loss only ever looks at cells with a known rating. The blank cells stay invisible throughout training. But because U and V are small and shared across every row and column, fitting the known cells well tends to make the blank cells sensible too. That is the entire trick behind every "you might also like" row you have ever seen. It also exposes a genuine weak spot, usually called the cold-start problem: a brand-new viewer who hasn't rated anything has no known cells anywhere in their row, so there is nothing for the loss to fit, and a brand-new movie nobody has rated yet has exactly the same problem in its column. Real platforms typically patch this with something outside factorization entirely for new signups, an onboarding survey or a list of trending titles, until enough real ratings build up for the factorization to take over.
Code Trace: Watching the Algorithm Learn
Hide Meera's Simmba rating from the algorithm completely, and check whether it can recover the value 3 purely by fitting the other eight known ratings.
import numpy as np
# Rows = users, columns = movies. 0 marks the one rating we are hiding.
R = np.array([
[4, 2, 5], # Aisha: Pathaan, 3 Idiots, Simmba
[2, 4, 4], # Rohan
[2, 2, 0], # Meera -> her Simmba rating is unknown (true value: 3)
], dtype=float)
mask = (R != 0).astype(float) # 1 = known rating, 0 = hidden
np.random.seed(42)
k = 2 # number of hidden taste factors
U = np.random.uniform(0.3, 0.8, (3, k)) # user-factor matrix
V = np.random.uniform(0.3, 0.8, (3, k)) # movie-factor matrix
lr, reg, epochs = 0.02, 0.01, 500
for epoch in range(1, epochs + 1):
pred = U @ V.T
error = mask * (R - pred) # only known ratings count
U -= lr * (-2 * error @ V + 2 * reg * U) # nudge U downhill
V -= lr * (-2 * error.T @ U + 2 * reg * V) # nudge V downhill
if epoch in (1, 10, 50, 100, 500):
loss = np.sum(error ** 2)
new_pred = (U @ V.T)[2, 2]
print(f"epoch {epoch:4d} loss={loss:8.4f} predicted Meera-Simmba={new_pred:.3f}")
print("\nFull reconstructed matrix:\n", np.round(U @ V.T, 2))
epoch 1 loss= 58.1370 predicted Meera-Simmba=0.724
epoch 10 loss= 3.6839 predicted Meera-Simmba=2.664
epoch 50 loss= 0.0020 predicted Meera-Simmba=2.982
epoch 100 loss= 0.0002 predicted Meera-Simmba=2.991
epoch 500 loss= 0.0002 predicted Meera-Simmba=2.992
Full reconstructed matrix:
[[3.99 2. 4.99]
[2. 3.99 4. ]
[1.99 2. 2.99]]
The algorithm starts badly. After one update, its prediction for Meera's Simmba rating is 0.724, and the total squared error across the eight known ratings is 58.14. Ten updates in, the loss has already fallen by more than 90%, and the prediction has climbed to 2.66. By epoch 50 the loss has essentially vanished, down to 0.002 from 58, and the prediction has settled at 2.98. From epoch 100 onward almost nothing changes; the algorithm has converged. Its final prediction for a rating it was never shown: 2.99. The true value, withheld from it the entire time, was exactly 3.
Two things are worth sitting with. First, the algorithm never saw the number 3 anywhere in its input; it reconstructed it purely from the structure shared across the other eight ratings. Second, look at what U and V actually converge to; run the code and print them, and they will not look like the neat [2, 1]-style vectors from the hand-worked example, even though they reproduce the same ratings. That is expected, not a bug. Double every number in U and halve every number in V, and the product U @ V.T does not change at all, so there are infinitely many equally valid ways to split credit between the two matrices. Gradient descent finds one valid split, not necessarily the split a human would have labelled "action" and "comedy." The product is what matters, not the individual numbers.
Beyond Movies: Matrix Factorization at Work
Recommendation is the most visible use of matrix factorization, but far from the only one. The same blank-filling trick works wherever many people interact with many items and only a sliver of the possible pairs is ever observed: which products a shopper on an e-commerce site has bought, which songs a listener has replayed, which restaurants a food-delivery app's users have ordered from. Swap "movie" for "product" or "song," and the matrix, the factorization, and the gradient-descent loop above are otherwise unchanged.
The technique's reputation in machine learning was cemented by the Netflix Prize. In 2006, Netflix publicly offered $1,000,000 to whoever could improve the accuracy of its recommendation engine by at least 10% over its existing system, measured on ratings the competing teams never got to see. It took the community about three years to cross that bar. Nearly every leading entry, including the eventual winning team, leaned heavily on matrix factorization, much of it directly inspired by a gradient-descent approach a competitor named Simon Funk described in a widely read 2006 write-up: multiply two small factor matrices, compare against known ratings, and nudge the factors to shrink the error, essentially the same process traced above.
Funk's method is sometimes loosely called an "SVD" approach, after Singular Value Decomposition, the classical, fully determined form of matrix factorization taught in linear algebra. True SVD needs every entry of the matrix already filled in, and it produces a factorization that is unique up to sign rather than one of infinitely many equally valid splits, which is exactly why it cannot be applied directly to ratings data full of blanks. Where SVD does apply directly is anywhere the full matrix is already known with no missing entries. A grayscale image is nothing but a matrix of brightness values, one number per pixel, with no blanks at all. Running SVD on that matrix and keeping only its most significant components gives a smaller matrix pair that reconstructs a close approximation of the original image. A 1000 × 1000 pixel image is a million numbers; keeping the top 50 components needs two 1000 × 50 matrices plus 50 singular values, just over 100,000 numbers in total, a roughly tenfold saving with the image still clearly recognisable.
The same underlying idea, finding a small number of directions that account for almost all of the pattern in a large table, also underpins Principal Component Analysis, used to compress many correlated columns of data down to a few informative ones, and topic modelling in text search, where documents and words both get reduced to a handful of hidden "topics" in exactly the way viewers and movies were reduced to hidden genres above.
Back to Your Screen
Real recommendation engines run the same process traced above, just at a scale too large to picture by hand: millions of viewers, tens of thousands of titles, and somewhere between 20 and 200 latent factors instead of 2. Nobody labels those factors "action" or "comedy." Like the numbers gradient descent actually produced for Aisha, Rohan, and Meera, they usually end up as columns of numbers with no obvious human meaning, just directions the optimiser found useful for predicting ratings accurately. That is precisely why your father's cricket-and-news row, your sibling's Korean dramas, and your own action-and-comedy recommendations can all come out of the exact same few lines of matrix multiplication, run on the exact same underlying model, just with three very different rows of a matrix called U.
The vectors packed into U and V have another name worth knowing if you go further into AI: embeddings. A modern neural network's internal understanding of a word, a face, or a product is, at its core, a list of numbers much like Aisha's [2, 1]: a compressed, learned position in some hidden space, arrived at the same way Meera's Simmba rating was: starting random and nudging downhill until the numbers become useful. Matrix factorization is the simplest working version of an idea that runs through most of modern machine learning.
The next time a recommendation lands that feels a little too accurate, you now know what is actually behind it: not a human editor, and not a rule someone wrote by hand, but two comparatively small matrices, multiplied together, filling in a blank the way Meera's Simmba rating got filled in above, by borrowing structure from everything else the system already knew.
Think About It
Think about this: How would you explain matrix factorization: breaking down data to a friend who has never seen a computer? What real-world analogy would you use? Imagine you had to build a system using these concepts — what would be your first step? Try this: before moving on, write down three things you learned and one question you still have.
Practice Exercises
Now it is time to practice! Complete these challenges to solidify your understanding:
- Exercise 1: Write a short program that demonstrates the core concept from this chapter. Test it with at least 3 different inputs.
- Exercise 2: Find a real-world example where matrix factorization: breaking down data is used in an Indian company (like TCS, Infosys, Flipkart, or ISRO). Write a paragraph explaining the connection.
- Exercise 3: Create a mind-map connecting matrix factorization: breaking down data to at least 3 other topics you have studied.
Key Takeaways — Summary and Recap
Let us recap what we covered: the core ideas behind matrix factorization: breaking down data, how they connect to real-world applications, and why they matter for your journey in computer science. Remember these key points as you move forward. For competitive exam preparation (CBSE, JEE, BITSAT), focus on understanding the WHY behind each concept, not just the WHAT.