1. Lighthouse

Level 1 · Cohorts by first order

The request

From Jordan Reyes, Head of Marketing

“Before we talk retention I want to know who we are retaining. How many new customers did we win each quarter since 2023? I suspect the holiday quarters bring in a lot of them.”

Your goal

Booked orders are those with status "completed" or "refunded". Set result to a DataFrame with one row per quarter of each customer's first booked order and columns cohort (the quarter as text, like "2023Q1") and new_customers (customers whose first booked order falls in that quarter), sorted by cohort ascending, with a default 0..n index.

  • Use the orders DataFramenot done yet
  • Show exactly cohort new_customersnot done yet
  • 12 rows, sorted as askednot done yet

Your code

Python

Loading the editor…

    ResultPreview of orders · press Run to see yours
    Preview of orders
    order_idcustomer_idorder_datestatuschannel
    10011252023-01-01 20:51:19completedweb
    10021562023-01-02 07:58:46completedweb
    1003222023-01-02 10:25:27completedmarketplace
    1004482023-01-02 11:21:51completedmarketplace

    Mote checks your result

    Press Run. Each row that matches the goal becomes a firefly in your lantern.

    DataFrames

    Loaded for you as pandas DataFrames, plus pd and np.

    orders12,000 rows · 7 columns
    • order_idinteger
    • customer_idinteger
    • order_datetimestamp
    • statusvarchar
    • channelvarchar
    • shipping_feedecimal
    • coupon_codevarchar
    First 5 rows of orders
    order_idcustomer_idorder_datestatuschannelshipping_feecoupon_code
    10011252023-01-01 20:51:19completedweb0.00NaN
    10021562023-01-02 07:58:46completedweb0.00NaN
    1003222023-01-02 10:25:27completedmarketplace4.99WELCOME10
    1004482023-01-02 11:21:51completedmarketplace4.99WELCOME10
    1005822023-01-02 11:43:36completedweb0.00WELCOME10
    customers2,018 rows · 9 columns
    • customer_idinteger
    • first_namevarchar
    • last_namevarchar
    • emailvarchar
    • cityvarchar
    • statevarchar
    • signup_datedate
    • segmentvarchar
    • referral_sourcevarchar
    First 5 rows of customers
    customer_idfirst_namelast_nameemailcitystatesignup_datesegmentreferral_source
    1OwenHudsonowen.hudson@icloud.comSan FranciscoCA2022-06-02consumersearch
    2DouglasMendozadmendoza69@gmail.comAtlantaGA2022-06-02consumerNaN
    3HenryBrookshbrooks@lakesidecafe.comLos AngelesCA2022-06-04businessNaN
    4BrianGrahambgraham@bluecedarhomes.comSeattleWA2022-06-06businesspinterest
    5KyleJimenezkjimenez27@yahoo.comIndianapolisIN2022-06-07consumerNaN
    products120 rows · 8 columns
    • product_idinteger
    • namevarchar
    • categoryvarchar
    • subcategoryvarchar
    • unit_pricedecimal
    • unit_costdecimal
    • launched_ondate
    • is_activeboolean
    First 5 rows of products
    product_idnamecategorysubcategoryunit_priceunit_costlaunched_onis_active
    101Vale Velvet LoveseatFurnitureSofas1659.00NaN2023-09-11true
    102Alder Oak Coffee TableFurnitureTables919.00503.502024-05-16true
    103Orchard Rattan Dining ChairFurnitureChairs789.00429.872023-05-27true
    104Upland Oak BookcaseFurnitureStorage429.00214.702022-12-20true
    105Avery Leather Bed FrameFurnitureBeds449.00232.702021-08-31true
    order_items30,338 rows · 6 columns
    • order_item_idinteger
    • order_idinteger
    • product_idinteger
    • quantityinteger
    • unit_pricedecimal
    • discount_pctdecimal
    First 5 rows of order_items
    order_item_idorder_idproduct_idquantityunit_pricediscount_pct
    11001121931.990.00
    21001154311.990.00
    31002154411.990.00
    410021941149.000.00
    51002193219.990.00
    returns1,673 rows · 5 columns
    • return_idinteger
    • order_item_idinteger
    • returned_ondate
    • reasonvarchar
    • refund_amountdecimal
    First 5 rows of returns
    return_idorder_item_idreturned_onreasonrefund_amount
    1142023-01-10damaged83.69
    2422023-01-10wrong_item19.99
    31052023-01-14wrong_item10.99
    4242023-01-16changed_mind26.99
    51262023-01-16late20.99
    employees60 rows · 8 columns
    • employee_idinteger
    • first_namevarchar
    • last_namevarchar
    • departmentvarchar
    • titlevarchar
    • manager_idinteger
    • hire_datedate
    • salaryinteger
    First 5 rows of employees
    employee_idfirst_namelast_namedepartmenttitlemanager_idhire_datesalary
    1CatherineHaleExecutiveChief Executive OfficerNaN2016-03-01285000
    2RobertKimExecutiveChief Operating Officer12017-01-09235000
    3MeganCollinsSalesHead of Sales12018-04-16172000
    4ChloeGutierrezSalesAccount Executive32020-01-2172000
    5FrankBellSalesAccount Executive32023-05-2173000
    web_sessions40,000 rows · 7 columns
    • session_idinteger
    • customer_idinteger
    • started_attimestamp
    • devicevarchar
    • sourcevarchar
    • pages_viewedinteger
    • convertedboolean
    First 5 rows of web_sessions
    session_idcustomer_idstarted_atdevicesourcepages_viewedconverted
    1NaN2023-01-01 23:02:24mobilepaid1false
    2182023-01-01 15:07:49desktoppaid1false
    3NaN2023-01-01 16:55:46desktopdirect7false
    4NaN2023-01-01 12:43:28mobileorganic3false
    5NaN2023-01-01 13:06:21mobilesocial2false
    marketing_spend3,276 rows · 3 columns
    • spend_datedate
    • channelvarchar
    • amountdecimal
    First 5 rows of marketing_spend
    spend_datechannelamount
    2023-01-01paid492.99
    2023-01-01email37.38
    2023-01-01social200.53
    2023-01-02paid709.13
    2023-01-02email64.13

    The lesson

    What a cohort is

    A cohort is a group of customers who share a starting point. For a store, the natural starting point is the first purchase: everyone whose first order fell in January to March 2023 is the 2023Q1 cohort. From then on you follow the same people over time and ask what share of them came back.

    Cohorts fix the biggest problem with “repeat rate this year”: the customers in the denominator are not comparable. Someone who first bought in December has had weeks to come back; someone who first bought three years ago has had years. Grouping by start date compares like with like.

    One date per customer

    The cohort comes from a single date per customer, the earliest booked order:

    booked = orders[orders["status"].isin(["completed", "refunded"])]
    first = booked.groupby("customer_id")["order_date"].min()

    Only booked orders count. A cancelled order was never paid, and a pending one may never be. A customer whose first attempt was cancelled and whose first real purchase came two months later belongs to the later cohort. Refunded orders do count: the customer did buy, even if the product came back.

    Months or quarters

    Monthly cohorts are the textbook default, but Harbor & Pine wins about 100 to 250 new customers a quarter. Split by month, 22 of the 36 cohorts hold between 28 and 42 people, and their retention numbers jump around from noise alone. Quarterly cohorts are big enough to read. pandas turns a date into its quarter with a period:

    first.dt.to_period("Q").astype(str)   # "2023Q1", "2023Q2", ...

    Text like "2023Q1" sorts correctly, which keeps the table in time order.

    Reading the sizes

    Look at the sizes before any retention number. Here the fourth quarter of each year brings in far more customers than the others, because holiday shoppers arrive in November and December. That matters later: holiday cohorts are full of gift buyers, who often do not come back, so a big Q4 cohort can drag the overall retention rate down without anything getting worse.

    The 2023Q1 cohort is big for a different reason: 116 of its 177 customers signed up before 2023. The data starts in January 2023, so for them “first order in the data” is not their first order ever. Treat that cohort as existing customers, not new ones.

    Common mistakes

    • Using the signup date. Signing up is not buying. About 230 customers never ordered at all.
    • Using any order status. Cancelled first orders put people in the wrong cohort.
    • Too many, too small cohorts. If a cohort has a few dozen people, merge to quarters.

    Pick what may run on this site. You can change this any time from "Cookie settings" at the bottom of every page.