1. Lighthouse

Level 6 · Boss: how big should the sample be?

The request

From Laura Bennett, Head of Finance

“The auditors want to keep sampling orders by hand. Tell me how far off a 100-order sample can be, prove it, and tell me how many orders they'd need to get the average within $25 of the real figure.”

Your goal

Step 1 of 3. Set result to a dict with "sd", the standard deviation of completed["order_value"] (pandas .std()), and "se", the standard error of the mean for a sample of 100 orders (sd divided by the square root of 100), both rounded to 2 decimals. Compute se from the unrounded sd.

  • Use the orders DataFramenot done yet
  • Use the order_items DataFramenot done yet
  • Store a dict in resultnot done yet

Step 1 · 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.

    Step 2 · 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.

      Step 3 · 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
        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
        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
        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

        The standard error

        Last level, one sample of 200 orders came out $28 below the true mean, and other samples landed anywhere from $385 to $581. The standard error (SE) puts one number on that wobble: it is the standard deviation of the sample mean across all the samples you could draw.

        sd = completed["order_value"].std()   # 795.75, spread of single orders
        se = sd / math.sqrt(100)              # 79.57, spread of 100-order averages

        The formula is SE = sd / √n. Two things set it: how spread out the values are (sd) and how many you sample (n). It falls with the square root of n, so four times the sample only halves the error.

        Checking it by simulation

        A formula is easier to trust once you have watched it work. With the whole population in memory you can draw many samples and look at their means directly:

        rng = np.random.default_rng(42)
        values = completed["order_value"].to_numpy()
        means = pd.Series([rng.choice(values, size=100, replace=False).mean() for _ in range(1000)])
        means.std()   # close to the formula's 79.57

        The list of 1,000 means is the sampling distribution of the mean. Its centre sits on the true mean, and its spread is the standard error. It is also far more bell-shaped than the order values themselves (skew 0.38 against 3.95): averages of many values smooth out the tail. That is the central limit theorem at work, and it is why a 1.96 multiplier works for means even when the data is skewed.

        From standard error to margin of error

        About 95% of sample means fall within 1.96 standard errors of the true mean, so the 95% margin of error of a sample mean is 1.96 × SE. For 100 orders that is 1.96 × 79.57 ≈ ±$156. Flip the formula around to plan a sample:

        n = math.ceil((1.96 * sd / 25) ** 2)   # orders needed for ±$25

        Round up: a sample of 3,892.1 orders doesn’t exist, and rounding down would miss the target.

        What the standard error doesn’t cover

        The standard error measures random sampling error only. A sample picked the wrong way (last level’s email visitors) has a small standard error and a big bias. Use it with random samples.

        Common mistakes

        • Confusing sd and SE. The sd describes single values and does not shrink with more data; the SE describes an average and does.
        • Expecting linear gains. Doubling the sample cuts the error by only 29%.
        • Mixing ddof. pandas .std() divides by n − 1, numpy’s np.std by n. Pick one and say so; here everything uses pandas.
        • Rounding n down. Sample sizes always round up.

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