Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
🔢 Week 2 – NumPy & Pandas  ·  Day 09

Day 9: NumPy Maths, Broadcasting & Random

⏱ 2 hours📶 Beginner → Intermediate🎯 100% self-study
Day 9 / 60

✅ Today you will learn

  • Vectorised maths on whole arrays
  • Broadcasting: maths between different shapes
  • Aggregations: sum, mean, std, percentile, cumsum
  • np.where, clip, unique and sorting
  • Random numbers and a Monte Carlo simulation

🏢 In the real world

An e-commerce company wants to know: “If we give 10% off in every city but 20% off in metro cities, what will the new prices be for 50,000 products?” Broadcasting answers it in one line, and a random simulation estimates the risk.

Vectorised maths

Python
import numpy as np
prices = np.array([499, 1299, 2499, 89, 15999])
qty = np.array([3, 1, 2, 10, 1])
print("Revenue per item:", prices * qty)
print("With 18% GST    :", (prices * 1.18).round(2))
print("Log prices      :", np.log10(prices).round(2))
print("Total revenue   :", (prices * qty).sum())
Revenue per item: [ 1497 1299 4998 890 15999] With 18% GST : [ 588.82 1532.82 2948.82 105.02 18878.82] Log prices : [2.7 3.11 3.4 1.95 4.2 ] Total revenue : 24683

Broadcasting

Broadcasting lets NumPy combine arrays of different shapes by stretching the smaller one – no copies, no loops. Rule: compare shapes from the right; sizes must be equal or 1.

A shapeB shapeResultWorks?
(5,)() scalar(5,)✅
(4, 3)(3,)(4, 3)✅ row repeated
(4, 3)(4, 1)(4, 3)✅ column repeated
(4, 3)(4,)—❌ 3 ≠ 4
Python
import numpy as np
# 3 cities × 4 products base prices
base = np.array([[100, 250, 400, 1200],
                 [110, 260, 420, 1250],
                 [ 95, 240, 390, 1180]])
city_discount = np.array([[0.20], [0.20], [0.10]])     # shape (3, 1): metro, metro, small city
product_gst = np.array([0.05, 0.12, 0.18, 0.18])       # shape (4,)
final = base * (1 - city_discount) * (1 + product_gst)
print(final.round(1))
[[ 84. 224. 377.6 1132.8] [ 92.4 233. 396.5 1180. ] [ 89.8 241.9 414.2 1253.2]]
Python
import numpy as np
scores = np.array([[78, 82, 69], [92, 88, 95], [65, 70, 58], [88, 79, 84]])
col_mean = scores.mean(axis=0)
print("Centred (score - subject mean):")
print((scores - col_mean).round(1))
z = (scores - scores.mean(axis=0)) / scores.std(axis=0)
print("Z-scores:")
print(z.round(2))
Centred (score - subject mean): [[ -2.8 2.2 -7.5] [ 11.2 8.2 18.5] [-15.8 -9.8 -18.5] [ 7.2 -0.8 7.5]] Z-scores: [[-0.26 0.35 -0.53] [ 1.08 1.27 1.31] [-1.51 -1.5 -1.31] [ 0.7 -0.12 0.53]]

Aggregations

Python
import numpy as np
daily_sales = np.array([42, 55, 38, 61, 70, 95, 88, 47, 52, 49, 66, 91, 99, 58])   # in thousands ₹
print("sum", daily_sales.sum(), "| mean", daily_sales.mean().round(2), "| median", np.median(daily_sales))
print("std", daily_sales.std().round(2), "| min", daily_sales.min(), "| max", daily_sales.max())
print("25th/75th percentile:", np.percentile(daily_sales, [25, 75]))
print("Running total:", daily_sales.cumsum()[:7])
print("Day-on-day change:", np.diff(daily_sales)[:6])
sum 911 | mean 65.07 | median 59.5 std 19.75 | min 38 | max 99 25th/75th percentile: [49.75 83.5 ] Running total: [ 42 97 135 196 266 361 449] Day-on-day change: [ 13 -17 23 9 25 -7]

np.where, clip, unique, sort

Python
import numpy as np
marks = np.array([35, 82, 47, 91, 28, 66, 73])
print(np.where(marks >= 40, "Pass", "Fail"))
print(np.select([marks >= 75, marks >= 40], ["Distinction", "Pass"], default="Fail"))
print(np.clip(marks + 15, 0, 100))                 # grace marks, max 100
cities = np.array(["Pune", "Delhi", "Pune", "Agra", "Delhi", "Pune"])
vals, counts = np.unique(cities, return_counts=True)
print({str(v): int(c) for v, c in zip(vals, counts)})
print(np.sort(marks)[::-1], np.argsort(marks)[::-1][:3])
['Fail' 'Pass' 'Pass' 'Pass' 'Fail' 'Pass' 'Pass'] ['Fail' 'Distinction' 'Pass' 'Distinction' 'Fail' 'Pass' 'Pass'] [ 50 97 62 100 43 81 88] {'Agra': 1, 'Delhi': 2, 'Pune': 3} [91 82 73 66 47 35 28] [3 1 6]

Random numbers

Python
import numpy as np
rng = np.random.default_rng(42)           # modern, reproducible generator
print(rng.integers(1, 7, size=10))        # 10 dice rolls
print(rng.random(3).round(3))             # 0–1 uniform
heights = rng.normal(loc=165, scale=8, size=1000)   # mean 165 cm, sd 8
print("mean", heights.mean().round(1), "| sd", heights.std().round(1))
print(rng.choice(["UPI", "Card", "Cash"], size=8, p=[0.6, 0.25, 0.15]))
[1 5 4 3 3 6 1 5 2 1] [0.976 0.761 0.786] mean 164.8 | sd 7.9 ['Card' 'UPI' 'UPI' 'UPI' 'Card' 'Cash' 'UPI' 'Card']
Python
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(42)
heights = rng.normal(165, 8, 5000)
plt.hist(heights, bins=40, color="#0ea5e9", edgecolor="white")
plt.axvline(heights.mean(), color="red", linestyle="--", label=f"mean {heights.mean():.1f} cm")
plt.title("5,000 simulated student heights")
plt.xlabel("Height (cm)"); plt.ylabel("Students"); plt.legend()
plt.show()
Histogram of simulated heights forming a bell curve
rng.normal creates the familiar bell curve (more on Day 28).

Real example: Monte Carlo risk simulation

A small café sells between 80 and 160 cups a day (average 120). Each cup earns ₹35 profit and fixed costs (rent, staff, electricity) are ₹4,100 a day. What is the chance of making a loss in a month? We simulate 10,000 months.

Python
import numpy as np
rng = np.random.default_rng(7)
months, days = 10_000, 30
cups = rng.normal(120, 22, size=(months, days)).clip(80, 160)    # broadcasting-friendly 2-D array
profit = (cups * 35 - 4100).sum(axis=1)                          # one value per month
print("Average monthly profit: ₹", round(profit.mean()))
print("Worst 5% month       : ₹", round(np.percentile(profit, 5)))
print("Chance of a loss     :", f"{(profit < 0).mean():.2%}")
print("Chance profit > ₹10,000:", f"{(profit > 10000).mean():.1%}")
Average monthly profit: ₹ 3008 Worst 5% month : ₹ -3555 Chance of a loss : 22.37% Chance profit > ₹10,000: 4.0%
💡 Why simulate?

When maths formulas get hard, generating thousands of random “what-if” worlds gives a reliable answer. Banks, insurers and supply-chain teams use Monte Carlo every day.

🏅 Job skills unlocked today

✔ Vectorise business calculations✔ Apply broadcasting across rows and columns✔ Summarise with percentiles and cumsum✔ Run reproducible random simulations

Practice tasks

🏋️ Practice – do it yourself

Task 1: Convert temperatures [30, 35, 41, 28] °C to °F (F = C × 9/5 + 32) in one line.
Show solution
Python
import numpy as np
c = np.array([30, 35, 41, 28])
print(c * 9 / 5 + 32)
[ 86. 95. 105.8 82.4]
Task 2: A 3×3 array has sales of 3 shops (rows) for 3 months. Express each value as a % of its shop’s total.
Show solution
Python
import numpy as np
s = np.array([[120, 150, 130], [80, 95, 125], [200, 180, 220]])
print((s / s.sum(axis=1, keepdims=True) * 100).round(1))
[[30. 37.5 32.5] [26.7 31.7 41.7] [33.3 30. 36.7]]
Task 3: Simulate 100,000 rolls of two dice and estimate the probability that the total is 7.
Show solution
Python
import numpy as np
rng = np.random.default_rng(1)
rolls = rng.integers(1, 7, size=(100000, 2)).sum(axis=1)
print(round((rolls == 7).mean(), 4), "(exact = 1/6 = 0.1667)")
0.1662 (exact = 1/6 = 0.1667)

Quick quiz

🧠 Quick Quiz – test yourself

1. Shapes (4, 3) and (3,) broadcast to…
The (3,) row is repeated for all 4 rows.
2. np.where(a > 0, a, 0) does…
Where the condition is False, the third argument is used.
3. Why call default_rng(42)?
A fixed seed makes random results repeatable.
4. np.percentile(x, 50) equals…
The 50th percentile is the median.
5. cumsum of [2, 3, 5] is…
Running totals: 2, 2+3, 2+3+5.

Interview corner

💼 Interview Corner

Explain broadcasting with an example.

Subtracting a (3,) array of column means from a (100, 3) matrix: NumPy virtually repeats the mean row 100 times and subtracts element-wise, without loops or extra memory. Shapes are compared from the right and must be equal or 1.

What is a Monte Carlo simulation?

Estimating an uncertain quantity by running the process many times with random inputs and summarising the outcomes – for example the probability of a monthly loss or the range of project costs.

Summary

  • Maths on arrays works element-wise – no loops.
  • Broadcasting combines shapes like (4,3) with (3,) or (4,1).
  • sum, mean, std, percentile, cumsum summarise data fast.
  • default_rng(seed) gives reproducible simulations.
➡️ Next

Day 10: pandas – Series and DataFrames, the tables every data scientist uses all day.

Frequently Asked Questions

np.random.seed or default_rng?
New code should use rng = np.random.default_rng(seed). The old np.random.seed still works but the Generator API is faster and safer.
What is keepdims=True?
It keeps the reduced axis with size 1, so the result broadcasts back against the original array – handy for percentages of row totals.
← Data Science (60 Days)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicDay 10: Pandas Series & DataFrame Your progress: 9 / 60 (15%) · Lesson 10 / 60 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free