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.
| Part | Priya's words | The decision you make |
|---|---|---|
| Metric | a problem | Share of payments that failed |
| Rows | UPI | df_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.
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.
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.
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.
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.
| Metric | Best when someone asks |
|---|---|
| Count | How many customers did we annoy? |
| Rate | Is this method worse than the others? |
| Rupees | How 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.