AI Computer Institute
Expert-curated CS & AI curriculum aligned to CBSE standards. A bharath.ai initiative. About Us

Python for Data Science: NumPy, Pandas, Matplotlib

📚 Data Science & Programming⏱️ 21 min read🎓 Grade 10
✍️ AI Computer Institute Editorial Team Updated: August 2026 CBSE-aligned · Peer-reviewed · 21 min read
Content curated by subject matter experts with IIT/NIT backgrounds. All chapters are fact-checked against official CBSE/NCERT syllabi.

The Notebook Problem

Priya runs a small photocopy-and-stationery shop outside a college gate in Pune. Every evening after closing, she opens a ruled notebook and writes down the day's collections — how much came in through UPI, how much in cash. After two weeks of this she has 14 rows of numbers and a nagging set of questions. Is business actually growing, or does it just feel that way? Which days should she stock extra paper and snacks for? And when she visits her bank next month to ask for a loan to buy a second photocopier, what can she show as proof that the shop earns steadily, rather than just telling the loan officer to trust her notebook?

Answering these from a handwritten notebook means picking up a calculator and adding numbers one at a time, hoping not to make a slip. A spreadsheet is better, but it gets clumsy once a shop starts logging hundreds of individual transactions a month instead of just daily totals, and clumsier still once Priya wants to compare this month against last month, or one branch against another. This is exactly the gap a specific stack of Python tools was built to close: fast number-crunching, tables that behave like a smart spreadsheet, and charts that turn a fortnight of digits into a picture a bank manager — or Priya herself — can read in five seconds.

Three Tools, One Job

The three libraries this chapter covers are not competitors; they sit on top of one another, each solving the part of the problem the one below it leaves unsolved.

  • NumPy (short for Numerical Python) supplies the fast, memory-efficient array that everything else is quietly built on.
  • Pandas wraps row labels and column names around those arrays, turning "a block of numbers" into "a table you can query like a spreadsheet."
  • Matplotlib takes a NumPy array or a Pandas column and draws it as a chart.

Each has an origin worth knowing, because it explains why the code looks the way it does. NumPy was created by Travis Oliphant and released in 2006, merging two earlier, competing array libraries into one standard the scientific Python community could share. Pandas was written by Wes McKinney starting in 2008, while he worked at a financial firm that needed to analyze time-stamped financial data quickly; its name comes from "panel data," an econometrics term for exactly the kind of row-and-column, date-stamped dataset that Priya's sales log is a tiny example of. Matplotlib was built by John D. Hunter and first released in 2003, to give Python the kind of plotting commands scientists already knew from MATLAB — which is where the "Mat" in the name comes from.

By convention, not by any rule of the language, Python programmers import all three the same way, and it is worth reading and writing these three lines until they are automatic:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

The aliases np, pd, and plt are so universal that using anything else in shared code would confuse other programmers, even though nothing in the language stops you from writing import numpy as banana.

NumPy: Numbers at Scale

Suppose Priya's first week of UPI collections looks like this, Monday through Sunday: 1200, 950, 1100, 1400, 1650, 2200, 1800 rupees. Stored as an ordinary Python list, adding a 2% payment-gateway fee to every entry means writing a loop:

sales_list = [1200, 950, 1100, 1400, 1650, 2200, 1800]
after_fee = []
for amount in sales_list:
    after_fee.append(amount * 1.02)
print(after_fee)
# [1224.0, 969.0, 1122.0, 1428.0, 1683.0, 2244.0, 1836.0]

This works, but it does more than the task really needs. A Python list is a collection of pointers to separate objects scattered around memory, so the loop has to fetch each number, check its type, multiply, and store the result — one slow, individually interpreted step at a time. That overhead is invisible on 7 numbers and very visible on 7 million.

A NumPy array (technically an ndarray, for n-dimensional array) fixes this by storing same-type numbers in one unbroken block of memory and running the multiplication as a single compiled operation across the whole block — what is called vectorization. The same task becomes:

import numpy as np

sales = np.array([1200, 950, 1100, 1400, 1650, 2200, 1800])
after_fee = sales * 1.02
print(after_fee)
# [1224.  969. 1122. 1428. 1683. 2244. 1836.]

No loop, no .append() — the multiplication happens once, across the whole array. This is called broadcasting: NumPy takes the single number 1.02 and stretches it to match every element of sales automatically. On seven numbers the speed difference is invisible, but as arrays grow into the thousands or millions of elements — a full year of transaction-level records for a mid-sized business, say — vectorized NumPy code routinely runs one to two orders of magnitude faster than the equivalent hand-written Python loop, simply because the heavy lifting happens in compiled code instead of the Python interpreter.

Arrays also carry useful self-description. sales.shape returns (7,) — one dimension, 7 elements. sales.dtype returns int64, meaning every element is stored as the same 64-bit integer type, which is precisely what makes the block-of-memory trick possible. Arrays can also be built without typing out every value: np.zeros(5) gives five zeros, np.arange(0, 14, 1) gives the integers 0 through 13 (handy for numbering Priya's 14 days), and np.linspace(0, 1, 5) gives five evenly spaced points between 0 and 1.

Arrays also support slicing and filtering the way lists do, but with more power. sales[2:5] returns the Wednesday, Thursday, and Friday collections as a new array, [1100 1400 1650], using the same start-inclusive, stop-exclusive rule as list slicing. sales[-1] returns the last element, Sunday's ₹1800, by counting from the end. More useful for Priya is Boolean indexing: writing sales > 1500 compares every element to 1500 in one shot and produces an array of True/False values, [False False False False True True True]; feeding that straight back into the brackets, sales[sales > 1500], keeps only the matching elements and returns [1650 2200 1800]. Filtering by condition without writing a loop or an if statement is the single habit that carries most directly into Pandas.

Working Through the Numbers by Hand

NumPy's real value for a shop owner like Priya shows up in its statistical functions — np.mean(), np.std(), np.min(), np.max() — but those are worth trusting only after checking one of them by hand, once.

Take Priya's first week again: 1200, 950, 1100, 1400, 1650, 2200, 1800 rupees, Monday through Sunday.

Step 1. Sum the values: 1200 + 950 + 1100 + 1400 + 1650 + 2200 + 1800 = 10,300.

Step 2. Divide by the number of days to get the mean: 10,300 ÷ 7 ≈ ₹1,471.43.

Step 3. For each day, subtract the mean, then square the result. Squaring cancels the negative signs and penalizes big swings more than small ones:

Day         Value    Deviation   Deviation squared
Monday       1200     -271.43         73,673.47
Tuesday       950     -521.43        271,887.76
Wednesday    1100     -371.43        137,959.18
Thursday     1400      -71.43          5,102.04
Friday       1650     +178.57         31,887.76
Saturday     2200     +728.57        530,816.33
Sunday       1800     +328.57        107,959.18

Step 4. Average the squared deviations to get the variance: the seven values above sum to 1,159,285.72; divided by 7, that is ≈165,612.25.

Step 5. Take the square root, to bring the units back from "rupees squared" to rupees: √165,612.25 ≈ ₹406.95. That is the standard deviation — roughly how far a typical day strays from the week's average.

Now check the hand calculation against NumPy:

week1 = np.array([1200, 950, 1100, 1400, 1650, 2200, 1800])
print(np.mean(week1))   # 1471.4285714285713
print(np.std(week1))    # 406.9548438069747

The numbers match, which is the entire point of doing it by hand once. There is one sharp edge worth flagging before it causes a bug: np.std() divides by n (7, here), treating the week as a complete population. Pandas' equivalent, calling .std() on a Series, divides by n − 1 by default — the standard statistical adjustment for treating your data as a sample drawn from a larger pattern rather than the whole of it. On this same week that difference moves the answer from ₹406.95 to ₹439.56. Neither is "wrong"; they answer subtly different questions, and mixing them up in a report is a classic, avoidable data-science bug.

Pandas: Giving Data a Shape

A NumPy array is excellent at holding one column of same-type numbers, but Priya's real notebook has several columns — the day of the week, which week it was, the UPI amount, the cash amount — and a spreadsheet-like structure to hold them together is exactly what a plain array does not provide. That structure is the Pandas DataFrame: a table where each column is internally a NumPy array, but the whole thing carries row labels and column names the way a spreadsheet does. A single column pulled out of a DataFrame is called a Series — a labeled, one-dimensional array. A DataFrame is best thought of as a dictionary of same-length Series glued together as columns.

Building Priya's two-week log looks like this:

import pandas as pd

data = {
    "Day":  ["Mon","Tue","Wed","Thu","Fri","Sat","Sun",
             "Mon","Tue","Wed","Thu","Fri","Sat","Sun"],
    "Week": [1,1,1,1,1,1,1, 2,2,2,2,2,2,2],
    "UPI":  [1200,950,1100,1400,1650,2200,1800,
             1300,1000,1250,1500,1700,2400,1950],
    "Cash": [300,250,200,180,220,500,450,
             280,260,210,190,240,520,470]
}

sales = pd.DataFrame(data)
sales["Total"] = sales["UPI"] + sales["Cash"]
print(sales.head())
   Day  Week   UPI  Cash  Total
0  Mon     1  1200   300   1500
1  Tue     1   950   250   1200
2  Wed     1  1100   200   1300
3  Thu     1  1400   180   1580
4  Fri     1  1650   220   1870

The line sales["Total"] = sales["UPI"] + sales["Cash"] is doing the same vectorized addition NumPy does under the hood; Pandas just lets you refer to whole columns by name instead of remembering which array holds what. head() shows the first five rows by default, a quick sanity check before working on all fourteen. In real use, this table would rarely be typed out by hand — Priya's UPI app can export a month of transactions as a .csv file, and pd.read_csv("sales.csv") would build the same kind of DataFrame directly from that file.

Individual rows and row ranges follow the same slicing logic as NumPy. sales.loc[5] returns row 5 as its own Series — the first Saturday's full record: Day "Sat", Week 1, UPI 2200, Cash 500, Total 2700 — while sales.iloc[0:3] returns the first three rows by position, the identical start-inclusive, stop-exclusive rule arrays use. That family resemblance is not an accident: strip away the row labels and column names, and a DataFrame is, conceptually, a 2D table built from one NumPy array per column. sales[["UPI", "Cash"]].to_numpy() returns exactly that — a plain array of shape (14, 2), fourteen rows by two columns.

Real logs are rarely this tidy, and Pandas is built with that expectation. Suppose Priya forgot to note the cash amount on one especially busy Saturday — that cell would show up as NaN ("Not a Number"), Pandas' marker for a missing value, and an ordinary .sum() or .mean() over that column would silently skip it rather than crashing or quietly treating it as zero. sales.isna().sum() reports exactly which columns have a gap and how many; sales.dropna() removes the incomplete row entirely; sales.fillna(0) replaces the gap with a stand-in value instead. Choosing between ignoring, removing, and filling is a judgment call about the data, not a syntax problem, and it is one of the first real decisions any data scientist has to make before trusting a single number computed from a messy, real-world log.

Asking Questions of the Table

With the data in a DataFrame, Priya's original questions become one-line queries. Is business growing between week 1 and week 2? Group the rows by week and average the Total column:

print(sales.groupby("Week")["Total"].mean())
Week
1    1771.428571
2    1895.714286
Name: Total, dtype: float64

Week 2 averages about ₹124 more per day than week 1 — a real, if modest, upward trend, not just a feeling.

Which days should she stock extra paper and snacks for? Filter the table with a condition, the same Boolean-indexing idea NumPy uses, now applied to a whole row at a time:

print(sales[sales["Total"] > 2000])
    Day  Week   UPI  Cash  Total
5   Sat     1  2200   500   2700
6   Sun     1  1800   450   2250
12  Sat     2  2400   520   2920
13  Sun     2  1950   470   2420

Every single row above ₹2,000 is a Saturday or a Sunday — in fact, it is all four weekend days in the log, and no weekday clears that mark even once. sales.sort_values("Total", ascending=False).head(3) confirms the same pattern from the other direction: the top three days by revenue are the two Saturdays and one of the Sundays. That is a genuine, actionable finding — Priya's weekend footfall, likely students catching up on printing before Monday deadlines, is what is really pulling her average up, and it tells her exactly when to keep extra stock on the shelf.

One method bundles several such questions into a single call: sales[["UPI","Cash","Total"]].describe() returns the count, mean, standard deviation, minimum, maximum, and the 25th/50th/75th percentiles for every numeric column at once — a fast first look worth running on any new dataset before writing a single targeted query.

One more question a bank manager would ask: how dependable is UPI as a payment channel for this business, compared with cash?

total_revenue = sales["Total"].sum()
upi_share = sales["UPI"].sum() / total_revenue * 100
print(round(upi_share, 1))
# 83.4

Over the two weeks, 83.4% of Priya's ₹25,670 in total sales arrived through UPI — a computed fact, not a guess, and one far more convincing on a loan application than a notebook full of daily entries.

Matplotlib: Seeing the Pattern

Numbers convince a spreadsheet; a picture convinces a person in under five seconds, because human vision is built to spot a pattern in a shape far faster than in a column of digits. Matplotlib's core interface, pyplot — conventionally imported as plt — turns a column of numbers into a chart with a handful of function calls:

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 5))
plt.plot(sales.index, sales["Total"], marker="o", color="#2E86AB", label="Daily total")
plt.axhline(sales["Total"].mean(), color="gray", linestyle="--", label="14-day average")
plt.title("Priya's Shop: Daily Sales Over Two Weeks")
plt.xlabel("Day number (0 = first Monday)")
plt.ylabel("Sales (Rs.)")
plt.legend()
plt.show()

Running this draws a line in a saw-tooth pattern: it climbs through the week, peaks on each Saturday (day 5 and day 12), stays high into Sunday, and drops sharply every Monday, with a dashed gray line marking the two-week average for reference. Anyone glancing at it, expert or not, immediately sees the weekend pattern that took several lines of Pandas code to prove numerically.

A third view often matters more than the raw 14-day trend: were the good days in week 2 better than the equivalent days in week 1, weekday for weekday? Slicing the Total column into two 7-day halves and plotting them on the same axes answers that directly:

week1_total = sales["Total"].iloc[0:7].values
week2_total = sales["Total"].iloc[7:14].values
days = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]

plt.plot(days, week1_total, marker="o", label="Week 1")
plt.plot(days, week2_total, marker="o", label="Week 2")
plt.title("Same Weekday, Two Weeks")
plt.ylabel("Sales (Rs.)")
plt.legend()
plt.show()

The week 2 line sits above the week 1 line on all seven days, by anywhere from ₹60 to ₹220 depending on the day. The improvement is not one lucky Saturday skewing the whole fortnight — it shows up consistently across every weekday and weekend day alike.

A fourth, simpler chart makes the UPI-versus-cash comparison just as immediate:

plt.figure(figsize=(5, 5))
plt.bar(["UPI", "Cash"], [sales["UPI"].sum(), sales["Cash"].sum()],
        color=["#2E86AB", "#F24236"])
plt.title("Two-Week Revenue by Payment Mode")
plt.ylabel("Amount (Rs.)")
plt.show()

The UPI bar towers over the cash bar at roughly five times its height, matching the 83.4% figure computed earlier — except now it needs no explanation at all. Calling plt.savefig("weekend_pattern.png") just before plt.show() would save any of these charts as an image file Priya could attach to a loan application or share over WhatsApp.

Back to Priya's Shop

None of the three libraries did anything a sufficiently patient person with a calculator could not eventually do by hand — the five-step standard-deviation walkthrough proves that directly. What changes is the cost of asking a second question. Once sales exists as a DataFrame, finding out whether business is growing, which days deserve extra stock, how reliable UPI is as a revenue channel, and whether last week's gains were a fluke or a pattern took a handful of short queries and three charts, not four separate evenings with a notebook and a calculator. Priya walks into the bank with an answer to every question she started with: sales up roughly ₹124 a day between the two weeks, gains showing up on all seven days of the week rather than one lucky Saturday, weekends clearly worth extra stock, and 83.4% of revenue arriving through a fully traceable digital channel. That is the actual promise of the NumPy-Pandas-Matplotlib stack — not new arithmetic no one could do before, but arithmetic made cheap enough to repeat five times before breakfast, whether the dataset is one small shop's fortnight or the millions of UPI transactions India's banking system settles every single day.

Think About It

Think about this: How would you explain python for data science: numpy, pandas, matplotlib 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 python for data science: numpy, pandas, matplotlib 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 python for data science: numpy, pandas, matplotlib to at least 3 other topics you have studied.

Key Takeaways — Summary and Recap

Let us recap what we covered: the core ideas behind python for data science: numpy, pandas, matplotlib, 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.

← Convolutional Neural Networks: How Computers SeeRecursion and Dynamic Programming →

Found this useful? Share it!

📱 WhatsApp 🐦 Twitter 💼 LinkedIn