The request

From Brian Mitchell, Finance Analyst
Your goal
Fit a straight line of monthly["revenue"] on monthly["spend"] with np.polyfit(x, y, 1). Set result to a dict: "slope" rounded to 2 decimals, "intercept" rounded to 0 decimals, and "r2" (the squared correlation of the two columns) rounded to 3 decimals.
- Use the
ordersDataFramenot done yet - Use the
order_itemsDataFramenot done yet - Store a dict in
resultnot done yet
One dot per month. The five dots far to the right are all Novembers and Decembers.
Show the numbers
| Marketing spend in the month | Revenue in the month |
|---|---|
| $27,045 | $85,437 |
| $23,861 | $66,625 |
| $28,064 | $87,788 |
| $28,975 | $106,298 |
| $29,574 | $146,984 |
| $27,652 | $102,555 |
| $30,030 | $145,155 |
| $29,177 | $140,662 |
| $30,443 | $118,229 |
| $31,944 | $128,086 |
| $53,609 | $231,165 |
| $41,817 | $241,527 |
| $31,341 | $109,306 |
| $28,007 | $77,547 |
| $31,957 | $161,478 |
| $31,847 | $142,766 |
| $34,146 | $151,773 |
| $30,973 | $146,719 |
| $33,858 | $136,668 |
| $33,903 | $156,410 |
| $34,403 | $151,881 |
| $36,786 | $149,408 |
| $62,236 | $319,217 |
| $52,436 | $290,432 |
| $35,944 | $150,571 |
| $31,328 | $99,903 |
| $36,419 | $166,787 |
| $36,895 | $189,735 |
| $40,022 | $206,469 |
| $38,016 | $213,062 |
| $39,652 | $191,967 |
| $40,143 | $182,987 |
| $39,381 | $143,379 |
| $42,808 | $174,599 |
| $70,675 | $292,364 |
| $59,359 | $288,347 |
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 Brian 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 |
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 |
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 |
The lesson
A line through the dots
A simple linear regression finds the straight line y = slope × x + intercept that sits closest to
the points, in the sense that the squared vertical distances from the points to the line add up to
as little as possible (“least squares”). In NumPy it is one call:
slope, intercept = np.polyfit(monthly["spend"], monthly["revenue"], 1)
# slope ≈ 5.50, intercept ≈ -40,288
The 1 is the degree: a straight line. The order of the arguments matters: x (the column you
predict from) first, y (the one you predict) second. Swap them and you get a different line.
Reading the slope
The slope is the change in y per one unit of x. Here: months with $1,000 more marketing spend had about $5,500 more revenue. Read every word of that sentence. It compares months; it describes this data; it says nothing about what happens if you add $1,000 next month. Level 2 showed why: November and December have big budgets and holiday shoppers, so the slope carries both.
Reading the intercept
The intercept is the predicted y when x is 0: here, -$40,288 of revenue in a month with no marketing. Negative revenue is impossible. The intercept is just where the line crosses zero, far to the left of every real month (the lowest spend was $23,861). Treat it as a parameter of the line, not a forecast.
R²: how much of the variation the line follows
R² (R-squared) is the share of the variation in y around its mean that the line accounts for. For one x it is the correlation squared:
monthly["spend"].corr(monthly["revenue"]) ** 2 # 0.845
0.845 means the line follows revenue’s ups and downs closely. It doesn’t mean the line is causal, and it doesn’t mean predictions are accurate to 84.5%. A high R² with a confounder is still a confounded line.
Common mistakes
- Swapping x and y in
np.polyfit. The slope of revenue on spend is not 1 / (slope of spend on revenue) unless the points sit exactly on a line. - Calling the slope a return on investment. It is an association across months.
- Reading the intercept as a real scenario when x = 0 is far outside the data.
- Treating a high R² as proof. It measures fit, not cause.
Lantern lit!
Practised: linear regressionslopeinterceptr squared
- Solved
- No hints
- First run
