Day 12: Selecting, Filtering & Sorting
✅ Today you will learn
- loc (labels) vs iloc (positions)
- Boolean filters with &, |, ~
- isin, between, str.contains
- query() for readable filters
- sort_values, nlargest and safe updates with loc
🏢 In the real world
A marketing team asks: “Give me all female customers aged 25–35 in metro cities who paid by UPI and gave a rating below 3.” This is a one-line pandas filter – and it decides who gets a ₹100 coupon.
loc vs iloc
df.loc[rows, cols]
- Uses index labels and column names
- Slices include the end label
- df.loc[5, "city"]
- df.loc[df.price > 100, ["city"]]
df.iloc[rows, cols]
- Uses integer positions
- Slices exclude the end
- df.iloc[0, 2]
- df.iloc[:10, :3]
import pandas as pd
sales = pd.read_csv("sales_data.csv")
cols = ["order_id", "city", "category", "unit_price"]
print(sales.loc[0:2, cols]) # labels 0, 1, 2 (end included)
print(sales.iloc[0:2, 0:3]) # positions 0, 1 (end excluded)
print(sales.loc[10, "product"], "|", sales.iloc[10, 5])import pandas as pd
sales = pd.read_csv("sales_data.csv").set_index("order_id")
print(sales.loc["BK100500", ["city", "product", "unit_price"]])
print(sales.loc[["BK100001", "BK100002"], "category"])Boolean filtering
import pandas as pd
sales = pd.read_csv("sales_data.csv")
big = sales[sales["unit_price"] > 10000]
print("Orders above ₹10,000:", len(big))
metro_upi = sales[(sales["city"].isin(["Delhi", "Mumbai", "Bengaluru"])) & (sales["payment_mode"] == "UPI")]
print("Metro + UPI orders:", len(metro_upi))
not_cod = sales[~(sales["payment_mode"] == "Cash on Delivery")]
print("Prepaid orders:", len(not_cod))import pandas as pd
sales = pd.read_csv("sales_data.csv")
young = sales[sales["customer_age"].between(25, 35)]
phones = sales[sales["product"].str.contains("Phone|Watch", case=False)]
low = sales[sales["rating"] < 3]
print(len(young), "aged 25–35 |", len(phones), "phone/watch orders |", len(low), "low ratings")
print(phones["product"].value_counts())query() – filters you can read aloud
import pandas as pd
sales = pd.read_csv("sales_data.csv")
target = sales.query("customer_gender == 'Female' and 25 <= customer_age <= 35 "
"and region in ['North', 'West'] and payment_mode == 'UPI' and rating < 3")
print(len(target), "customers get the ₹100 coupon")
print(target[["order_id", "city", "customer_age", "rating"]].head())
limit = 2000
print(len(sales.query("unit_price > @limit")), "orders above", limit)Sorting and top-N
import pandas as pd
sales = pd.read_csv("sales_data.csv")
sales["revenue"] = sales["quantity"] * sales["unit_price"] * (1 - sales["discount"])
print(sales.sort_values("revenue", ascending=False)[["order_id", "product", "revenue"]].head(3))
print(sales.sort_values(["city", "revenue"], ascending=[True, False])[["city", "revenue"]].head(4))
print(sales.nlargest(3, "revenue")[["product", "revenue"]])
print(sales.nsmallest(2, "unit_price")[["product", "unit_price"]])Changing values the right way
import pandas as pd
sales = pd.read_csv("sales_data.csv")
sales.loc[sales["payment_mode"] == "Cash on Delivery", "payment_mode"] = "COD" # rename a category
sales.loc[sales["unit_price"] > 50000, "segment"] = "Premium"
sales["segment"] = sales["segment"].fillna("Regular")
print(sales["payment_mode"].value_counts().to_dict())
print(sales["segment"].value_counts().to_dict())Writing df[df.x > 5]["y"] = 0 may change a temporary copy and do nothing. Always use one .loc: df.loc[df.x > 5, "y"] = 0. If you need a separate table, add .copy(): sub = df[df.x > 5].copy().
Real example: find unhappy high-value customers
import pandas as pd
sales = pd.read_csv("sales_data.csv")
sales["revenue"] = sales["quantity"] * sales["unit_price"] * (1 - sales["discount"])
vip_unhappy = (sales[(sales["revenue"] >= 5000) & (sales["rating"] <= 3)]
.sort_values("revenue", ascending=False)
[["order_id", "city", "product", "revenue", "rating"]])
print(len(vip_unhappy), "high-value orders with rating ≤ 3")
print(vip_unhappy.head(5).to_string(index=False))
vip_unhappy.to_csv("call_these_customers.csv", index=False)The support team calls these customers first – fixing a ₹15,000 phone complaint protects far more future revenue than a ₹200 grocery complaint. Filtering + sorting = prioritising.
🏅 Job skills unlocked today
Practice tasks
🏋️ Practice – do it yourself
students_performance.csv, list students with attendance below 70 but average above 70.Show solution
import pandas as pd
st = pd.read_csv("students_performance.csv")
r = st[(st["attendance"] < 70) & (st["average"] > 70)]
print(len(r)); print(r[["student_id", "attendance", "average"]].head())house_prices.csv.Show solution
import pandas as pd
h = pd.read_csv("house_prices.csv")
print(h.query("city == 'Pune' and bedrooms == 3").nsmallest(5, "price_lakh")[["area_sqft", "age_years", "price_lakh"]])telecom_churn.csv, how many senior citizens on a monthly contract churned?Show solution
import pandas as pd
t = pd.read_csv("telecom_churn.csv")
print(len(t.query("senior_citizen == 1 and contract == 'Monthly' and churn == 'Yes'")))Quick quiz
🧠 Quick Quiz – test yourself
Interview corner
💼 Interview Corner
Explain the difference between loc and iloc.
loc selects by labels (index values and column names) and its slices include the end; iloc selects by integer position like Python lists and excludes the end. Use loc for filters with conditions.
How would you get the top 3 products by revenue in each city?
Sort by city and revenue descending, then groupby("city").head(3) – or use nlargest inside groupby().apply. Day 13 covers groupby in detail.
Summary
- loc = labels (end included); iloc = positions (end excluded).
- Filters: df[(cond1) & (cond2)], isin, between, str.contains, ~.
- query("col > @var") reads like English.
- Update with df.loc[cond, "col"] = value; use .copy() for subsets.
Day 13: GroupBy and pivot tables – the heart of every business report.
