Three months of orders, the five questions a manager asks, answered with pandas.
/build/project-sales-analysis-pandas with the starter and the rubric already in it.Load three months of orders from a small electronics shop into a DataFrame and answer the manager's questions: revenue by region, top products, revenue per month, month-on-month growth and a region × product pivot table of units.
groupby, pivot_table and pct_change are most of what a fresher data analyst does in the first month. Here they run on data small enough to check by hand, so you can trust every number you print.
You can load CSV data into pandas, add a derived column, group, pivot and compute growth rates.
Each step is one function in sales.py. In the workspace, press Check next to a step: it runs your file and tells you exactly what is still wrong.
Build against this exact list — it is the spec your published project is judged on.
Copy this into a new file — or open it in a workspace as sales.py. The TODO parts are yours to fill.
"""
Sales analysis with pandas.
Three months of orders from a small electronics shop. Answers the questions
a manager actually asks: which region sells most, which products earn most,
how revenue moved month to month.
Fill in one function per step, press Run, then press "Check step".
The first Run downloads pandas into your browser (a few MB, once).
"""
import io
import pandas as pd
SALES_CSV = """order_id,date,region,product,units,unit_price
1001,2026-07-02,North,Earbuds,3,1499
1002,2026-07-05,South,Power Bank,2,1199
1003,2026-07-09,West,Smartwatch,1,3999
1004,2026-07-14,North,Power Bank,4,1199
1005,2026-07-21,East,Earbuds,2,1499
1006,2026-07-28,South,Smartwatch,2,3999
1007,2026-08-03,West,Earbuds,5,1499
1008,2026-08-07,North,Smartwatch,1,3999
1009,2026-08-12,South,Earbuds,3,1499
1010,2026-08-18,East,Power Bank,6,1199
1011,2026-08-25,West,Speaker,2,2499
1012,2026-08-30,North,Speaker,1,2499
1013,2026-09-02,South,Speaker,3,2499
1014,2026-09-06,East,Smartwatch,2,3999
1015,2026-09-11,North,Earbuds,4,1499
1016,2026-09-15,West,Power Bank,3,1199
1017,2026-09-22,South,Smartwatch,3,3999
1018,2026-09-27,East,Earbuds,1,1499
"""
def load(csv_text: str = SALES_CSV) -> pd.DataFrame:
# TODO: pd.read_csv(io.StringIO(csv_text), parse_dates=["date"]),
# then add a "revenue" column = units * unit_price.
raise NotImplementedError("step 1, load(): read the CSV and add revenue")
def revenue_by_region(df: pd.DataFrame) -> pd.Series:
# TODO: total revenue per region, highest first.
# Hint: df.groupby("region")["revenue"].sum().sort_values(...)
raise NotImplementedError("step 2, revenue_by_region(): groupby + sum")
def top_products(df: pd.DataFrame, n: int = 3) -> pd.Series:
# TODO: the n products with the most revenue, highest first. Hint: nlargest
raise NotImplementedError("step 3, top_products(): best sellers by revenue")
def monthly_revenue(df: pd.DataFrame) -> pd.Series:
# TODO: revenue per month, indexed by "YYYY-MM" strings, oldest first.
# Hint: df["date"].dt.strftime("%Y-%m")
raise NotImplementedError("step 4, monthly_revenue(): revenue per month")
def month_on_month(monthly: pd.Series) -> pd.Series:
# TODO: % change from the previous month, 1 decimal. First month is NaN.
# Hint: pct_change()
raise NotImplementedError("step 5, month_on_month(): growth in %")
def region_product_table(df: pd.DataFrame) -> pd.DataFrame:
# TODO: units sold, regions as rows and products as columns, 0 where
# nothing sold. Hint: df.pivot_table(..., aggfunc="sum", fill_value=0)
raise NotImplementedError("step 6, region_product_table(): pivot table")
def main() -> None:
df = load()
print(f"{len(df)} orders, total revenue ₹{df['revenue'].sum():,}")
print("\nRevenue by region:")
for region, amount in revenue_by_region(df).items():
print(f" {region:<6} ₹{amount:>7,}")
print("\nTop 3 products:")
for product, amount in top_products(df).items():
print(f" {product:<11} ₹{amount:>7,}")
monthly = monthly_revenue(df)
growth = month_on_month(monthly)
print("\nMonth Revenue Change")
for month, amount in monthly.items():
change = "" if pd.isna(growth[month]) else f"{growth[month]:+.1f}%"
print(f" {month} ₹{amount:>7,} {change}".rstrip())
print("\nUnits by region and product:")
print(region_product_table(df).to_string())
if __name__ == "__main__":
try:
main()
except NotImplementedError as todo:
# A fresh starter is SUPPOSED to stop here. Say which step is next
# instead of printing a traceback that looks like a bug.
print(f"Not built yet: {todo}")
print("Write that function, then press Run again. Each step you finish moves this message forward.")
Try every step first. This version passes all 6 checks; yours can look different and still pass.
"""
Sales analysis with pandas.
Three months of orders from a small electronics shop. Answers the questions
a manager actually asks: which region sells most, which products earn most,
how revenue moved month to month.
"""
import io
import pandas as pd
SALES_CSV = """order_id,date,region,product,units,unit_price
1001,2026-07-02,North,Earbuds,3,1499
1002,2026-07-05,South,Power Bank,2,1199
1003,2026-07-09,West,Smartwatch,1,3999
1004,2026-07-14,North,Power Bank,4,1199
1005,2026-07-21,East,Earbuds,2,1499
1006,2026-07-28,South,Smartwatch,2,3999
1007,2026-08-03,West,Earbuds,5,1499
1008,2026-08-07,North,Smartwatch,1,3999
1009,2026-08-12,South,Earbuds,3,1499
1010,2026-08-18,East,Power Bank,6,1199
1011,2026-08-25,West,Speaker,2,2499
1012,2026-08-30,North,Speaker,1,2499
1013,2026-09-02,South,Speaker,3,2499
1014,2026-09-06,East,Smartwatch,2,3999
1015,2026-09-11,North,Earbuds,4,1499
1016,2026-09-15,West,Power Bank,3,1199
1017,2026-09-22,South,Smartwatch,3,3999
1018,2026-09-27,East,Earbuds,1,1499
"""
def load(csv_text: str = SALES_CSV) -> pd.DataFrame:
df = pd.read_csv(io.StringIO(csv_text), parse_dates=["date"])
df["revenue"] = df["units"] * df["unit_price"]
return df
def revenue_by_region(df: pd.DataFrame) -> pd.Series:
return df.groupby("region")["revenue"].sum().sort_values(ascending=False)
def top_products(df: pd.DataFrame, n: int = 3) -> pd.Series:
return df.groupby("product")["revenue"].sum().nlargest(n)
def monthly_revenue(df: pd.DataFrame) -> pd.Series:
return df.groupby(df["date"].dt.strftime("%Y-%m"))["revenue"].sum()
def month_on_month(monthly: pd.Series) -> pd.Series:
return (monthly.pct_change() * 100).round(1)
def region_product_table(df: pd.DataFrame) -> pd.DataFrame:
return df.pivot_table(index="region", columns="product", values="units", aggfunc="sum", fill_value=0)
def main() -> None:
df = load()
print(f"{len(df)} orders, total revenue ₹{df['revenue'].sum():,}")
print("\nRevenue by region:")
for region, amount in revenue_by_region(df).items():
print(f" {region:<6} ₹{amount:>7,}")
print("\nTop 3 products:")
for product, amount in top_products(df).items():
print(f" {product:<11} ₹{amount:>7,}")
monthly = monthly_revenue(df)
growth = month_on_month(monthly)
print("\nMonth Revenue Change")
for month, amount in monthly.items():
change = "" if pd.isna(growth[month]) else f"{growth[month]:+.1f}%"
print(f" {month} ₹{amount:>7,} {change}".rstrip())
print("\nUnits by region and product:")
print(region_product_table(df).to_string())
if __name__ == "__main__":
main()
sales.py and a README.md holding all 5 rubric items as a checklist.pyrun.in/u/<handle>/w/project-sales-analysis-pandas.pyrun.in/u/<handle> portfolio page.Your workspace saves to this browser only. Sign in to keep it across devices and to publish it.
Flip the workspace to Public and paste its URL below, or push the file to a GitHub gist or repo. Paste the code inline too if you want the optional AI review to comment on specific lines.
A published PyRun workspace URL (pyrun.in/u/<handle>/w/project-sales-analysis-pandas) works as the public URL too.