{"id":"l-ml-1-3","courseId":"ml-crash-course","lang":"en","kind":"lesson","summary":"Use any scikit-learn model through the same three calls (fit, predict, score), read what a fitted model learned, and spot memorisation by comparing training and test scores.","html":"<p>scikit-learn ships dozens of models, from straight lines to forests of trees, and you use every one of them the same way. Learn three method calls and you can try any of them on the churn data in a few lines. That consistency is the main reason scikit-learn is the default library for classic machine learning.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Three calls</h2>\n<p>A model in scikit-learn is an <strong>estimator</strong>: a Python object you create with its settings, train with <code dir=\"ltr\">fit</code>, and use with <code dir=\"ltr\">predict</code> and <code dir=\"ltr\">score</code>.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Python</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"python\" data-index=\"0\" aria-label=\"Run this example\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.model_selection </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.tree </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> DecisionTreeClassifier</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">churn </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"churn.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">features </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"tenure_days\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"orders\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"total_spent\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"avg_order_value\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">            \"days_since_last_order\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"used_coupon\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"support_tickets\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"mobile_share\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X, y </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> churn[features], churn[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"churned\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X_train, X_test, y_train, y_test </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split(</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    X, y, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">test_size</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.25</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">stratify</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">y)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">model </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> DecisionTreeClassifier(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">max_depth</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># 1. create</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">model.fit(X_train, y_train)                                    </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># 2. learn</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.predict(X_test)[:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">10</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])                              </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># 3. use</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"train accuracy:\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">round</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.score(X_train, y_train), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"test accuracy: \"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">round</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.score(X_test, y_test), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))</span></span></code></pre><div class=\"run-output\" data-run-output=\"0\" hidden></div></div>\n<p>What each call does:</p>\n<ul>\n<li><strong>The constructor</strong> takes <strong>hyperparameters</strong>: choices you make before training. <code dir=\"ltr\">max_depth=3</code> says the tree may ask at most three questions in a row. <code dir=\"ltr\">random_state=42</code> makes tie-breaking repeatable.</li>\n<li><strong><code dir=\"ltr\">fit(X_train, y_train)</code></strong> looks at the examples and learns the model’s <strong>parameters</strong>. For a tree, those are the questions and thresholds (“is <code dir=\"ltr\">days_since_last_order</code> above 236.5?”). It returns the model itself, so <code dir=\"ltr\">model = DecisionTreeClassifier().fit(X, y)</code> also works.</li>\n<li><strong><code dir=\"ltr\">predict(X)</code></strong> returns one prediction per row: here an array of 0s and 1s.</li>\n<li><strong><code dir=\"ltr\">score(X, y)</code></strong> predicts and compares with the true answers. For classifiers it returns <strong>accuracy</strong>, the share of correct predictions. For regressors it returns R², which you’ll meet in section 2.</li>\n</ul>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 190\" role=\"img\" aria-labelledby=\"l-ml-1-3-t1\"><defs><marker id=\"arrow-l-ml-1-3-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-ml-1-3-t1\">An estimator is created with hyperparameters, fit on training data to learn parameters stored in attributes ending with an underscore, and then used to predict on new data or score against known answers.</title>\n  <rect class=\"d-box\" x=\"20\" y=\"60\" width=\"150\" height=\"64\" rx=\"12\"/>\n  <text class=\"d-code\" x=\"95\" y=\"88\" text-anchor=\"middle\">Model(max_depth=3)</text>\n  <text class=\"d-label-muted\" x=\"95\" y=\"110\" text-anchor=\"middle\">hyperparameters</text>\n  <path class=\"d-arrow\" d=\"M170 92 L250 92\" marker-end=\"url(#arrow-l-ml-1-3-1)\"/>\n  <text class=\"d-code\" x=\"210\" y=\"80\" text-anchor=\"middle\">fit</text>\n  <rect class=\"d-box-primary\" x=\"255\" y=\"60\" width=\"170\" height=\"64\" rx=\"12\"/>\n  <text class=\"d-label\" x=\"340\" y=\"88\" text-anchor=\"middle\">Fitted model</text>\n  <text class=\"d-code\" x=\"340\" y=\"110\" text-anchor=\"middle\">classes_, tree_ …</text>\n  <path class=\"d-arrow\" d=\"M425 80 L505 40\" marker-end=\"url(#arrow-l-ml-1-3-1)\"/>\n  <path class=\"d-arrow\" d=\"M425 104 L505 146\" marker-end=\"url(#arrow-l-ml-1-3-1)\"/>\n  <rect class=\"d-box-accent\" x=\"510\" y=\"16\" width=\"150\" height=\"48\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"585\" y=\"45\" text-anchor=\"middle\">predict(X)</text>\n  <rect class=\"d-box-success\" x=\"510\" y=\"122\" width=\"150\" height=\"48\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"585\" y=\"151\" text-anchor=\"middle\">score(X, y)</text>\n</svg><figcaption>The life of an estimator</figcaption></figure>\n<h2 id=\"sec-2\" tabindex=\"-1\">What a fitted model knows</h2>\n<p>Everything a model learns during <code dir=\"ltr\">fit</code> is stored in attributes whose names end with an underscore. They don’t exist before <code dir=\"ltr\">fit</code>; asking for one raises an <code dir=\"ltr\">AttributeError</code>, and calling <code dir=\"ltr\">predict</code> on an unfitted model raises <code dir=\"ltr\">NotFittedError</code>.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Python</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"python\" data-index=\"1\" aria-label=\"Run this example\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.model_selection </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.tree </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> DecisionTreeClassifier</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">churn </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"churn.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">features </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"tenure_days\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"orders\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"total_spent\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"avg_order_value\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">            \"days_since_last_order\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"used_coupon\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"support_tickets\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"mobile_share\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X_train, X_test, y_train, y_test </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split(</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    churn[features], churn[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"churned\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">], </span><span style=\"color:#953800;--shiki-dark:#FFA657\">test_size</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.25</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">    stratify</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">churn[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"churned\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">model </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> DecisionTreeClassifier(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">max_depth</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">).fit(X_train, y_train)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.classes_)            </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># the labels it saw: [0 1]</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.n_features_in_)      </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># 8</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.feature_names_in_[:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">new_customer </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.DataFrame([{</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"tenure_days\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">400</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"orders\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"total_spent\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">180.0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"avg_order_value\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">90.0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"days_since_last_order\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">150</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"used_coupon\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"support_tickets\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"mobile_share\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}])</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.predict(new_customer))        </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># [1]: likely to churn</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.predict_proba(new_customer))  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># [[0.36 0.64]]</span></span></code></pre><div class=\"run-output\" data-run-output=\"1\" hidden></div></div>\n<p><code dir=\"ltr\">predict_proba</code> gives the model’s estimated probability for each class, in the order of <code dir=\"ltr\">classes_</code>. This customer gets 64% for churn. You’ll lean on probabilities heavily in section 3, because they let you choose how cautious to be.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">The training score lies</h2>\n<p>Now remove the depth limit and watch what happens. An unlimited tree keeps asking questions until every training customer sits in a leaf with only their own class.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Python</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"python\" data-index=\"2\" aria-label=\"Run this example\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.model_selection </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.tree </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> DecisionTreeClassifier</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.neighbors </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> KNeighborsClassifier</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">churn </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"churn.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">features </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"tenure_days\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"orders\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"total_spent\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"avg_order_value\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">            \"days_since_last_order\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"used_coupon\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"support_tickets\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"mobile_share\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X_train, X_test, y_train, y_test </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split(</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    churn[features], churn[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"churned\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">], </span><span style=\"color:#953800;--shiki-dark:#FFA657\">test_size</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.25</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">    stratify</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">churn[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"churned\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> model </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [DecisionTreeClassifier(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">max_depth</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">),</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">              DecisionTreeClassifier(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">),</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">              KNeighborsClassifier(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">n_neighbors</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)]:</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    model.fit(X_train, y_train)</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">f</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">model</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">!r:55}</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> train </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">model.score(X_train, y_train)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:.2f}</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  test </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">model.score(X_test, y_test)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:.2f}</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span></code></pre><div class=\"run-output\" data-run-output=\"2\" hidden></div></div>\n<p>The unlimited tree is perfect on the 298 customers it studied and worse than the shallow tree on the 100 it didn’t. It memorised quirks of individual customers. This gap between training and test performance is <strong>overfitting</strong>, and you’ll spend much of section 2 learning to control it.</p>\n<p>Notice also the third model. k-nearest neighbours works nothing like a tree (it predicts by looking at the five most similar training customers), yet the code is identical. Swapping models costs one line.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">Same contract, different assumptions</h2>\n<p>The shared API hides very different ideas about the world. A tree assumes churn can be described by a handful of yes/no questions with sharp cut-offs. k-nearest neighbours assumes customers who look alike behave alike, where “look alike” means close together when every column is treated as a distance. Neither assumption is right; each is useful in some situations and wrong in others. That’s why you try several models on the same split rather than arguing about which one ought to win.</p>\n<p>Regression models keep the same contract. <code dir=\"ltr\">DecisionTreeRegressor</code> or <code dir=\"ltr\">LinearRegression</code> take a numeric <code dir=\"ltr\">y</code>, <code dir=\"ltr\">predict</code> returns numbers instead of classes, and <code dir=\"ltr\">score</code> returns R² instead of accuracy. Everything you learn about one estimator carries over to the rest.</p>\n<p>Two details save confusion later. Calling <code dir=\"ltr\">fit</code> a second time throws away what the model learned before and starts from scratch; it doesn’t add to the old knowledge. And the settings you passed to the constructor stay readable as plain attributes (<code dir=\"ltr\">model.max_depth</code>), so you can always check what a fitted model was told to do.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Feeding predict a differently shaped table</span></p>\n<p><code dir=\"ltr\">predict</code> needs the same columns, in the same order, as <code dir=\"ltr\">fit</code>. Pass a DataFrame with the columns shuffled and scikit-learn raises <code dir=\"ltr\">ValueError: The feature names should match those that were passed during fit</code>. Pass a bare NumPy array and it can’t check names at all: it warns and uses the columns by position, which silently gives wrong answers if your order differs. Build prediction inputs from the same <code dir=\"ltr\">features</code> list you trained with.</p>\n</aside>\n<p>You now have a model at 73% test accuracy. Is that good? You can’t say yet, because you haven’t asked what a model with no intelligence at all would score. That’s the next lesson.</p>\n","toc":[{"id":"sec-1","text":"Three calls","level":2},{"id":"sec-2","text":"What a fitted model knows","level":2},{"id":"sec-3","text":"The training score lies","level":2},{"id":"sec-4","text":"Same contract, different assumptions","level":2}],"takeaways":["Every scikit-learn estimator is created with its settings, learns in <code dir=\"ltr\">fit(X, y)</code>, and is used with <code dir=\"ltr\">predict(X)</code> and <code dir=\"ltr\">score(X, y)</code>.","Hyperparameters such as <code dir=\"ltr\">max_depth</code> are set by you before training; parameters such as split thresholds are learned during <code dir=\"ltr\">fit</code>.","Fitted attributes end with an underscore (<code dir=\"ltr\">classes_</code>, <code dir=\"ltr\">feature_names_in_</code>) and only exist after <code dir=\"ltr\">fit</code>.","<code dir=\"ltr\">score</code> returns accuracy for classifiers and R² for regressors.","A large gap between training and test scores means the model memorised its training rows."],"further":[{"title":"Getting started: fitting and predicting","url":"https://scikit-learn.org/stable/getting_started.html"},{"title":"DecisionTreeClassifier","url":"https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html"},{"title":"Glossary: estimator, fit, predict","url":"https://scikit-learn.org/stable/glossary.html"}],"quiz":[{"q":"<p>What does this print?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Python</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.tree </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> DecisionTreeClassifier</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">model </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> DecisionTreeClassifier(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">max_depth</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(model.classes_)</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">[0 1]</code>, the two churn classes.","why":"<code dir=\"ltr\">classes_</code> is learned from <code dir=\"ltr\">y</code> during <code dir=\"ltr\">fit</code>. This model has never seen any data."},{"text":"<code dir=\"ltr\">None</code>, because no classes have been set yet.","why":"scikit-learn doesn’t create fitted attributes as <code dir=\"ltr\">None</code>. They don’t exist until <code dir=\"ltr\">fit</code> runs."},{"text":"An <code dir=\"ltr\">AttributeError</code>, because <code dir=\"ltr\">classes_</code> only exists after <code dir=\"ltr\">fit</code>.","why":"Correct. The trailing underscore marks an attribute that <code dir=\"ltr\">fit</code> creates."}],"answer":2},{"q":"<p>A tree scores 1.00 on the training set and 0.72 on the test set. A depth-3 tree scores 0.78 and 0.73. Which is the better model for Cartwheel?</p>","options":[{"text":"The unlimited tree, because 1.00 shows it captured every pattern.","why":"A perfect training score on noisy data like churn means it memorised individual customers. Its test score is lower."},{"text":"The depth-3 tree, because it does at least as well on unseen customers and is far simpler.","why":"Correct. Judge on held-out data; when scores tie, prefer the model with fewer moving parts."},{"text":"They are equal, because their test scores differ by only 0.01.","why":"Test scores are close, but the depth-3 tree is easier to explain and less likely to swing on new data. That breaks the tie."}],"answer":1},{"q":"<p>Which value is a hyperparameter rather than a learned parameter?</p>","options":[{"text":"<code dir=\"ltr\">max_depth=3</code> passed to <code dir=\"ltr\">DecisionTreeClassifier</code>","why":"Correct. You choose it before training, and it limits how complex the learned tree can be."},{"text":"The threshold <code dir=\"ltr\">days_since_last_order &lt;= 236.5</code> at the root of a fitted tree","why":"That threshold is found by <code dir=\"ltr\">fit</code> from the data. It is a learned parameter."},{"text":"<code dir=\"ltr\">coef_</code> of a fitted <code dir=\"ltr\">LinearRegression</code>","why":"Coefficients are learned from the data, which is why they carry the trailing underscore."}],"answer":0},{"q":"<p>You fitted a model on a DataFrame with columns in one order, then call <code dir=\"ltr\">predict</code> on a DataFrame with the same columns in a different order. What happens?</p>","options":[{"text":"scikit-learn reorders the columns for you and predicts correctly.","why":"scikit-learn checks names but does not reorder. It refuses instead of guessing."},{"text":"It raises a <code dir=\"ltr\">ValueError</code> saying feature names must be in the same order as in fit.","why":"Correct. The check protects you from silently feeding <code dir=\"ltr\">orders</code> into the slot the model learned as <code dir=\"ltr\">tenure_days</code>."},{"text":"It predicts silently, using the columns by position.","why":"That is what happens with a NumPy array, which has no names. With a DataFrame, the name check catches the mismatch."}],"answer":1}],"exercise":{"kind":"python","files":["churn.csv"],"starter":"import pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.tree import DecisionTreeClassifier\n\nchurn = pd.read_csv(\"churn.csv\")\nfeatures = [\"tenure_days\", \"orders\", \"total_spent\", \"avg_order_value\",\n            \"days_since_last_order\", \"used_coupon\", \"support_tickets\", \"mobile_share\"]\nX_train, X_test, y_train, y_test = train_test_split(\n    churn[features], churn[\"churned\"], test_size=0.25, random_state=42,\n    stratify=churn[\"churned\"])\n\nnew_customer = pd.DataFrame([{\n    \"tenure_days\": 120, \"orders\": 6, \"total_spent\": 940.0, \"avg_order_value\": 156.7,\n    \"days_since_last_order\": 12, \"used_coupon\": 1, \"support_tickets\": 0,\n    \"mobile_share\": 0.8}])\n\n# 1. A tree limited to depth 3, and a tree with no depth limit (both random_state=42)\nshallow = DecisionTreeClassifier(max_depth=3, random_state=42)\ndeep = DecisionTreeClassifier(random_state=42)\n\n# 2. Fit both on the training data, then fill in the scores\nshallow_test = None\ndeep_train = None\ndeep_test = None\n\n# 3. The shallow tree's prediction (0 or 1) for new_customer\nnew_pred = None\n","solution":"import pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.tree import DecisionTreeClassifier\n\nchurn = pd.read_csv(\"churn.csv\")\nfeatures = [\"tenure_days\", \"orders\", \"total_spent\", \"avg_order_value\",\n            \"days_since_last_order\", \"used_coupon\", \"support_tickets\", \"mobile_share\"]\nX_train, X_test, y_train, y_test = train_test_split(\n    churn[features], churn[\"churned\"], test_size=0.25, random_state=42,\n    stratify=churn[\"churned\"])\n\nnew_customer = pd.DataFrame([{\n    \"tenure_days\": 120, \"orders\": 6, \"total_spent\": 940.0, \"avg_order_value\": 156.7,\n    \"days_since_last_order\": 12, \"used_coupon\": 1, \"support_tickets\": 0,\n    \"mobile_share\": 0.8}])\n\nshallow = DecisionTreeClassifier(max_depth=3, random_state=42).fit(X_train, y_train)\ndeep = DecisionTreeClassifier(random_state=42).fit(X_train, y_train)\n\nshallow_test = shallow.score(X_test, y_test)\ndeep_train = deep.score(X_train, y_train)\ndeep_test = deep.score(X_test, y_test)\n\nnew_pred = int(shallow.predict(new_customer)[0])\n\nprint(f\"shallow test {shallow_test:.2f} | deep train {deep_train:.2f}, test {deep_test:.2f}\")\n","checks":[{"id":"fitted","test":"hasattr(shallow, 'classes_') and hasattr(deep, 'classes_') and shallow.max_depth == 3 and deep.max_depth is None"},{"id":"shallow-test","test":"shallow_test is not None and abs(float(shallow_test) - 0.73) < 0.005"},{"id":"deep-scores","test":"deep_train is not None and float(deep_train) == 1.0 and abs(float(deep_test) - 0.72) < 0.005"},{"id":"prediction","test":"new_pred is not None and int(__import__('numpy').ravel(new_pred)[0]) == 0"}],"title":"Fit two trees and compare","prompt":"<p>Fit two decision trees on the churn training data and see memorisation in numbers.</p>\n<ol>\n<li>Fit <code dir=\"ltr\">shallow</code> (<code dir=\"ltr\">max_depth=3</code>) and <code dir=\"ltr\">deep</code> (no depth limit), both with <code dir=\"ltr\">random_state=42</code>.</li>\n<li>Set <code dir=\"ltr\">shallow_test</code> to the shallow tree’s test accuracy, and <code dir=\"ltr\">deep_train</code> / <code dir=\"ltr\">deep_test</code> to the deep tree’s training and test accuracy.</li>\n<li>Set <code dir=\"ltr\">new_pred</code> to the shallow tree’s prediction (0 or 1) for <code dir=\"ltr\">new_customer</code>.</li>\n</ol>\n","hints":["<code dir=\"ltr\">fit</code> returns the model, so <code dir=\"ltr\">DecisionTreeClassifier(...).fit(X_train, y_train)</code> works in one line.","<code dir=\"ltr\">model.score(X, y)</code> returns accuracy for a classifier.","<code dir=\"ltr\">predict</code> returns an array with one value per row; take element <code dir=\"ltr\">[0]</code> for the single new customer."],"explanation":"<p>The deep tree scores 1.00 on the customers it trained on and 0.72 on new ones; the depth-3 tree scores 0.73 on new ones with a fraction of the rules. The training score of a flexible model tells you almost nothing. The new customer ordered 12 days ago and has six orders, so the shallow tree predicts 0 (stays).</p>\n","checkLabels":{"fitted":"Both trees are fitted with the right depth settings","shallow-test":"shallow_test is the shallow tree’s test accuracy","deep-scores":"deep_train and deep_test are the deep tree’s scores","prediction":"new_pred is the shallow tree’s prediction for new_customer"}},"words":688,"readMinutes":3}