Class 12 Informatics Practices Chapter 01 Β· 34 min read

πŸ“˜ Data Handling Using Pandas – I

Unit 1 Β· Ch 1 Jul 10, 2026
Chapter Quiz

This chapter introduces Pandas, the Python library used to store and work with tabular data such as a school register, a shop's inventory or a list of student marks. It covers the two main Pandas data structures β€” the Series and the DataFrame β€” and how to create them, access and change their data, and add, delete and rename rows and columns.

πŸ’‘ How to use these notes

Read slowly, run every code example in Python, and read the 🎯 Board Exam Tips with each section. Pay particular attention to Series creation, DataFrame creation, loc/iloc and add/delete operations during revision.


1.1 🌟 Introduction β€” What is Pandas?

Imagine you have 500 students' marks in a school. You need to:

  • Find who scored above 90
  • Calculate the class average
  • Sort by marks

Doing this manually takes hours. Writing raw Python code takes many lines. Pandas does it in ONE line!

graph LR
    PROB["😩 Problem\nManaging big data\nin Python is painful"]
    PANDAS["🐼 Pandas\nPowerful data tool\nbuilt on NumPy"]
    SOL["😊 Solution\nAnalyse, filter, sort\nin seconds!"]

    PROB --> PANDAS --> SOL

    style PANDAS fill:#FF9800,color:#fff
    style SOL fill:#4CAF50,color:#fff
🎯

What Pandas Does

Handles tables of data like Excel

But MUCH faster and works inside Python code!
πŸ—οΈ

Built On

NumPy (the math engine)

Pandas = NumPy + labels + convenience
πŸ“Š

Who Uses It

Data Scientists, Companies, Researchers

GoogleAmazonISRO use Pandas daily!
⚑

Why Fast

Vectorization β€” processes whole column at once

No slow loops needed

Best Analogy: Think of Python lists as a hand-written notebook and Pandas as an Excel spreadsheet. Both store data, but Excel has built-in tools for filtering, sorting, and calculations. That's exactly what Pandas adds to Python!


1.2 πŸ”Œ Using Pandas

Before you can use Pandas, you need to import it. We give it a short nickname pd so we don't type "pandas" every time.

# import_pandas.py
import pandas as pd         # Standard practice β€” always use alias 'pd'
import numpy as np          # Often imported together with pandas

print("Pandas version:", pd.__version__)
🧠 Why alias 'pd'? 🧠

This is a universal convention β€” every Pandas programmer in the world writes import pandas as pd. If you write import pandas, your code still works but you'd type pandas.Series() instead of pd.Series(). Short = better!

πŸ“‹ Board Exam Tip

"How do you import the Pandas library?" β€” 1-mark question. Answer: import pandas as pd If they ask for numpy too: import numpy as np


1.3 πŸ—οΈ Pandas Data Structures

Pandas gives us two main data structures to store and manage data:

graph TD
    PANDAS["🐼 PANDAS\nData Structures"]
    S["πŸ“Œ Series\n1-Dimensional\nLike one column"]
    D["πŸ“Š DataFrame\n2-Dimensional\nLike a full table"]

    PANDAS --> S
    PANDAS --> D

    S --> EX1["Marks of ONE student\nacross subjects:\nMath: 85, Sci: 90, Eng: 78"]
    D --> EX2["Marks of ALL students\nacross ALL subjects\n(full spreadsheet!)"]

    style S fill:#2196F3,color:#fff
    style D fill:#9C27B0,color:#fff
πŸ“Œ

Series

1D β€” like a single column in Excel

Roll numbersmarks of one studentprices of items
πŸ“Š

DataFrame

2D β€” like a complete Excel sheet

Full class resultproduct catalogueattendance register

1.4 πŸ“Œ Series β€” The Smart Column

A Series is a one-dimensional labeled array. It's like a Python list, but every element has a label (called index) attached to it.

Without Pandas (List):        With Pandas (Series):
[85, 90, 78]                  0    85
                              1    90
                              2    78
                              dtype: int64

The left column (0, 1, 2) = Index (label) The right column (85, 90, 78) = Values (data)


1.4.1 Creating Series Objects πŸ› οΈ

Method 1: From a List (most basic)

# series_from_list.py
import pandas as pd

marks = [85, 90, 78, 92, 65]
s = pd.Series(marks)
print(s)

Output:

0    85
1    90
2    78
3    92
4    65
dtype: int64

Pandas automatically assigns index 0, 1, 2, 3, 4 when you don't specify one.


Method 2: From a List WITH Custom Index

# series_custom_index.py
import pandas as pd

marks = [85, 90, 78]
students = ['Amit', 'Neha', 'Raj']

s = pd.Series(marks, index=students)
print(s)

Output:

Amit    85
Neha    90
Raj     78
dtype: int64

Now instead of 0, 1, 2 β€” we have names as labels! Much more readable!


Method 3: From a Dictionary (Keys β†’ Index, Values β†’ Data)

# series_from_dict.py
import pandas as pd

data = {'Math': 95, 'Science': 88, 'English': 72, 'Hindi': 80}
s = pd.Series(data)
print(s)

Output:

Math       95
Science    88
English    72
Hindi      80
dtype: int64

Dictionary keys automatically become the Index! This is the most natural way.


Method 4: From a Scalar (Same Value Everywhere)

# series_scalar.py
import pandas as pd

s = pd.Series(100, index=['A', 'B', 'C', 'D'])
print(s)

Output:

A    100
B    100
C    100
D    100
dtype: int64

Fills all positions with the same value β€” useful for creating blank/default data!


1.4.2 Creating Series Objects β€” Additional Functionality πŸ”§

Using dtype to specify data type:

# series_dtype.py
import pandas as pd

s = pd.Series([1, 2, 3], dtype=float)
print(s)

Output:

0    1.0
1    2.0
2    3.0
dtype: float64

Using name to give the Series a title:

# series_name.py
import pandas as pd

s = pd.Series([85, 90, 78], index=['Amit', 'Neha', 'Raj'], name='Marks')
print(s)
print("Series name:", s.name)

Output:

Amit    85
Neha    90
Raj     78
Name: Marks, dtype: int64
Series name: Marks

Using NumPy array as input:

# series_numpy.py
import pandas as pd
import numpy as np

arr = np.array([10, 20, 30, 40])
s = pd.Series(arr)
print(s)
πŸ“‹ Board Exam Tip

"Write code to create a Series from a dictionary with subject names as index." β€” 2-mark question. Answer:

import pandas as pd
d = {'Math': 85, 'Science': 90, 'English': 78}
s = pd.Series(d)
print(s)

1.4.3 Series Object Attributes πŸ”

Attributes are properties that tell you about the Series β€” like its size, type, values, etc.

Let's create a Series to demonstrate:

import pandas as pd
s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
Attribute What It Returns Example Output
s.values All data as a NumPy array [10 20 30 40]
s.index All index labels Index(['a','b','c','d'])
s.dtype Data type of values int64
s.size Total number of elements 4
s.shape Dimensions as tuple (4,)
s.nbytes Memory used in bytes 32
s.empty True if Series is empty False
s.name Name of the Series None (if not set)
s.ndim Number of dimensions 1
# series_attributes.py
import pandas as pd

s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])

print("Values:", s.values)
print("Index:", s.index)
print("Data type:", s.dtype)
print("Size:", s.size)
print("Shape:", s.shape)
print("Is empty?", s.empty)

Output:

Values: [10 20 30 40]
Index: Index(['a', 'b', 'c', 'd'], dtype='object')
Data type: int64
Size: 4
Shape: (4,)
Is empty? False
πŸ“‹ Board Exam Tip

"What is the difference between s.size and s.shape?" β€” 1-mark question. s.size β†’ returns a number (total elements e.g. 4) s.shape β†’ returns a tuple showing dimensions e.g. (4,)


1.5 πŸ”Ž Accessing a Series Object and its Elements

1.5.1 Accessing Individual Elements

Elements in a Series can be accessed using the index label (name) or position number.

# access_series.py
import pandas as pd

s = pd.Series([85, 90, 78, 92], index=['Amit', 'Neha', 'Raj', 'Priya'])

Using label (index name):

print(s['Neha'])        # Output: 90
print(s['Raj'])         # Output: 78

Using position number:

print(s[0])             # Output: 85 (first element)
print(s[2])             # Output: 78 (third element)

Accessing multiple elements (fancy indexing):

print(s[['Amit', 'Priya']])   # Pass a list of labels

Output:

Amit     85
Priya    92
dtype: int64

1.5.2 Extracting Slices from Series Object 🍰

Slicing means getting a portion (chunk) of the Series.

# slice_series.py
import pandas as pd

s = pd.Series([10, 20, 30, 40, 50], index=['a', 'b', 'c', 'd', 'e'])

Slicing by position (like Python lists):

print(s[1:4])    # Positions 1, 2, 3 (4 is EXCLUDED)

Output:

b    20
c    30
d    40
dtype: int64

Slicing by label:

print(s['b':'d'])   # Labels b, c, d (d is INCLUDED!)

Output:

b    20
c    30
d    40
dtype: int64
⚠ Common Mistake β€” The Big Slice Trap!

s[1:4] using position β†’ index 4 is EXCLUDED (like Python lists) s['b':'d'] using label β†’ 'd' is INCLUDED (label slicing is inclusive!) Watch for this trick in output-based questions.


1.6 πŸ› οΈ Operations on Series Object

1.6.1 Modifying Elements of Series Object ✏️

You can change values in a Series by assigning to the index:

# modify_series.py
import pandas as pd

s = pd.Series([85, 90, 78], index=['Amit', 'Neha', 'Raj'])
print("Before:", s['Neha'])

s['Neha'] = 95           # Modify using label
print("After:", s['Neha'])

s[2] = 82               # Modify using position
print("Raj's new marks:", s['Raj'])

Output:

Before: 90
After: 95
Raj's new marks: 82

Modifying multiple values:

s[['Amit', 'Raj']] = [88, 85]   # Change multiple at once
print(s)

1.6.2 Renaming Indexes 🏷️

You can rename the index labels of a Series using .rename() or by directly assigning a new index:

Method 1: Assign new index directly

# rename_index.py
import pandas as pd

s = pd.Series([85, 90, 78], index=['A', 'B', 'C'])
s.index = ['Amit', 'Neha', 'Raj']    # Replace all index labels
print(s)

Output:

Amit    85
Neha    90
Raj     78
dtype: int64

Method 2: Using rename() β€” selective renaming

s = s.rename({'Amit': 'AMIT', 'Neha': 'NEHA'})   # Rename specific labels
print(s)

Output:

AMIT    85
NEHA    90
Raj     78
dtype: int64
🧠 rename() does NOT change the original! 🧠

s.rename(...) returns a NEW Series. The original s is unchanged unless you write s = s.rename(...). This is true for most Pandas operations!


1.6.3 The head() and tail() Functions πŸ“‹

When a Series has many elements, you don't want to print ALL of them. head() and tail() let you peek at the first/last few:

# head_tail.py
import pandas as pd

s = pd.Series([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])

print("First 3 elements:")
print(s.head(3))

print("\nLast 3 elements:")
print(s.tail(3))

print("\nDefault head (5):")
print(s.head())          # Default shows 5

Output:

First 3 elements:
0    10
1    20
2    30
dtype: int64

Last 3 elements:
7    80
8    90
9    100
dtype: int64

Default head (5):
0    10
1    20
2    30
3    40
4    50
dtype: int64
πŸ“‹ Board Exam Tip

"What does s.head() return by default?" β€” 1-mark question. Answer: By default (with no argument), head() returns the first 5 elements. tail() returns the last 5 elements.


1.6.4 Vector Operations on Series Objects ⚑

Vectorization means performing an operation on every element at once β€” no loop needed!

# vector_operations.py
import pandas as pd

s = pd.Series([10, 20, 30, 40, 50])

print("Original:", s.values)
print("Add 5:", (s + 5).values)
print("Multiply by 2:", (s * 2).values)
print("Square root:", (s ** 0.5).values)
print("Divide by 10:", (s / 10).values)

Output:

Original: [10 20 30 40 50]
Add 5: [15 25 35 45 55]
Multiply by 2: [20 40 60 80 100]
Square root: [3.16 4.47 5.48 6.32 7.07]
Divide by 10: [1. 2. 3. 4. 5.]

Every operation applies to the entire Series automatically β€” no for loop needed! This is the biggest advantage of Pandas over plain Python lists.


1.6.5 Arithmetic on Series Objects βž•

When you do arithmetic between two Series, Pandas aligns them by their index labels before calculating:

# arithmetic_series.py
import pandas as pd

marks_test1 = pd.Series({'Math': 45, 'Science': 40, 'English': 35})
marks_test2 = pd.Series({'Math': 50, 'Science': 45, 'English': 40})

total = marks_test1 + marks_test2
print("Total Marks:")
print(total)

percentage = (total / 2)
print("\nAverage:")
print(percentage)

Output:

Total Marks:
Math       95
Science    85
English    75
dtype: int64

Average:
Math       47.5
Science    42.5
English    37.5
dtype: float64

What happens when indexes don't match?

# mismatched_arithmetic.py
import pandas as pd

s1 = pd.Series({'a': 10, 'b': 20, 'c': 30})
s2 = pd.Series({'b': 5, 'c': 15, 'd': 25})

print(s1 + s2)

Output:

a     NaN
b    25.0
c    45.0
d     NaN
dtype: float64

When an index exists in one Series but NOT the other, the result is NaN (Not a Number) β€” representing a missing/unknown value!

πŸ“‹ Board Exam Tip

"What is NaN in Pandas?" β€” 1-mark question. Answer: NaN (Not a Number) is Pandas' way of representing a missing or undefined value. It appears when arithmetic is performed between Series with non-matching index labels, or when data is missing in a dataset.


1.6.6 Filtering Entries in Series Objects πŸ”

Filtering means picking only the elements that match a condition:

# filter_series.py
import pandas as pd

marks = pd.Series([85, 45, 92, 38, 75, 60],
                  index=['Amit', 'Neha', 'Raj', 'Priya', 'Sita', 'Karan'])

# Who scored more than 70?
print("Students who passed with distinction (>70):")
print(marks[marks > 70])

print("\nStudents who failed (<50):")
print(marks[marks < 50])

print("\nStudents who scored between 60 and 90:")
print(marks[(marks >= 60) & (marks <= 90)])

Output:

Students who passed with distinction (>70):
Amit    85
Raj     92
Sita    75
dtype: int64

Students who failed (<50):
Neha     45
Priya    38
dtype: int64

Students who scored between 60 and 90:
Amit     85
Sita     75
Karan    60
dtype: int64
>

Greater than

marks[marks > 70]

Elements above 70
<

Less than

marks[marks < 50]

Elements below 50
&

AND condition

(marks > 60) & (marks < 90)

Between 60 and 90

OR condition

(marks < 40)

1.6.7 Sorting Series Values πŸ“Ά

Two ways to sort a Series:

# sort_series.py
import pandas as pd

s = pd.Series([30, 10, 50, 20, 40], index=['c', 'a', 'e', 'b', 'd'])

print("Sort by VALUES (ascending):")
print(s.sort_values())

print("\nSort by VALUES (descending):")
print(s.sort_values(ascending=False))

print("\nSort by INDEX (label):")
print(s.sort_index())

Output:

Sort by VALUES (ascending):
a    10
b    20
c    30
d    40
e    50
dtype: int64

Sort by VALUES (descending):
e    50
d    40
c    30
b    20
a    10
dtype: int64

Sort by INDEX (label):
a    10
b    20
c    30
d    40
e    50
dtype: int64
Method What it sorts by Default
sort_values() The data values ascending=True
sort_index() The index labels ascending=True
πŸ“‹ Board Exam Tip

"Write code to sort a Series of prices in descending order." β€” 2-mark question. Answer: s.sort_values(ascending=False)


1.7 πŸ“Š Series vs. 1D Data Structures

1.7.1 Series Objects vs. Lists

Feature Python List Pandas Series
Index Only 0, 1, 2... (numeric) Custom labels (names, dates, etc.)
Data Type Mixed types allowed Uniform type (faster!)
Math Operations Need loops Vectorized β€” one line!
Missing Data No concept NaN support built-in
Size Can grow/shrink Fixed size after creation
Example [85, 90, 78] pd.Series([85, 90, 78], index=['A','B','C'])
# list_vs_series.py
import pandas as pd

# List: need loop to add 10 to all
my_list = [10, 20, 30]
result_list = [x + 10 for x in my_list]    # Needs loop

# Series: no loop needed!
my_series = pd.Series([10, 20, 30])
result_series = my_series + 10              # No loop!

print("List result:", result_list)
print("Series result:", result_series.values)

1.7.2 Series Objects vs. Dictionaries

Feature Python Dictionary Pandas Series
Index Keys (any hashable type) Index labels (same concept!)
Order Maintained (Python 3.7+) Always maintains order
Math Operations Not supported Vectorized math built-in
Slicing Limited (no range slicing) Full slicing support
Alignment No βœ… Auto-aligns by index during arithmetic
Convert to Series pd.Series(dict) Already a Series
# dict_vs_series.py
import pandas as pd

# Dictionary
d = {'Math': 85, 'Science': 90}
# d + 5  ← This would cause ERROR!

# Series (from dictionary)
s = pd.Series(d)
print(s + 5)    # βœ… Works perfectly!

Output:

Math       90
Science    95
dtype: int64

1.7.3 Difference between NumPy Arrays and Series Objects

Feature NumPy Array (1D) Pandas Series
Index Only 0, 1, 2... (numeric) Custom index labels
Data Type Must be uniform Must be uniform
NaN Handling Limited Full NaN support
Mathematical Ops βœ… Fast βœ… Fast (uses NumPy inside)
Label-based Access ❌ Not available βœ… s['label'] works
Index Alignment ❌ No βœ… Auto-aligns by label
# numpy_vs_series.py
import pandas as pd
import numpy as np

arr = np.array([10, 20, 30])
s = pd.Series([10, 20, 30], index=['a', 'b', 'c'])

# NumPy array: only position access
print("NumPy arr[0]:", arr[0])     # Output: 10

# Series: both position AND label access
print("Series s['b']:", s['b'])    # Output: 20
print("Series s[1]:", s[1])        # Output: 20
πŸ“‹ Board Exam Tip

"Differentiate between a Pandas Series and a NumPy 1D Array." β€” 2-mark question asked often! Key differences: Series has custom labels (NumPy only has numeric positions). Series supports index alignment in arithmetic. Series has better NaN handling.


1.8 πŸ“Š DataFrame Data Structure

A DataFrame is a 2-dimensional table with:

  • Rows β€” each row is one record
  • Columns β€” each column is one attribute
  • Row Index β€” labels for rows
  • Column Labels β€” headers for columns
     Name    Math  Science  English
0    Amit      85       88       75
1    Neha      90       92       88
2    Raj       78       80       72
3    Priya     92       95       89

↑               ↑
Row Index    Column Labels

Think of a DataFrame as a collection of Series β€” each column is a Series, all sharing the same row index!


1.9 πŸ“‹ Creating and Displaying a DataFrame

Method 1: Dictionary of Lists (Most Common! ⭐)

Keys = Column names, Values = Column data as lists

# df_from_dict.py
import pandas as pd

data = {
    'Name':    ['Amit', 'Neha', 'Raj', 'Priya'],
    'Math':    [85, 90, 78, 92],
    'Science': [88, 92, 80, 95],
    'English': [75, 88, 72, 89]
}

df = pd.DataFrame(data)
print(df)

Output:

    Name  Math  Science  English
0   Amit    85       88       75
1   Neha    90       92       88
2    Raj    78       80       72
3  Priya    92       95       89

With custom row index:

df = pd.DataFrame(data, index=['S1', 'S2', 'S3', 'S4'])
print(df)

Output:

     Name  Math  Science  English
S1   Amit    85       88       75
S2   Neha    90       92       88
S3    Raj    78       80       72
S4  Priya    92       95       89

Method 2: List of Dictionaries

Each dictionary = one row. Keys = column names.

# df_from_list_of_dicts.py
import pandas as pd

data = [
    {'Name': 'Amit',  'Marks': 85, 'Grade': 'A'},
    {'Name': 'Neha',  'Marks': 90, 'Grade': 'A+'},
    {'Name': 'Raj',   'Marks': 78, 'Grade': 'B+'},
]

df = pd.DataFrame(data)
print(df)

Output:

   Name  Marks Grade
0  Amit     85     A
1  Neha     90    A+
2   Raj     78    B+

Method 3: Dictionary of Series

# df_from_series.py
import pandas as pd

marks = pd.Series([85, 90, 78], index=['Amit', 'Neha', 'Raj'])
grades = pd.Series(['A', 'A+', 'B+'], index=['Amit', 'Neha', 'Raj'])

df = pd.DataFrame({'Marks': marks, 'Grade': grades})
print(df)

Output:

      Marks Grade
Amit     85     A
Neha     90    A+
Raj      78   B+

Method 4: 2D NumPy Array

# df_from_numpy.py
import pandas as pd
import numpy as np

arr = np.array([[85, 88, 75],
                [90, 92, 88],
                [78, 80, 72]])

df = pd.DataFrame(arr,
                  columns=['Math', 'Science', 'English'],
                  index=['Amit', 'Neha', 'Raj'])
print(df)

Output:

      Math  Science  English
Amit    85       88       75
Neha    90       92       88
Raj     78       80       72
πŸ“‹ Board Exam Tip

"Write code to create a DataFrame with student name, marks in 3 subjects." β€” 3-mark question, most common! Use Method 1 (Dictionary of Lists) β€” it's the cleanest and most widely tested.


1.10 πŸ”’ DataFrame Attributes

Using this DataFrame for all examples:

import pandas as pd
data = {
    'Name':    ['Amit', 'Neha', 'Raj', 'Priya'],
    'Marks':   [85, 90, 78, 92],
    'Grade':   ['A', 'A+', 'B+', 'A+']
}
df = pd.DataFrame(data, index=['S1', 'S2', 'S3', 'S4'])
Attribute What It Returns Output
df.shape (rows, columns) as tuple (4, 3)
df.index Row labels Index(['S1','S2','S3','S4'])
df.columns Column names Index(['Name','Marks','Grade'])
df.dtypes Data type of each column (table of types)
df.values All data as 2D NumPy array array([[...]])
df.size Total cells (rows Γ— cols) 12
df.ndim Number of dimensions 2
df.empty True if DataFrame is empty False
df.T Transpose (flip rows↔cols) (flipped table)
df.head(n) First n rows (default 5) First 4 rows
df.tail(n) Last n rows (default 5) Last rows
df.info() Summary of types and nulls Technical summary
df.describe() Statistics (mean, min, max) Stats table
# df_attributes_demo.py
print("Shape:", df.shape)
print("Columns:", df.columns.tolist())
print("Index:", df.index.tolist())
print("Size:", df.size)
print("Dimensions:", df.ndim)
print("\nFirst 2 rows:")
print(df.head(2))

Output:

Shape: (4, 3)
Columns: ['Name', 'Marks', 'Grade']
Index: ['S1', 'S2', 'S3', 'S4']
Size: 12
Dimensions: 2

First 2 rows:
    Name  Marks Grade
S1  Amit     85     A
S2  Neha     90    A+

1.11 πŸ”„ DataFrame vs. Series and 2D NumPy Array

1.11.1 DataFrame vs. Series

Feature Series DataFrame
Dimensions 1D (one column) 2D (rows + columns)
Index One index (row labels) Row index + Column labels
Data One column of data Multiple columns
Access s['label'] df['column']['row']
Relationship A single column A collection of Series
When to use One variable (marks only) Multiple variables (name, marks, grade)
# series_vs_df.py
import pandas as pd

# Series β€” one column
s = pd.Series([85, 90, 78], name='Marks', index=['Amit', 'Neha', 'Raj'])

# DataFrame β€” multiple columns (collection of Series!)
df = pd.DataFrame({
    'Marks': [85, 90, 78],
    'Grade': ['A', 'A+', 'B+']
}, index=['Amit', 'Neha', 'Raj'])

print("Series:\n", s)
print("\nDataFrame:\n", df)

1.11.2 DataFrame vs. 2D NumPy Array (ndarray)

Feature 2D NumPy Array Pandas DataFrame
Row Labels Only 0, 1, 2... Custom labels
Column Labels Only 0, 1, 2... Named columns
Mixed Types ❌ All must be same βœ… Each column can differ
NaN Support Limited βœ… Full support
Label Access ❌ Position only βœ… Name + position
Pretty Printing Raw array format Table format
πŸ“‹ Board Exam Tip

"How is a DataFrame different from a 2D NumPy Array?" β€” 2-mark question. Key: DataFrame has named rows and columns (not just numbers), supports mixed data types per column, and has built-in NaN handling. NumPy arrays are faster but less flexible.


1.12 🎯 Selecting or Accessing Data

Selecting and accessing data is used throughout the rest of the chapter, so learn this section thoroughly.

Our reference DataFrame for all examples:

import pandas as pd

data = {
    'Name':    ['Amit', 'Neha', 'Raj', 'Priya', 'Sita'],
    'Marks':   [85, 90, 78, 92, 65],
    'Grade':   ['A', 'A+', 'B+', 'A+', 'B'],
    'City':    ['Delhi', 'Mumbai', 'Delhi', 'Pune', 'Delhi']
}
df = pd.DataFrame(data, index=['R1', 'R2', 'R3', 'R4', 'R5'])
print(df)
    Name  Marks Grade     City
R1  Amit     85     A    Delhi
R2  Neha     90    A+   Mumbai
R3   Raj     78   B+    Delhi
R4 Priya     92   A+     Pune
R5  Sita     65     B    Delhi

1.12.1 Selecting / Accessing a Column

# select_one_column.py
print(df['Name'])           # Returns a Series
print(type(df['Name']))     # <class 'pandas.core.series.Series'>

Output:

R1     Amit
R2     Neha
R3      Raj
R4    Priya
R5     Sita
Name: Name, dtype: object

1.12.2 Selecting / Accessing Multiple Columns

Use double brackets [[ ]] to select multiple columns β€” you're passing a list of column names:

# select_multiple_columns.py
print(df[['Name', 'Marks']])         # Double brackets!
print(type(df[['Name', 'Marks']]))   # DataFrame (not Series!)

Output:

    Name  Marks
R1  Amit     85
R2  Neha     90
R3   Raj     78
R4 Priya     92
R5  Sita     65
⚠ Single vs Double Brackets!

df['Name'] β†’ returns a Series (one column) df[['Name']] β†’ returns a DataFrame (still one column but in table form) df[['Name', 'Marks']] β†’ returns a DataFrame with two columns This is one of the top mistakes in board exams!


1.12.3 Selecting a Subset using Row/Column Names β€” loc[] 🎯

loc = Label-based access. Use actual names to select.

Syntax: df.loc[row_label, column_label]

# loc_demo.py

# Access ONE cell: row R2, column Marks
print(df.loc['R2', 'Marks'])       # Output: 90

# Access ONE full row:
print(df.loc['R3'])

# Access specific rows AND columns:
print(df.loc[['R1', 'R3'], ['Name', 'Marks']])

# Access a range of rows (INCLUSIVE on both ends!):
print(df.loc['R1':'R3'])

# Access all rows, specific columns:
print(df.loc[:, ['Name', 'City']])

Output of df.loc[['R1', 'R3'], ['Name', 'Marks']]:

   Name  Marks
R1 Amit     85
R3  Raj     78

1.12.4 Selecting Rows/Columns β€” iloc[] πŸ”’

iloc = Integer-position-based access. Use numbers (0, 1, 2...) to select.

Syntax: df.iloc[row_number, column_number]

# iloc_demo.py

# Access ONE cell: 1st row (index 1), 2nd column (index 1)
print(df.iloc[1, 1])               # Output: 90 (Neha's Marks)

# Access ONE full row:
print(df.iloc[2])                  # 3rd row (Raj)

# Access a range of rows (EXCLUSIVE end!):
print(df.iloc[0:3])                # Rows 0, 1, 2 (NOT 3!)

# Access specific rows and columns by number:
print(df.iloc[[0, 2], [0, 1]])    # Rows 0,2 and Columns 0,1

Output of df.iloc[0:3]:

    Name  Marks Grade    City
R1  Amit     85     A   Delhi
R2  Neha     90    A+  Mumbai
R3   Raj     78   B+   Delhi

loc vs iloc β€” The Critical Comparison:

Feature loc iloc
Based on Labels (names) Integer positions (numbers)
Row access df.loc['R2'] df.iloc[1]
Column access df.loc[:, 'Name'] df.iloc[:, 0]
Slice end INCLUSIVE (includes last) EXCLUSIVE (excludes last)
Remember as loc = Label iloc = Integer
graph LR
    LOC["loc\nUse LABELS\n'R1' to 'R3'\nInclusive end"]
    ILOC["iloc\nUse NUMBERS\n0 to 2\nExclusive end"]

    style LOC fill:#4CAF50,color:#fff
    style ILOC fill:#2196F3,color:#fff
πŸ“‹ Board Exam Tip

"What is the difference between loc and iloc?" β€” 2-mark question. Answer: loc uses row/column labels (names) and the end of a slice is inclusive. iloc uses integer positions (0,1,2...) and the end of a slice is exclusive (like Python list slicing).


1.12.5 Selecting / Accessing Individual Value

Two ways to access one specific cell:

# access_individual_value.py

# Method 1: Using loc (label-based)
print(df.loc['R2', 'Marks'])       # Output: 90

# Method 2: Using iloc (position-based)
print(df.iloc[1, 1])               # Output: 90

# Method 3: Using at (fastest for single value, label-based)
print(df.at['R2', 'Marks'])        # Output: 90

# Method 4: Using iat (fastest for single value, position-based)
print(df.iat[1, 1])                # Output: 90

at and iat are slightly faster than loc and iloc for accessing a SINGLE value, but loc and iloc are more versatile for ranges.


1.12.6 Selecting DataFrame Rows/Columns Based on Boolean Conditions πŸ”

Filter rows based on a condition β€” this is the most practical use case!

# boolean_filter.py
import pandas as pd

data = {
    'Name':  ['Amit', 'Neha', 'Raj', 'Priya', 'Sita'],
    'Marks': [85, 90, 78, 92, 65],
    'City':  ['Delhi', 'Mumbai', 'Delhi', 'Pune', 'Delhi']
}
df = pd.DataFrame(data, index=['R1', 'R2', 'R3', 'R4', 'R5'])

# Students with Marks > 80:
print("Marks above 80:")
print(df[df['Marks'] > 80])

# Students from Delhi:
print("\nStudents from Delhi:")
print(df[df['City'] == 'Delhi'])

# Students from Delhi with Marks > 75:
print("\nDelhi students with Marks > 75:")
print(df[(df['City'] == 'Delhi') & (df['Marks'] > 75)])

Output (Marks > 80):

    Name  Marks    City
R1  Amit     85   Delhi
R2  Neha     90  Mumbai
R4 Priya     92    Pune
πŸ“‹ Board Exam Tip

"Write code to display all students who scored more than 80 marks." β€” 2-mark question! Answer: print(df[df['Marks'] > 80])


1.13 βž• Adding/Modifying Rows/Columns in DataFrames

1.13.1 Adding/Modifying a Column

Adding a new column:

# add_column.py
import pandas as pd

df = pd.DataFrame({
    'Name': ['Amit', 'Neha', 'Raj'],
    'Marks': [85, 90, 78]
})

# Add new column with calculated values:
df['Percentage'] = df['Marks'] / 100 * 100
df['Grade'] = ['A', 'A+', 'B+']
df['Status'] = 'Pass'   # Same value for all rows

print(df)

Output:

   Name  Marks  Percentage Grade Status
0  Amit     85        85.0     A   Pass
1  Neha     90        90.0    A+   Pass
2   Raj     78        78.0   B+   Pass

Modifying an existing column:

# Increase all marks by 5 (bonus marks):
df['Marks'] = df['Marks'] + 5
print(df['Marks'])

Output:

0    90
1    95
2    83
Name: Marks, dtype: int64

1.13.2 Adding/Modifying a Row

Adding a new row using loc[]:

# add_row.py
import pandas as pd

df = pd.DataFrame({
    'Name': ['Amit', 'Neha'],
    'Marks': [85, 90]
}, index=['R1', 'R2'])

# Add a new row:
df.loc['R3'] = ['Raj', 78]
print(df)

Output:

   Name  Marks
R1 Amit     85
R2 Neha     90
R3  Raj     78

Modifying an existing row:

df.loc['R2'] = ['NEHA', 95]   # Replace entire row R2

1.13.3 Modifying a Single Cell

# modify_cell.py
import pandas as pd

df = pd.DataFrame({
    'Name': ['Amit', 'Neha', 'Raj'],
    'Marks': [85, 90, 78]
}, index=['R1', 'R2', 'R3'])

# Using loc:
df.loc['R2', 'Marks'] = 95
print("After update:", df.loc['R2', 'Marks'])   # Output: 95

# Using iloc:
df.iloc[0, 1] = 88
print("After update:", df.iloc[0, 1])            # Output: 88

# Using at:
df.at['R3', 'Marks'] = 82
print("After update:", df.at['R3', 'Marks'])     # Output: 82

1.14 ❌ Deleting/Renaming Columns/Rows

1.14.1 Deleting Rows/Columns in a DataFrame

Using the drop() method:

# delete_demo.py
import pandas as pd

df = pd.DataFrame({
    'Name': ['Amit', 'Neha', 'Raj', 'Priya'],
    'Marks': [85, 90, 78, 92],
    'Grade': ['A', 'A+', 'B+', 'A+']
}, index=['R1', 'R2', 'R3', 'R4'])

Delete a COLUMN (axis=1):

df2 = df.drop('Grade', axis=1)    # Returns new df WITHOUT Grade column
print(df2)

Output:

    Name  Marks
R1  Amit     85
R2  Neha     90
R3   Raj     78
R4 Priya     92

Delete a ROW (axis=0):

df3 = df.drop('R3', axis=0)       # Removes Raj's row
print(df3)

Output:

    Name  Marks Grade
R1  Amit     85     A
R2  Neha     90    A+
R4 Priya     92    A+

Delete multiple rows or columns:

df.drop(['R1', 'R4'], axis=0)              # Delete multiple rows
df.drop(['Grade', 'Marks'], axis=1)         # Delete multiple columns

Using inplace=True to modify the original:

df.drop('Grade', axis=1, inplace=True)     # Changes df itself, no need to reassign
⚠ drop() doesn't change the original by default!

df.drop('Grade', axis=1) returns a NEW DataFrame β€” df itself is unchanged! Use inplace=True OR reassign: df = df.drop('Grade', axis=1) to actually change df.

πŸ“‹ Board Exam Tip

"Write code to delete the column 'Grade' from a DataFrame df." β€” 2-mark question! Answer: df = df.drop('Grade', axis=1) or df.drop('Grade', axis=1, inplace=True) Remember: axis=1 for columns, axis=0 for rows!


1.14.2 Renaming Rows/Columns

Using the rename() method:

# rename_demo.py
import pandas as pd

df = pd.DataFrame({
    'Name': ['Amit', 'Neha'],
    'Marks': [85, 90]
}, index=['R1', 'R2'])

# Rename COLUMNS:
df2 = df.rename(columns={'Name': 'StudentName', 'Marks': 'Score'})
print(df2)

Output:

   StudentName  Score
R1        Amit     85
R2        Neha     90

Rename ROWS (index):

df3 = df.rename(index={'R1': 'Row1', 'R2': 'Row2'})
print(df3)

Output:

      Name  Marks
Row1  Amit     85
Row2  Neha     90

Rename both at once:

df4 = df.rename(columns={'Name': 'StudentName'},
                index={'R1': 'Row1'})

1.15 πŸ”΅ More on DataFrame Indexing β€” BOOLEAN INDEXING

Boolean indexing is about creating and using True/False arrays to filter data.

1.15.1 Creating DataFrames with Boolean Indexes

A Boolean index is a Series of True/False values used as row labels:

# boolean_index.py
import pandas as pd

data = {
    'Name':   ['Amit', 'Neha', 'Raj', 'Priya'],
    'Marks':  [85, 90, 78, 92],
}
df = pd.DataFrame(data)

# Creating a Boolean Series:
bool_index = pd.Series([True, False, True, False])

print("Boolean Series:")
print(bool_index)
print("\nDataFrame with Boolean Index:")
print(df[bool_index])

Output:

Boolean Series:
0     True
1    False
2     True
3    False
dtype: bool

DataFrame with Boolean Index:
   Name  Marks
0  Amit     85
2   Raj     78

When you pass a Boolean Series to a DataFrame, it keeps only the rows where the value is True and skips the rows where it's False!


1.15.2 Accessing Rows from DataFrames with Boolean Indexes πŸ”

The real power β€” creating boolean conditions dynamically from data:

# boolean_access.py
import pandas as pd

data = {
    'Name':    ['Amit', 'Neha', 'Raj', 'Priya', 'Sita'],
    'Marks':   [85, 90, 78, 92, 65],
    'Subject': ['Math', 'Science', 'Math', 'Science', 'Math'],
    'City':    ['Delhi', 'Mumbai', 'Delhi', 'Pune', 'Delhi']
}
df = pd.DataFrame(data)

# Step 1: Create a boolean condition (this creates True/False series)
condition = df['Marks'] > 80
print("Boolean condition:")
print(condition)
print()

# Step 2: Use it to filter the DataFrame
print("Students with Marks > 80:")
print(df[condition])

Output:

Boolean condition:
0     True
1     True
2    False
3     True
4    False
dtype: bool

Students with Marks > 80:
   Name  Marks  Subject    City
0  Amit     85     Math   Delhi
1  Neha     90  Science  Mumbai
3 Priya     92  Science    Pune

Combining Multiple Conditions:

# multiple_conditions.py

# AND condition (&): Both must be True
print("Math students scoring > 80:")
print(df[(df['Subject'] == 'Math') & (df['Marks'] > 80)])

# OR condition (|): At least one must be True
print("\nDelhi students OR students scoring > 88:")
print(df[(df['City'] == 'Delhi') | (df['Marks'] > 88)])

# NOT condition (~): Reverse True/False
print("\nStudents NOT from Delhi:")
print(df[~(df['City'] == 'Delhi')])

Output of Math AND Marks > 80:

   Name  Marks Subject   City
0  Amit     85    Math  Delhi
&

AND

Both conditions must be True

df[(df['Marks'] > 80) & (df['City'] == 'Delhi')]

OR

At least one condition True
~

NOT

Reverses True/False

df[~(df['City'] == 'Mumbai')]
πŸ“‹ Board Exam Tip

"Write a query to display students who scored more than 75 AND are from Delhi." β€” 3-mark question! Answer: df[(df['Marks'] > 75) & (df['City'] == 'Delhi')] Remember: Use & (not and) and | (not or) inside Pandas conditions!


⚠️ Common Errors and Misconceptions

Mistake What Goes Wrong Correct Code
❌ df['Name', 'Marks'] TypeError βœ… df[['Name', 'Marks']] (double brackets!)
❌ df.loc[0:2] thinking 2 is excluded Includes index label 2! βœ… Use df.iloc[0:2] if you want 2 excluded
❌ df.drop('Name') β€” column not deleted axis not specified βœ… df.drop('Name', axis=1)
❌ df.drop('R1') doesn't change original drop() returns new df βœ… df = df.drop('R1', axis=0) or inplace=True
❌ df[(df['M'] > 80) and (df['C'] == 'Delhi')] Use of Python and βœ… Use & not and
❌ s[1:3] for label slice includes 3 Position slice excludes 3 βœ… Label slice s['b':'d'] INCLUDES 'd'
❌ Forgetting import pandas as pd NameError: pd not defined βœ… Always import at the top!

πŸ”‘ Quick Revision

Series β€” One-Line Summary:

  • Create: pd.Series(list/dict/scalar, index=[...])
  • Access: s['label'] or s[position]
  • Slice: s['a':'c'] (inclusive) or s[0:3] (exclusive)
  • Sort: sort_values() / sort_index()
  • Filter: s[s > 50]

DataFrame β€” One-Line Summary:

  • Create: pd.DataFrame(dict_of_lists, index=[...])
  • Column: df['col'] β†’ Series; df[['col1','col2']] β†’ DataFrame
  • Row by label: df.loc['R1']
  • Row by number: df.iloc[0]
  • Filter: df[df['col'] > value]
  • Add column: df['NewCol'] = values
  • Delete: df.drop('col', axis=1) or df.drop('row', axis=0)
  • Rename: df.rename(columns={'old':'new'})

loc vs iloc quick rule:

  • loc = Label β†’ Inclusive slice
  • iloc = Integer β†’ Exclusive slice

🎯 Sample Board Exam Questions

Q1: Very Short Answer [1 mark each]

a) Which Pandas data structure is 2-dimensional? β†’ DataFrame

b) Write the command to import Pandas with alias pd. β†’ import pandas as pd

c) What does df.shape return for a DataFrame with 5 rows and 3 columns? β†’ (5, 3) β€” a tuple (rows, columns)

d) What does head() return by default? β†’ First 5 rows

e) Which attribute gives data type of all columns in a DataFrame? β†’ df.dtypes


Q2: Short Answer [2 marks]

Q: Differentiate between loc and iloc with example.

loc uses label names to access rows/columns and the slice end is inclusive. iloc uses integer positions (0, 1, 2...) and the slice end is exclusive.

df.loc['R1':'R3']     # Returns R1, R2, R3 (R3 INCLUDED)
df.iloc[0:3]          # Returns rows 0, 1, 2 (3 EXCLUDED)

Q3: Program Writing [3 marks]

Q: Create a DataFrame with columns Name, Age, City for 3 students. Display students from 'Delhi'.

import pandas as pd

data = {
    'Name': ['Amit', 'Neha', 'Raj'],
    'Age':  [16, 17, 16],
    'City': ['Delhi', 'Mumbai', 'Delhi']
}
df = pd.DataFrame(data)
print("Delhi students:")
print(df[df['City'] == 'Delhi'])

Q4: Program Writing [3 marks]

Q: Create a Series of 5 subjects and their marks. Display subjects with marks above 80. Sort in descending order.

import pandas as pd

marks = pd.Series(
    [95, 72, 88, 65, 91],
    index=['Math', 'English', 'Science', 'Hindi', 'IP']
)

print("Subjects above 80:")
print(marks[marks > 80])

print("\nSorted in descending order:")
print(marks.sort_values(ascending=False))

Q5: Output Based [2 marks]

Q: What is the output?

import pandas as pd
s = pd.Series([10, 20, 30, 40, 50], index=['a','b','c','d','e'])
print(s['b':'d'])
print(s[1:3])

Output:

b    20
c    30
d    40
dtype: int64
b    20
c    30
dtype: int64

(Note: Label slice 'b':'d' INCLUDES 'd'. Position slice 1:3 EXCLUDES index 3)


✏️ Practice Problems

  1. Create a Series of 6 students' marks and display only those who scored between 70 and 90.

  2. Create a DataFrame for a product catalogue with columns: ProductName, Price, Quantity, Category. Display all products under β‚Ή500.

  3. Write code to add a 'Total' column to a student DataFrame that has 'Test1' and 'Test2' columns.

  4. Create a DataFrame and delete a specific row and column. Show the output before and after deletion.

  5. Using loc, select rows R2 to R4 and columns 'Name' and 'Marks' from a DataFrame.

  6. What is the difference between sort_values() and sort_index() in a Series? Give examples.

  7. Write code to rename the column 'Marks' to 'Score' and the index label 'R1' to 'Row1'.

  8. Create a DataFrame with student data. Using boolean indexing, display students who are from 'Mumbai' OR scored above 85.

  9. Explain with code what happens when you add two Series with different index labels.

  10. Write code to access the element at the 3rd row and 2nd column of a DataFrame using both loc and iloc.

Solved Board Questions

Practice real board exam questions for this chapter.

View Solved Board Questions
🎯 CBSE BOARD EXAM 2027

Complete Preparation Resources

Prepare smarter with the right combination of CSIP12's FREE digital resources + optional printed study books.

INFORMATICS PRACTICES β€” 065

2026–27
LEARN β€” Core Theory
Sumita Arora β€” Informatics Practices with Python
Primary

2026–27 Session Edition β€’ Dhanpat Rai & Co.

PRACTISE β€” Pandas, SQL & Case Studies
Together With CBSE Class 12 Informatics Practices Question Bank
Primary

Chapterwise & Topicwise | For 2027 Exam

Additional Option
Arihant All in One Informatics Practices Class 12 View on Amazon

You don't need every book. Choose resources that complement your preparation. CSIP12 provides notes, programs, quizzes, solved questions and previous-year papers for FREE.

Learning Support

Need Help With This Chapter?

Save key topics for exam revision, ask questions to teachers, or submit content corrections.

Verified Doubts & Teacher Answers

Take the Chapter 01 Quiz