Lesson 1 of 2 in this module

1/8 in track

From a business question to a table question

pandas10 min

Overview

A manager asks 'is UPI a problem?'. Learn to turn that into a metric, a filter and a time range you can compute.

On this page5 sections

What happened

Priya runs the online store. On Monday she sends you one line: "Is UPI a problem?" That is the whole brief.

You could open the payments table and start counting things. Ten minutes later you would have a number, and no idea whether it answers her.

Her question is real, but it is not a table question yet. A table question names a table, the rows to keep and the number to compute.

Why it broke (or worked)

"Is UPI a problem?" hides four decisions. What does problem mean? Which rows count? Compared with what? Over which dates?

One vague sentence, four small decisions.

PartPriya's wordsThe decision you make
Metrica problemShare of payments that failed
RowsUPIdf_payments where method is upi
Compared with(nothing said)The other methods: card, netbanking, wallet
Time range(nothing said)All of August, the dates in the table

Write these four down before you code. If one is a guess, send Priya a one-line message and ask. It is cheaper than redoing the work.

A question is ready to code when you can name the metric, the rows, the comparison and the dates.

The pattern to steal

Say the question as one sentence: "The share of payments that failed, split by method, for August." Every word in it maps to a line of pandas.

Look at the table first

You cannot filter a column you have not seen. Print the size and the first rows.

PythonSize and first rows of payments
print(df_payments.shape)
print(df_payments.head(3))
(150, 6)
  payment_id  order_id   amount      method    status              paid_at
0   PAY-0001  ORD-0001   612.07  netbanking  captured  2026-08-02 17:29:28
1   PAY-0002  ORD-0002   446.70         upi  refunded  2026-08-03 22:03:58
2   PAY-0003  ORD-0003  1104.32  netbanking  captured  2026-08-06 10:37:04

150 rows, 6 columns. One row is one payment attempt. The status column has the word we need.

How you write it

Turn "failed" into a filter

A filter keeps the rows where a test is true: df[df["status"] == "failed"]. Read it as: from df, keep the rows where status equals failed.

PythonFailed payments
failed = df_payments[df_payments["status"] == "failed"]
print(len(failed), "failed payments out of", len(df_payments))
29 failed payments out of 150

29 of 150 is about 19%. That is a number, but it is not yet an answer to "is UPI a problem". For that you split by method. The lesson on rates does exactly this.

Watch outA count is not an answer

UPI had 12 failures and card had 6. UPI made 43 payments and card made 35. Always ask: out of how many?

What if the question is still unclear after I write the four parts?

Ask. Send two lines: "I will measure the share of failed payments by method for August. Is that what you meant?" A quick yes saves a wasted day.

Do I need to know pandas to write the four parts?

No. Write them in plain words first. The code comes second and is usually short.

What comes next

Next you take a first look at a table you have never seen, so you know what is in it before you trust any number from it.

Going further: the same question, three different answers

Two analysts can both answer "is UPI a problem?" correctly and still give different numbers, because they chose different metrics. Try three metrics on a tiny payments table, so you can check every number by hand.

PythonThree metrics for one question
import pandas as pd

payments = pd.DataFrame({
    "method": ["upi", "upi", "upi", "upi", "card", "card", "card", "card"],
    "status": ["failed", "captured", "captured", "captured", "failed", "failed", "captured", "captured"],
    "amount": [900.0, 450.0, 300.0, 250.0, 120.0, 80.0, 600.0, 700.0],
})
for method, rows in payments.groupby("method"):
    failed = rows[rows["status"] == "failed"]
    print(method, "| count:", len(failed), "| rate:", round(len(failed) / len(rows) * 100, 1), "% | rupees:", failed["amount"].sum())
card | count: 2 | rate: 50.0 % | rupees: 200.0
upi | count: 1 | rate: 25.0 % | rupees: 900.0

On this small sample, card has 2 failures out of 4 and UPI has 1 out of 4. By count and by rate, card looks worse. By rupees, UPI looks worse, because its one failure was a Rs 900 payment. The metric you pick changes the answer, which is why you choose it before you look.

MetricBest when someone asks
CountHow many customers did we annoy?
RateIs this method worse than the others?
RupeesHow much money is at risk?

Try a new scenario

The marketing lead asks: "Are weekend orders a problem?" Write the four parts: metric, rows, comparison and time range.

Work it out, then open the answer

One good version: the metric is the share of orders that end cancelled or refunded; the rows are orders created on Saturday or Sunday; the comparison is orders created Monday to Friday; the time range is the dates in the table. Then check the order count per group before you trust any percentage.

Why do analysts ask so many questions before they code?

Because the code is easy and the wrong question is expensive. A two-line message can save a day of work on the wrong metric.

Close the lesson and explain it

Without scrolling up, name the four parts of a table question and say why a count alone is not an answer.

Practicals · load into the editor

After you read the theory, run these in the pane on the right. They execute in this tab, no cluster.

Finished this lesson?

Mark it as read when you could explain it to someone else.

Rate:
Was this useful?