1. Lighthouse

Level 9 · A repeatable spot-check sample

The request

From Angela Rivera, Head of Customer Support

“Every month my team phones ten random web customers about their order. Can you pick ten web orders for us, mark whether shipping was free, and make sure you'd pick the same ten if you ran it again?”

Your goal

Make web a copy (with .copy()) of the orders whose channel is 'web', and add a column free_shipping that is True where shipping_fee is 0. Set result to web.sample(n=10, random_state=7) with only the columns order_id, status, shipping_fee, free_shipping, in the order sample() returns the rows (don't sort, don't reset the index).

  • Use the orders DataFramenot done yet
  • Show exactly order_id status shipping_fee free_shippingnot done yet
  • 10 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

    A filter result is not always a separate table

    When you filter, pandas may hand you something that is still tied to the original DataFrame. If you then add or change a column on it, pandas can’t be sure whether you meant to change orders too, and it warns you:

    web = orders[orders["channel"] == "web"]
    web["free_shipping"] = web["shipping_fee"] == 0
    # SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.

    The warning is pandas saying “this might not do what you think”. Here the column lands only in web, but closely related code, such as orders[orders["channel"] == "web"]["shipping_fee"] = 0, silently changes nothing at all. The clean answer is to say what you want: a separate table of your own.

    web = orders[orders["channel"] == "web"].copy()
    web["free_shipping"] = web["shipping_fee"] == 0   # no warning, orders is untouched

    Plain assignment, web2 = web, doesn’t copy anything either. It gives the same table a second name, so a change through one name shows up through the other. Use .copy() whenever you plan to modify a filtered or borrowed table.

    Random rows you can reproduce

    sample picks rows at random. n says how many; frac=0.1 would take 10% instead.

    web.sample(n=10)                   # a different ten every run
    web.sample(n=10, random_state=7)   # the same ten every run

    random_state is a seed: any whole number works, and the same number on the same table always picks the same rows. That matters for Angela’s team. If someone asks “why did you call these customers?”, you can rerun the code and get the identical list. With random_state=7, the first picks are orders 2453, 12392 and 8576.

    sample returns the rows in the random order it drew them, with their original index labels. For a call list that’s fine, so leave the order alone here.

    Reading the sample

    Eight of the ten sampled orders shipped free. Across all 5,913 web orders the share is about 79%, so the sample looks typical. A small sample can easily look unusual by chance, which is worth knowing before anyone reads too much into ten rows.

    Common mistakes

    • Skipping .copy() and getting a SettingWithCopyWarning when you add the column.
    • Thinking web2 = web makes a copy. It doesn’t; both names point to the same table.
    • Leaving out random_state, so the list changes every time you run it.
    • Sampling orders first and filtering afterwards, which gives fewer than ten web orders.
    • Sorting or resetting the sample when the task asks for it as drawn.

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