Weighted Scoring with @
A practical use of matrix multiplication: compute fantasy-cricket points for every player in one line by multiplying a stats matrix with a weights vector.
Matrix multiplication is the backbone of linear regression, neural networks and recommendation systems — but you can understand why with a simple fantasy-cricket problem. A fantasy platform gives 1 point per run, 25 points per wicket and 10 points per catch. We want every player's total, in one operation.
Definition
A weighted sum multiplies each value by a weight (how much it counts) and adds the results:
score = runs×1 + wickets×25 + catches×10. Computing a weighted sum for every row of a data matrix at once is exactly a matrix–vector product:stats @ weights.
- Stats matrix — shape
(players, features): one row per player, one column per stat. - Weights — one number per feature (column), shape
(features,)or(features, 1). - Result — one score per player, shape
(players,)or(players, 1).
This is literally how a linear model predicts: predictions = X @ w, where X holds the features and w the learned weights.
Syntax
python
scores = stats @ weights # weights 1D (k,) -> scores (n,)
scores = stats @ weights_col # weights (k, 1) -> scores (n, 1)
scores = (stats * weights).sum(axis=1) # same numbers, via broadcasting| Item | Shape | Meaning |
|---|---|---|
stats | (n, k) | n players × k stats |
weights | (k,) or (k, 1) | points for each stat |
schemes | (k, s) | s different weight columns (scoring systems) at once |
| result | (n,), (n, 1) or (n, s) | weighted score per player (per scheme) |
Example — fantasy points for one match
python
import numpy as np
PLAYERS = ["Virat", "Rohit", "Hardik", "Shubman", "Shreyas"]
match_stats = np.array([
[72, 0, 1], # Virat: 72 runs, 0 wickets, 1 catch
[56, 0, 0], # Rohit: 56 runs, 0 wickets, 0 catches
[12, 2, 1], # Hardik: 12 runs, 2 wickets, 1 catch
[33, 0, 2], # Shubman: 33 runs, 0 wickets, 2 catches
[45, 1, 0], # Shreyas: 45 runs, 1 wicket, 0 catches
])
point_values = np.array([[1], [25], [10]]) # per run, per wicket, per catch
fantasy_points = match_stats @ point_values
print("shapes:", match_stats.shape, "@", point_values.shape, "->", fantasy_points.shape)
for name, pts in zip(PLAYERS, fantasy_points[:, 0]):
print(f" {name:<8} {pts:>4} points")
print("Hardik by hand:", 12*1 + 2*25 + 1*10)text
shapes: (5, 3) @ (3, 1) -> (5, 1)
Virat 82 points
Rohit 56 points
Hardik 72 points
Shubman 53 points
Shreyas 70 points
Hardik by hand: 72How it works: (5, 3) @ (3, 1) → (5, 1). Each player's row [runs, wickets, catches] is dotted with the column [1, 25, 10]. Hardik: 12×1 + 2×25 + 1×10 = 72. One line computes all five players — or five million.
Example — 1D weights, and the broadcasting equivalent
python
weights = np.array([1, 25, 10]) # 1D vector
print(match_stats @ weights) # shape (5,)
print((match_stats * weights).sum(axis=1))text
[82 56 72 53 70]
[82 56 72 53 70]With a 1D weight vector you get a flat 1D result, which is usually more convenient. The second line does the same maths in two steps (broadcast multiply, then sum each row) — useful to understand, but @ is shorter and faster.
Example — compare two scoring systems at once
python
schemes = np.array([[1, 1], # points per run (scheme A, scheme B)
[25, 30], # points per wicket
[10, 8]]) # points per catch
print(match_stats @ schemes)text
[[82 80]
[56 56]
[72 80]
[53 49]
[70 75]](5, 3) @ (3, 2) → (5, 2): column 0 is scheme A, column 1 is scheme B. Scheme B (more for wickets, less for catches) helps the all-rounders Hardik and Shreyas. Each extra column of weights = one extra column of results, still a single operation.
Where this pattern appears
| Field | Matrix | Weights | Result |
|---|---|---|---|
| Fantasy cricket | player stats | points per stat | fantasy score |
| Linear regression | features X | coefficients w | predictions |
| Neural network layer | inputs | weight matrix | next layer's activations |
| Shopping cart | quantities | prices | bill per customer |
| Exam grading | marks per section | section weightage | final grade |
Common mistakes
- ❌ Weights in the wrong order (
[25, 1, 10]when columns are runs, wickets, catches). ✅ The i-th weight must match the i-th column. - ❌
match_stats * point_valueswithpoint_valuesof shape(3, 1)→ broadcasting error or wrong shape. ✅ Use@for weighted sums. - ❌ Forgetting that a
(k, 1)weight column gives a(n, 1)result — thenprint(result[2])shows[72], not72. ✅ Use a 1D weight vector, or.ravel()the result.
Interview tip
Q: How is a linear-regression prediction computed in NumPy?
A: y_pred = X @ w + b — the feature matrix X of shape (n_samples, n_features) times the weight vector w of shape (n_features,) gives one prediction per sample; the bias b is added by broadcasting.
Key points to remember
- A weighted sum multiplies each value by its weight and adds the results.
- stats @ weights computes a weighted sum for every row in one operation.
- (n, k) @ (k,) gives a 1D result (n,); (n, k) @ (k, 1) gives a column (n, 1).
- Several weight columns (k, s) give s scores per row at once: (n, k) @ (k, s) → (n, s).
- (stats * weights).sum(axis=1) gives the same numbers via broadcasting.
- This is the same maths as linear-model predictions: X @ w.
Try it yourself
Fantasy points in one line
Two scoring schemes side by side
Practice: add a new stat
Revision Flashcards
Tap a card to flip it and see the answer.
