SkyAICampus
HomePracticeLearnCode LabFocus

Learn

HomePracticeConcept cardsCode LabSky Tutor

Review

Revise todayMistake notebookProgress

Focus

Campus ForestFocus roomsSquads

Questions or feedback?
support@skyaicampus.com

SkyAICampus
PrivacyTermssupport@skyaicampus.com© 2026 SkyAI Campus
← All modules

Pandas

One 60-second card per skill, in learning order. 14 of 14 cards ready.

Series and DataFrames 3/3Filtering and sorting 3/3GroupBy and aggregation 3/3Cleaning data 3/3Combining data 2/2

In this module

1Series and DataFrames3 of 3 cards2Filtering and sorting3 of 3 cards3GroupBy and aggregation3 of 3 cards4Cleaning data3 of 3 cards5Combining data2 of 2 cards

Topic 1

Series and DataFrames

Creating DataFrames · Looking at your data · Selecting columns

▶Open the lessonPractise this topic

60-second card

Creating DataFrames

A DataFrame is a table with named columns. Each column is a Series.

  • Build one from a dictionary: column name → list of values.
  • pd.read_csv('file.csv') loads a table from a file.
  • Every column has one type, like int64 or object (text).
import pandas as pd
df = pd.DataFrame({"name": ["Asha", "Ravi"], "marks": [82, 67]})
print(df.shape, list(df.columns))

Prints

(2, 2) ['name', 'marks']

Remember: Think of a DataFrame as a spreadsheet you control with code.

Common mistake: Giving columns lists of different lengths. Every column needs the same number of rows.

60-second card

Looking at your data

Look at your data before analysing it: its size, first rows and column types.

  • df.head() shows the first 5 rows; df.tail() the last 5.
  • df.info() lists columns, types and missing counts.
  • df.describe() gives count, mean, min and max for number columns.
import pandas as pd
df = pd.DataFrame({"marks": [82, 67, 91, 74]})
print(df["marks"].describe()[["mean", "max"]].tolist())

Prints

[78.5, 91.0]

Remember: head, info, describe: run these first, every time.

Common mistake: Calling df.shape() with brackets. shape is a property: df.shape.

60-second card

Selecting columns

Pick one column with df['col'] (a Series) or several with df[['a', 'b']] (a DataFrame).

  • df['marks'] gives one column.
  • df[['name', 'marks']] (double brackets) gives a smaller table.
  • df.marks works too, but fails for names with spaces.
import pandas as pd
df = pd.DataFrame({"name": ["Asha", "Ravi"], "city": ["Pune", "Delhi"], "marks": [82, 67]})
print(type(df["marks"]).__name__, df[["name", "marks"]].shape)

Prints

Series (2, 2)

Remember: One bracket: a column. Two brackets: a table.

Common mistake: Writing df['name', 'marks'] with single brackets, which gives a KeyError.

Topic 2

Filtering and sorting

Filtering rows · loc and iloc · Sorting

▶Open the lessonPractise this topic

60-second card

Filtering rows

Filter rows by putting a condition inside df[...].

  • df[df['marks'] > 80] keeps rows above 80.
  • Combine with & and |, each condition in brackets.
  • df[df['city'].isin(['Pune', 'Delhi'])] matches a list.
import pandas as pd
df = pd.DataFrame({"name": ["Asha", "Ravi", "Meena"], "city": ["Pune", "Delhi", "Pune"], "marks": [82, 67, 91]})
print(df[(df["city"] == "Pune") & (df["marks"] > 85)]["name"].tolist())

Prints

['Meena']

Remember: Condition in brackets, & between them.

Common mistake: Writing 'and' instead of &. With columns you need &.

60-second card

loc and iloc

loc picks rows and columns by label; iloc picks them by position.

  • df.loc[0, 'name'] uses the row label 0 and the column name.
  • df.iloc[0, 1] uses positions: first row, second column.
  • loc slices include the end label; iloc slices don't.
import pandas as pd
df = pd.DataFrame({"name": ["Asha", "Ravi", "Meena"], "marks": [82, 67, 91]})
print(len(df.loc[0:1]), len(df.iloc[0:1]), df.loc[2, "name"])

Prints

2 1 Meena

Remember: loc = labels. iloc = integer positions.

Common mistake: Expecting df.loc[0:2] to give 2 rows. loc includes label 2, so you get 3.

60-second card

Sorting

sort_values orders rows by one or more columns.

  • df.sort_values('marks') sorts smallest first.
  • ascending=False sorts largest first.
  • Pass a list to sort by several columns: ['city', 'marks'].
import pandas as pd
df = pd.DataFrame({"name": ["Asha", "Ravi", "Meena"], "marks": [82, 67, 91]})
print(df.sort_values("marks", ascending=False)["name"].tolist())

Prints

['Meena', 'Asha', 'Ravi']

Remember: sort_values returns a new table; save it or use it straight away.

Common mistake: Calling df.sort_values('marks') and expecting df itself to change.

Topic 3

GroupBy and aggregation

groupby basics · Several summaries at once · Counting values

▶Open the lessonPractise this topic

60-second card

groupby basics

groupby splits the table into groups and summarises each one.

  • df.groupby('city')['marks'].mean() gives the average per city.
  • Use sum, count, max or min the same way.
  • The group names become the index of the result.
import pandas as pd
df = pd.DataFrame({"city": ["Pune", "Delhi", "Pune"], "marks": [82, 67, 91]})
print(df.groupby("city")["marks"].mean().to_dict())

Prints

{'Delhi': 67.0, 'Pune': 86.5}

Remember: Split, apply, combine.

Common mistake: Forgetting to pick a column before .mean(), which tries to average text columns too.

60-second card

Several summaries at once

agg lets you work out several summaries at once.

  • df.groupby('city')['marks'].agg(['mean', 'max'])
  • Name your results: agg(avg=('marks', 'mean'), top=('marks', 'max')).
  • Each summary becomes a column.
import pandas as pd
df = pd.DataFrame({"city": ["Pune", "Delhi", "Pune"], "marks": [82, 67, 91]})
r = df.groupby("city").agg(avg=("marks", "mean"), top=("marks", "max"))
print(r.loc["Pune"].tolist())

Prints

[86.5, 91.0]

Remember: One groupby, many summaries with agg.

Common mistake: Calling groupby several times for each summary. agg does it in one go.

60-second card

Counting values

value_counts counts how often each value appears in a column.

  • Results are sorted from most to least common.
  • normalize=True gives shares instead of counts.
  • Missing values are left out unless you pass dropna=False.
import pandas as pd
s = pd.Series(["Pune", "Delhi", "Pune", "Pune"])
print(s.value_counts().to_dict())

Prints

{'Pune': 3, 'Delhi': 1}

Remember: Quickest way to see what's in a column.

Common mistake: Using groupby(...).count() just to count values; value_counts is simpler.

Topic 4

Cleaning data

Missing values · Duplicates · Changing types

▶Open the lessonPractise this topic

60-second card

Missing values

Missing values show up as NaN. Find them, then drop or fill them.

  • df.isna().sum() counts missing values per column.
  • df.dropna() removes rows with any missing value.
  • df['marks'].fillna(0) or fillna(df['marks'].mean()) fills the gaps.
import pandas as pd
import numpy as np
s = pd.Series([80, np.nan, 90])
print(int(s.isna().sum()), s.fillna(s.mean()).tolist())

Prints

1 [80.0, 85.0, 90.0]

Remember: Count missing values before you decide what to do.

Common mistake: Filling everything with 0 without thinking. 0 marks and 'unknown' aren't the same.

60-second card

Duplicates

Duplicate rows can double-count your data. Find them and drop them.

  • df.duplicated() marks rows that repeat an earlier row.
  • df.drop_duplicates() removes them.
  • subset=['email'] checks only some columns.
import pandas as pd
df = pd.DataFrame({"email": ["a@x.in", "b@x.in", "a@x.in"], "marks": [82, 67, 82]})
print(int(df.duplicated().sum()), len(df.drop_duplicates()))

Prints

1 2

Remember: Decide what makes a row 'the same' before dropping.

Common mistake: Dropping duplicates on all columns when a key like email repeats with small differences.

60-second card

Changing types

Columns sometimes load with the wrong type, like numbers stored as text. Convert them.

  • df['marks'].astype(int) changes the type.
  • pd.to_numeric(col, errors='coerce') turns bad values into NaN instead of failing.
  • pd.to_datetime(col) turns date text into real dates.
import pandas as pd
s = pd.Series(["82", "67", "absent"])
print(pd.to_numeric(s, errors="coerce").tolist())

Prints

[82.0, 67.0, nan]

Remember: Check df.dtypes: maths on text columns won't work.

Common mistake: Adding a text column of numbers and getting joined text, like '8267'.

Topic 5

Combining data

merge · concat

▶Open the lessonPractise this topic

60-second card

merge

merge joins two tables on a shared column, like a SQL join.

  • pd.merge(students, depts, on='dept_id') keeps matching rows.
  • how='left' keeps every row of the left table.
  • Use left_on and right_on when the column names differ.
import pandas as pd
s = pd.DataFrame({"name": ["Asha", "Ravi", "Karan"], "dept_id": [10, 20, 99]})
d = pd.DataFrame({"dept_id": [10, 20], "dept": ["CSE", "ECE"]})
print(len(pd.merge(s, d, on="dept_id")), len(pd.merge(s, d, on="dept_id", how="left")))

Prints

2 3

Remember: merge = join tables side by side on a key.

Common mistake: Merging on a key with duplicates on both sides, which multiplies rows.

60-second card

concat

concat stacks tables on top of each other (or side by side).

  • pd.concat([jan, feb]) puts February's rows under January's.
  • ignore_index=True renumbers the rows 0, 1, 2 ...
  • Columns are matched by name; missing ones become NaN.
import pandas as pd
jan = pd.DataFrame({"sales": [10, 20]})
feb = pd.DataFrame({"sales": [30]})
print(pd.concat([jan, feb], ignore_index=True)["sales"].tolist())

Prints

[10, 20, 30]

Remember: concat = stack. merge = join on a key.

Common mistake: Forgetting ignore_index=True and ending up with repeated row labels.

Log inSign up

Practise a little every day

Five questions a day keep your Sunrise Streak going. Your progress is saved when you sign up.

Sign up free