The request

From Kevin Brooks, Operations Manager
Your goal
daily has one row per day from 2023-01-01 to 2025-12-31 and one column per channel, holding that day's completed revenue (0 on days without a sale). Set result to a DataFrame with one row per channel (sorted A to Z) and columns channel, mean and std of daily revenue (pandas defaults, rounded to 2), and cv: the standard deviation divided by the mean, rounded to 3.
- Use the
ordersDataFramenot done yet - Use the
order_itemsDataFramenot done yet - Show exactly
channelmeanstdcvnot done yet
Each box holds the middle half of the 1,096 days; the line inside is the median day. Dots are unusually big days. A few days above $10,000 are not drawn.
Show the numbers
| Group | Values | Lower whisker | Q1 | Median | Q3 | Upper whisker | Beyond whiskers |
|---|---|---|---|---|---|---|---|
| app | 1,096 | $0 | $383.78 | $1,219 | $2,611 | $5,943 | 56 |
| marketplace | 1,096 | $0 | $0 | $307.44 | $983.58 | $2,452 | 84 |
| web | 1,096 | $0 | $997.11 | $2,092 | $3,825 | $8,033 | 45 |
Your code
Loading the editor…
Reference solution
| order_id | customer_id | order_date | status | channel |
|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace |
Mote checks your result
Press Run. Each row that matches the goal becomes a firefly in your lantern.
What Kevin gets, and why
DataFrames
Loaded for you as pandas DataFrames, plus pd and np.
orders12,000 rows · 7 columns
order_idintegercustomer_idintegerorder_datetimestampstatusvarcharchannelvarcharshipping_feedecimalcoupon_codevarchar
| order_id | customer_id | order_date | status | channel | shipping_fee | coupon_code |
|---|---|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web | 0.00 | NaN |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web | 0.00 | NaN |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace | 4.99 | WELCOME10 |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace | 4.99 | WELCOME10 |
| 1005 | 82 | 2023-01-02 11:43:36 | completed | web | 0.00 | WELCOME10 |
order_items30,338 rows · 6 columns
order_item_idintegerorder_idintegerproduct_idintegerquantityintegerunit_pricedecimaldiscount_pctdecimal
| order_item_id | order_id | product_id | quantity | unit_price | discount_pct |
|---|---|---|---|---|---|
| 1 | 1001 | 121 | 9 | 31.99 | 0.00 |
| 2 | 1001 | 154 | 3 | 11.99 | 0.00 |
| 3 | 1002 | 154 | 4 | 11.99 | 0.00 |
| 4 | 1002 | 194 | 1 | 149.00 | 0.00 |
| 5 | 1002 | 193 | 2 | 19.99 | 0.00 |
customers2,018 rows · 9 columns
customer_idintegerfirst_namevarcharlast_namevarcharemailvarcharcityvarcharstatevarcharsignup_datedatesegmentvarcharreferral_sourcevarchar
| customer_id | first_name | last_name | city | state | signup_date | segment | referral_source | |
|---|---|---|---|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco | CA | 2022-06-02 | consumer | search |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta | GA | 2022-06-02 | consumer | NaN |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles | CA | 2022-06-04 | business | NaN |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle | WA | 2022-06-06 | business | |
| 5 | Kyle | Jimenez | kjimenez27@yahoo.com | Indianapolis | IN | 2022-06-07 | consumer | NaN |
products120 rows · 8 columns
product_idintegernamevarcharcategoryvarcharsubcategoryvarcharunit_pricedecimalunit_costdecimallaunched_ondateis_activeboolean
| product_id | name | category | subcategory | unit_price | unit_cost | launched_on | is_active |
|---|---|---|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 | NaN | 2023-09-11 | true |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 | 503.50 | 2024-05-16 | true |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 | 429.87 | 2023-05-27 | true |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 | 214.70 | 2022-12-20 | true |
| 105 | Avery Leather Bed Frame | Furniture | Beds | 449.00 | 232.70 | 2021-08-31 | true |
returns1,673 rows · 5 columns
return_idintegerorder_item_idintegerreturned_ondatereasonvarcharrefund_amountdecimal
| return_id | order_item_id | returned_on | reason | refund_amount |
|---|---|---|---|---|
| 1 | 14 | 2023-01-10 | damaged | 83.69 |
| 2 | 42 | 2023-01-10 | wrong_item | 19.99 |
| 3 | 105 | 2023-01-14 | wrong_item | 10.99 |
| 4 | 24 | 2023-01-16 | changed_mind | 26.99 |
| 5 | 126 | 2023-01-16 | late | 20.99 |
employees60 rows · 8 columns
employee_idintegerfirst_namevarcharlast_namevarchardepartmentvarchartitlevarcharmanager_idintegerhire_datedatesalaryinteger
| employee_id | first_name | last_name | department | title | manager_id | hire_date | salary |
|---|---|---|---|---|---|---|---|
| 1 | Catherine | Hale | Executive | Chief Executive Officer | NaN | 2016-03-01 | 285000 |
| 2 | Robert | Kim | Executive | Chief Operating Officer | 1 | 2017-01-09 | 235000 |
| 3 | Megan | Collins | Sales | Head of Sales | 1 | 2018-04-16 | 172000 |
| 4 | Chloe | Gutierrez | Sales | Account Executive | 3 | 2020-01-21 | 72000 |
| 5 | Frank | Bell | Sales | Account Executive | 3 | 2023-05-21 | 73000 |
web_sessions40,000 rows · 7 columns
session_idintegercustomer_idintegerstarted_attimestampdevicevarcharsourcevarcharpages_viewedintegerconvertedboolean
| session_id | customer_id | started_at | device | source | pages_viewed | converted |
|---|---|---|---|---|---|---|
| 1 | NaN | 2023-01-01 23:02:24 | mobile | paid | 1 | false |
| 2 | 18 | 2023-01-01 15:07:49 | desktop | paid | 1 | false |
| 3 | NaN | 2023-01-01 16:55:46 | desktop | direct | 7 | false |
| 4 | NaN | 2023-01-01 12:43:28 | mobile | organic | 3 | false |
| 5 | NaN | 2023-01-01 13:06:21 | mobile | social | 2 | false |
marketing_spend3,276 rows · 3 columns
spend_datedatechannelvarcharamountdecimal
| spend_date | channel | amount |
|---|---|---|
| 2023-01-01 | paid | 492.99 |
| 2023-01-01 | 37.38 | |
| 2023-01-01 | social | 200.53 |
| 2023-01-02 | paid | 709.13 |
| 2023-01-02 | 64.13 |
The lesson
Same average, different risk
Imagine two stores that both sell $1,000 a day on average. In the first, most days land between $950 and $1,050. In the second, one day brings $400 and the next $1,800. The averages are equal; the businesses are not. The first can be staffed and stocked from the average; the second needs a buffer, because “average” is rarely what happens.
The standard deviation from level 4 measures exactly that: the typical distance of a day from the average day. Small means predictable, large means volatile.
Daily revenue per channel
The starter builds daily: one row per calendar day, one column per channel. Taking the standard
deviation of each column answers Kevin’s question:
daily.mean() # app 1847.38, marketplace 764.13, web 2766.49
daily.std() # app 2039.60, marketplace 1190.90, web 2502.56
On every channel the standard deviation is about as large as the mean, or larger. Daily revenue here is driven by a few big business orders and by the November and December peaks, so a “normal day” is hard to define. The box plot shows it: the boxes are short and the dots above them run far.
The coefficient of variation
Web’s standard deviation ($2,503) is the largest, yet web also sells the most. To compare spread between groups of different size, divide the standard deviation by the mean. That ratio is the coefficient of variation (CV):
cv = daily.std() / daily.mean() # web 0.905, app 1.104, marketplace 1.559
A CV of 0.9 means a typical day is about 90% of the average away from it. Web is the steadiest channel relative to its size; marketplace is the least predictable, with a typical swing of more than one and a half times its average day.
Count the empty days
Marketplace had no completed sale on 295 of the 1,096 days. If you group the orders by day without
filling in those days, they disappear: the mean rises to $1,046 and the CV falls to 1.23, which
makes the channel look steadier than it is. A day without sales is a real day with revenue 0. The
starter’s reindex(...).fillna(0) puts them back.
Common mistakes
- Comparing standard deviations of groups with different means. Use the CV, or compare each group’s spread to its own average.
- Dropping zero days. Grouping orders by day only creates the days that had orders. Build the full calendar first.
- Using the CV on data that can be negative or average near zero. Dividing by a mean close to 0 makes the ratio explode; it is meant for positive quantities like revenue.
- Reading volatility as bad. A channel with big swings may simply sell big items. It still needs more buffer in the plan.
Lantern lit!
Practised: standard deviationcoefficient of variationvolatilitygroupby
- Solved
- No hints
- First run
