{"id":1165,"date":"2026-10-17T21:05:58","date_gmt":"2026-10-17T15:35:58","guid":{"rendered":"https:\/\/codeanddebug.in\/blog\/?p=1165"},"modified":"2026-10-20T13:50:33","modified_gmt":"2026-10-20T08:20:33","slug":"logistic-regression-in-machine-learning","status":"publish","type":"post","link":"https:\/\/codeanddebug.in\/blog\/logistic-regression-in-machine-learning\/","title":{"rendered":"Logistic Regression in Machine Learning: Explained Visually (with Python)"},"content":{"rendered":"\n<style>.cdai{--cd-brand:#3c3fde;--cd-brand-soft:#eceeff;--cd-ink:#14162b;--cd-muted:#5b5f7a;--cd-line:#dfe1ee;--cd-card:#ffffff;--cd-bg:#f6f7fc;--cd-good:#0f8a5f;--cd-good-soft:#e3f6ee;--cd-bad:#c2410c;--cd-bad-soft:#fdebe1;--cd-warn:#b7791f;--cd-on-brand:#ffffff;\nfont-family:Inter,system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif;color:var(--cd-ink);background:var(--cd-bg);border:1px solid var(--cd-line);border-radius:14px;padding:22px;margin:28px 0;line-height:1.55;font-size:16px;box-sizing:border-box;max-width:100%;overflow:hidden}\n.s-dark .cdai,.cdai.cd-dark{--cd-brand:#8d90ff;--cd-brand-soft:#23254a;--cd-ink:#e8e9f5;--cd-muted:#a3a6c2;--cd-line:#32354f;--cd-card:#1b1d33;--cd-bg:#14162a;--cd-good:#4ccf98;--cd-good-soft:#163a2c;--cd-bad:#ff9a6b;--cd-bad-soft:#3d2316;--cd-warn:#f2c46b;--cd-on-brand:#0f1030}\n.cdai *,.cdai *::before,.cdai *::after{box-sizing:border-box}\n.cdai h4.cd-h{font-family:Outfit,Inter,sans-serif;font-size:1.25rem;font-weight:700;margin:0 0 4px;color:var(--cd-ink);line-height:1.3}\n.cdai .cd-sub{color:var(--cd-muted);font-size:.95rem;margin:0 0 16px}\n.cdai .cd-tag{display:inline-block;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--cd-brand);background:var(--cd-brand-soft);padding:3px 9px;border-radius:99px;margin-bottom:10px}\n.cdai button.cd-btn,.cdai .cd-chip{font:inherit;font-size:.92rem;font-weight:600;cursor:pointer;border-radius:10px;border:1.5px solid var(--cd-line);background:var(--cd-card);color:var(--cd-ink);padding:9px 14px;line-height:1.3;transition:transform .15s ease,border-color .15s ease,background .15s ease;text-transform:none;letter-spacing:normal;box-shadow:none;margin:0;min-height:0;height:auto}\n.cdai button.cd-btn:hover,.cdai .cd-chip:hover{border-color:var(--cd-brand);transform:translateY(-1px)}\n.cdai button.cd-btn:focus-visible,.cdai .cd-chip:focus-visible,.cdai input:focus-visible{outline:3px solid var(--cd-brand);outline-offset:2px}\n.cdai .cd-primary,.cdai button.cd-primary{background:var(--cd-brand);border-color:var(--cd-brand);color:var(--cd-on-brand)}\n.cdai .cd-chip[aria-pressed=\"true\"]{background:var(--cd-brand);border-color:var(--cd-brand);color:var(--cd-on-brand)}\n.cdai .cd-row{display:flex;flex-wrap:wrap;gap:10px;align-items:center}\n.cdai .cd-grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,230px),1fr));gap:12px}\n.cdai .cd-card{background:var(--cd-card);border:1px solid var(--cd-line);border-radius:12px;padding:14px}\n.cdai .cd-stat{font-family:Outfit,Inter,sans-serif;font-size:2rem;font-weight:700;color:var(--cd-brand);line-height:1.1;font-variant-numeric:tabular-nums}\n.cdai .cd-small{font-size:.85rem;color:var(--cd-muted)}\n.cdai label.cd-lab{font-weight:600;font-size:.92rem;display:flex;justify-content:space-between;gap:10px;margin:14px 0 6px}\n.cdai input[type=range]{width:100%;accent-color:var(--cd-brand);margin:0;height:28px;background:transparent;border:0;padding:0}\n.cdai canvas{display:block;width:100%;height:auto;border-radius:10px;background:var(--cd-card);border:1px solid var(--cd-line);touch-action:pan-y}\n\/* hero *\/\n.cdai.cd-hero{padding:0;position:relative;background:#101233;border-color:#24275a}\n.cdai.cd-hero canvas{border:0;border-radius:0;background:transparent;height:200px}\n.cdai.cd-hero .cd-hero-txt{position:absolute;left:0;right:0;bottom:0;padding:16px 20px;background:linear-gradient(transparent,rgba(16,18,51,.92) 55%);color:#fff}\n.cdai.cd-hero .cd-hero-txt b{font-family:Outfit,Inter,sans-serif;font-size:1.15rem}\n.cdai.cd-hero .cd-hero-txt span{display:block;color:#c9cbff;font-size:.9rem}\n\/* planner *\/\n.cdai .cd-timeline{display:flex;flex-direction:column;gap:7px;margin-top:6px}\n.cdai .cd-tl-row{display:grid;grid-template-columns:minmax(0,150px) 1fr 62px;gap:10px;align-items:center;font-size:.88rem}\n.cdai .cd-tl-name{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.cdai .cd-tl-name a{color:inherit;text-decoration:none}\n.cdai .cd-tl-name a:hover{color:var(--cd-brand)}\n.cdai .cd-tl-track{height:14px;background:var(--cd-brand-soft);border-radius:99px;overflow:hidden}\n.cdai .cd-tl-bar{height:100%;background:var(--cd-brand);border-radius:99px;width:0;transition:width .6s cubic-bezier(.2,.8,.2,1)}\n.cdai .cd-tl-bar.cd-skim{background:repeating-linear-gradient(45deg,var(--cd-brand),var(--cd-brand) 6px,transparent 6px,transparent 10px)}\n.cdai .cd-tl-w{text-align:right;font-variant-numeric:tabular-nums;color:var(--cd-muted)}\n.cdai .cd-prog{height:10px;border-radius:99px;background:var(--cd-brand-soft);overflow:hidden;margin-top:8px}\n.cdai .cd-prog i{display:block;height:100%;background:var(--cd-good);width:0;transition:width .4s ease}\n@media (max-width:520px){.cdai{padding:16px}.cdai .cd-tl-row{grid-template-columns:minmax(0,110px) 1fr 50px;font-size:.8rem}}\n\/* game *\/\n.cdai .cd-game-card{background:var(--cd-card);border:1px solid var(--cd-line);border-radius:12px;padding:18px;min-height:96px;font-size:1.05rem;font-weight:600;display:flex;align-items:center}\n.cdai .cd-feedback{margin-top:12px;padding:12px 14px;border-radius:10px;font-size:.93rem}\n.cdai .cd-feedback.cd-ok{background:var(--cd-good-soft);color:var(--cd-ink);border-left:4px solid var(--cd-good)}\n.cdai .cd-feedback.cd-no{background:var(--cd-bad-soft);color:var(--cd-ink);border-left:4px solid var(--cd-bad)}\n.cdai .cd-venn{position:relative;width:min(100%,300px);aspect-ratio:1\/1;margin:6px auto 0}\n.cdai .cd-venn div{position:absolute;border-radius:50%;border:2px solid var(--cd-brand);display:flex;justify-content:center;font-weight:700;font-size:.8rem;color:var(--cd-ink);padding-top:6px;transition:background .3s ease,transform .3s ease}\n.cdai .cd-venn div.cd-lit{background:var(--cd-brand-soft);transform:scale(1.03)}\n.cdai .cd-v1{inset:0}.cdai .cd-v2{inset:12%}.cdai .cd-v3{inset:26%}.cdai .cd-v4{inset:40%;align-items:center;padding-top:0!important}\n\/* checklist *\/\n.cdai.cd-check{padding:16px 18px;background:var(--cd-card)}\n.cdai.cd-check ul{list-style:none;margin:8px 0 0;padding:0}\n.cdai.cd-check li{margin:0;padding:0}\n.cdai.cd-check label{display:flex;gap:10px;align-items:flex-start;padding:7px 4px;cursor:pointer;font-size:.95rem;border-radius:8px}\n.cdai.cd-check label:hover{background:var(--cd-bg)}\n.cdai.cd-check input{width:18px;height:18px;margin-top:3px;accent-color:var(--cd-good);flex:none}\n.cdai.cd-check .cd-done{color:var(--cd-good);font-weight:700}\n\/* tokens *\/\n.cdai .cd-bars{display:flex;flex-direction:column;gap:6px;margin-top:10px}\n.cdai .cd-bar-row{display:grid;grid-template-columns:110px 1fr 52px;gap:10px;align-items:center;font-size:.9rem}\n.cdai .cd-bar-row b{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-weight:600}\n.cdai .cd-bar-row .cd-tl-bar{transition:width .35s ease}\n.cdai .cd-out{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;background:var(--cd-card);border:1px solid var(--cd-line);border-radius:10px;padding:12px;margin-top:12px;min-height:46px;font-size:.92rem;word-break:break-word}\n.cdai .cd-out mark{background:var(--cd-brand-soft);color:var(--cd-brand);padding:1px 4px;border-radius:4px;animation:cdpop .4s ease}\n@keyframes cdpop{from{transform:scale(1.4);opacity:0}to{transform:none;opacity:1}}\n.cdai .cd-meter{font-family:Outfit,Inter,sans-serif;font-weight:700;font-size:1.6rem;font-variant-numeric:tabular-nums}\n@media (prefers-reduced-motion:reduce){.cdai *{transition:none!important;animation:none!important}}\n.cdai .cd-tbl-wrap{overflow-x:auto;margin-top:10px}\n.cdai table.cd-tbl{border-collapse:collapse;width:100%;font-size:.88rem;font-variant-numeric:tabular-nums;background:var(--cd-card);margin:0}\n.cdai table.cd-tbl th,.cdai table.cd-tbl td{border:1px solid var(--cd-line);padding:6px 8px;text-align:center;color:var(--cd-ink)}\n.cdai table.cd-tbl th{background:var(--cd-brand-soft);font-weight:700;font-size:.8rem}\n.cdai table.cd-tbl input{width:64px;font:inherit;padding:4px 6px;border:1.5px solid var(--cd-line);border-radius:6px;background:var(--cd-bg);color:var(--cd-ink);text-align:center;margin:0}\n.cdai .cd-steps{margin-top:12px;display:grid;gap:6px;font-size:.92rem}\n.cdai .cd-steps div{background:var(--cd-card);border:1px solid var(--cd-line);border-radius:8px;padding:8px 12px}\n.cdai .cd-steps code,.cdai .cd-eq{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.9rem;background:transparent;color:var(--cd-ink);padding:0}\n.cdai .cd-eq{display:inline-block;background:var(--cd-brand-soft);color:var(--cd-brand);padding:4px 10px;border-radius:8px;font-weight:700}\n.cdai.cd-codebox{padding:0;background:#16182c;border-color:#2a2d48}\n.cdai.cd-codebox .cd-codehead{display:flex;justify-content:space-between;align-items:center;padding:8px 14px;border-bottom:1px solid #2a2d48;color:#a3a6c2;font-size:.8rem;font-weight:600}\n.cdai.cd-codebox pre{margin:0;padding:14px 16px;overflow-x:auto;background:transparent;border:0;color:#e6e7f2;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86rem;line-height:1.6;white-space:pre}\n.cdai.cd-codebox pre code{background:transparent;color:inherit;padding:0;font:inherit}\n.cdai.cd-codebox .cd-copy{font:inherit;font-size:.78rem;font-weight:600;cursor:pointer;background:#2a2d48;color:#e6e7f2;border:0;border-radius:6px;padding:5px 10px;margin:0;text-transform:none;letter-spacing:normal}\n.cdai.cd-codebox .cd-outp{border-top:1px dashed #2a2d48;color:#8fe3b8}\n.cdai .cd-legend{display:flex;flex-wrap:wrap;gap:14px;font-size:.82rem;color:var(--cd-muted);margin-top:8px}\n.cdai .cd-legend i{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:5px;vertical-align:middle}\n.cdai canvas.cd-touch{touch-action:none;cursor:crosshair}\n.cdai canvas.cd-grab{touch-action:none;cursor:grab}\n.cdai .cd-q-opts{display:grid;gap:8px;margin-top:12px}\n.cdai .cd-q-opts button.cd-btn{text-align:left;width:100%}\n.cdai .cd-q-opts button.cd-right{border-color:var(--cd-good);background:var(--cd-good-soft)}\n.cdai .cd-q-opts button.cd-wrong{border-color:var(--cd-bad);background:var(--cd-bad-soft)}\n.cdai .cd-odds-dots{display:grid;grid-template-columns:repeat(10,1fr);gap:6px;max-width:320px;margin-top:10px}\n.cdai .cd-odds-dots i{display:block;aspect-ratio:1\/1;border-radius:50%;background:var(--cd-line);transition:background .25s ease}\n.cdai .cd-cm{display:grid;grid-template-columns:auto 1fr 1fr;gap:6px;font-size:.88rem;max-width:420px;margin-top:12px}\n.cdai .cd-cm div{padding:10px 8px;border-radius:8px;text-align:center}\n.cdai .cd-cm .cd-cm-h{color:var(--cd-muted);font-weight:600;font-size:.78rem;align-self:center}\n.cdai .cd-cm .cd-cm-c{background:var(--cd-card);border:1px solid var(--cd-line)}\n.cdai .cd-cm .cd-cm-c b{display:block;font-family:Outfit,Inter,sans-serif;font-size:1.5rem;font-variant-numeric:tabular-nums}\n.cdai .cd-cm .cd-cm-good{border-color:var(--cd-good);background:var(--cd-good-soft)}\n.cdai .cd-cm .cd-cm-bad{border-color:var(--cd-bad);background:var(--cd-bad-soft)}\n<\/style>\n\n\n\n<p class=\"wp-block-paragraph\">Is this email spam? Will this customer repay the loan? Does this scan show a tumour? Will a student pass the exam? Questions with a yes or no answer are everywhere, and logistic regression is the first algorithm most data scientists reach for to answer them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide explains logistic regression in machine learning from the ground up, with something to play with in every section. You will bend the sigmoid curve yourself, convert probabilities into odds, draw a decision boundary by adding points, tune a spam filter&#8217;s threshold, and watch the model train. If you have not read our <a href=\"https:\/\/codeanddebug.in\/blog\/linear-regression-in-machine-learning\/\">linear regression guide<\/a> yet, it helps, but it is not required.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-what\">What is logistic regression in machine learning?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Logistic regression is a supervised machine learning algorithm used for classification. It looks at the input features, calculates the probability that an example belongs to a class, and then picks the class based on that probability. For a student who studied 6 hours, it might say &#8220;82% chance of passing&#8221;, and since 82% is above 50%, it predicts pass.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some everyday uses:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Spam detection: spam or not spam<\/li>\n\n\n<li>Credit risk: will a borrower default or repay<\/li>\n\n\n<li>Medical diagnosis: is a tumour malignant or benign<\/li>\n\n\n<li>Marketing: will a user click the ad or buy the product<\/li>\n\n\n<li>HR analytics: will an employee leave in the next year<\/li>\n\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"cd-classification\">Is logistic regression classification or regression?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Classification. The final output is a class label, like pass or fail. Under the hood, though, it does predict a number, the probability of the class, and the probability is what makes it so useful: you know how sure the model is, not only what it chose.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"cd-why-regression\">Why is it called regression?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Because the core of the model is a linear regression. It computes a weighted sum of the features, exactly like linear regression does, and then passes that sum through the logistic (sigmoid) function to turn it into a probability. Statisticians named it after that structure long before machine learning existed, and the name stuck.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-sigmoid\">The sigmoid function<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A plain straight line can produce any number, like 1.44 or \u22120.3, which makes no sense as a probability. The sigmoid function, also called the logistic function, fixes that by squashing any number into the range 0 to 1:<\/p>\n\n\n\n<div class=\"cdai\" style=\"padding:16px;display:grid;gap:10px;justify-items:center\"><span class=\"cd-eq\">\u03c3(z) = 1 \/ (1 + e<sup>\u2212z<\/sup>)<\/span><span class=\"cd-small\">z is the weighted sum: z = w \u00d7 x + b<\/span><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">When z is a large positive number, \u03c3(z) gets close to 1. When z is very negative, it gets close to 0. When z is exactly 0, the output is exactly 0.5. Plotted on a graph, it makes the famous S-shaped curve.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Below, the dots are 16 students: green passed, dark failed. Move the weight and bias to fit the S-curve to the data. The weight controls how steep the curve is, and the bias slides it left or right. Your goal is the lowest log loss, which we explain later.<\/p>\n\n\n\n<div class=\"cdai cd-lg-sig\"><span class=\"cd-tag\">Try it<\/span><h4 class=\"cd-h\">Fit the sigmoid curve yourself<\/h4><p class=\"cd-sub\">Hours studied vs passing the exam.<\/p><canvas><\/canvas>\n<div class=\"cd-grid2\"><div><label class=\"cd-lab\"><span>Weight w (steepness)<\/span><span class=\"cd-sig-wv\"><\/span><\/label><input type=\"range\" class=\"cd-sig-w\" min=\"0\" max=\"3\" step=\"0.01\" value=\"0.4\" aria-label=\"Weight\"><\/div>\n<div><label class=\"cd-lab\"><span>Bias b (shift)<\/span><span class=\"cd-sig-bv\"><\/span><\/label><input type=\"range\" class=\"cd-sig-b\" min=\"-12\" max=\"2\" step=\"0.01\" value=\"-1\" aria-label=\"Bias\"><\/div><\/div>\n<div class=\"cd-card\" style=\"margin-top:12px\"><div class=\"cd-row\" style=\"justify-content:space-between\"><span class=\"cd-eq cd-sig-eq\" style=\"font-size:.82rem\"><\/span><span><span class=\"cd-small\">Log loss <\/span><b class=\"cd-meter cd-sig-loss\" style=\"font-size:1.3rem\"><\/b><\/span><\/div><\/div>\n<div class=\"cd-row\" style=\"margin-top:12px\"><button type=\"button\" class=\"cd-btn cd-primary cd-sig-fit\">Let the model fit it<\/button><button type=\"button\" class=\"cd-btn cd-sig-reset\">Reset<\/button><\/div>\n<p class=\"cd-small cd-sig-msg\" style=\"margin:10px 0 0\"><\/p><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-formula\">Logistic regression formula and equation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With one feature, the logistic regression model is:<\/p>\n\n\n\n<div class=\"cdai\" style=\"padding:16px;display:grid;gap:10px;justify-items:center\"><span class=\"cd-eq\">p = 1 \/ (1 + e<sup>\u2212(b + w \u00d7 x)<\/sup>)<\/span><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">With many features, the weighted sum simply gets longer:<\/p>\n\n\n\n<div class=\"cdai\" style=\"padding:16px;display:grid;gap:10px;justify-items:center\"><span class=\"cd-eq\">p = 1 \/ (1 + e<sup>\u2212(b\u2080 + b\u2081x\u2081 + b\u2082x\u2082 + \u2026 + b\u2099x\u2099)<\/sup>)<\/span><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Here p is the probability of the positive class (pass, spam, default), the b values are the coefficients the model learns, and the x values are your features.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"cd-odds\">Odds, log-odds and the logit<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">There is a second way to write the same model that explains what the coefficients mean. First, <strong>odds<\/strong> compare the chance of something happening to the chance of it not happening:<\/p>\n\n\n\n<div class=\"cdai\" style=\"padding:16px;display:grid;gap:10px;justify-items:center\"><span class=\"cd-eq\">odds = p \/ (1 \u2212 p)<\/span><span class=\"cd-eq\">log-odds = ln( p \/ (1 \u2212 p) ) = b\u2080 + b\u2081x\u2081 + \u2026 + b\u2099x\u2099<\/span><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The second line is the key insight: logistic regression is a linear model for the log-odds. The log-odds function is also called the <strong>logit<\/strong>. Drag the slider to see how the three quantities relate.<\/p>\n\n\n\n<div class=\"cdai cd-lg-odds\"><span class=\"cd-tag\">Try it<\/span><h4 class=\"cd-h\">Probability, odds and log-odds converter<\/h4><p class=\"cd-sub\">Each dot is one student out of 20 similar students.<\/p><label class=\"cd-lab\"><span>Probability of passing<\/span><span class=\"cd-odds-pv\"><\/span><\/label><input type=\"range\" class=\"cd-odds-p\" min=\"1\" max=\"99\" step=\"1\" value=\"80\" aria-label=\"Probability\">\n<div class=\"cd-grid2\" style=\"margin-top:12px;grid-template-columns:repeat(auto-fit,minmax(140px,1fr))\"><div class=\"cd-card\"><div class=\"cd-small\">Odds of passing<\/div><div class=\"cd-meter cd-odds-o\"><\/div><\/div><div class=\"cd-card\"><div class=\"cd-small\">Log-odds (logit)<\/div><div class=\"cd-meter cd-odds-l\"><\/div><\/div><\/div>\n<div class=\"cd-odds-dots\" aria-hidden=\"true\"><\/div>\n<canvas style=\"margin-top:12px;border:0;background:transparent\"><\/canvas>\n<p class=\"cd-small cd-odds-msg\" style=\"margin:6px 0 0\"><\/p><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This is how you read a coefficient: increasing a feature by 1 adds its coefficient to the log-odds, which multiplies the odds by e<sup>coefficient<\/sup>. This number is called the <strong>odds ratio<\/strong>. In our Python example below the model learns w = 0.892 for hours studied, and e<sup>0.892<\/sup> \u2248 2.44. So every extra hour of study multiplies a student&#8217;s odds of passing by about 2.4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-boundary\">Decision boundary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Once the model outputs a probability, it needs a rule to choose a class. The default rule is simple: predict 1 if p \u2265 0.5, otherwise predict 0. Since p = 0.5 exactly when the weighted sum is 0, the dividing line between the classes is where b\u2080 + b\u2081x\u2081 + b\u2082x\u2082 = 0. With two features that is a straight line, called the <strong>decision boundary<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Below, each dot is a student described by two features: hours studied and attendance. The model is trained live in your browser. Click on the chart to add a student and watch it retrain and the boundary move. Ringed dots are students the model gets wrong.<\/p>\n\n\n\n<div class=\"cdai cd-lg-2d\"><span class=\"cd-tag\">Try it<\/span><h4 class=\"cd-h\">Draw the decision boundary<\/h4><p class=\"cd-sub\">Pick a class, then click on the chart to add students.<\/p><div class=\"cd-row\" role=\"group\" aria-label=\"Class to add\"><button type=\"button\" class=\"cd-chip\" data-c=\"1\" aria-pressed=\"true\">Add a pass<\/button><button type=\"button\" class=\"cd-chip\" data-c=\"0\" aria-pressed=\"false\">Add a fail<\/button><button type=\"button\" class=\"cd-btn cd-2d-reset\">Reset data<\/button><\/div>\n<canvas class=\"cd-touch\" style=\"margin-top:12px\"><\/canvas>\n<div class=\"cd-legend\"><span><i style=\"background:var(--cd-good)\"><\/i>Passed<\/span><span><i style=\"background:var(--cd-bad)\"><\/i>Failed<\/span><span>Shaded area shows what the model predicts<\/span><\/div>\n<label class=\"cd-lab\"><span>Decision threshold<\/span><span class=\"cd-2d-thr\"><\/span><\/label><input type=\"range\" class=\"cd-2d-t\" min=\"5\" max=\"95\" step=\"1\" value=\"50\" aria-label=\"Threshold\">\n<div class=\"cd-row\" style=\"justify-content:space-between;margin-top:8px\"><span class=\"cd-small\">Students classified correctly<\/span><b class=\"cd-meter cd-2d-acc\" style=\"font-size:1.3rem\"><\/b><\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Notice that the boundary is always a straight line. That is why logistic regression is called a linear classifier. If the real boundary between classes is curved, you need extra features, like squares of the inputs, or a different model.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-threshold\">Choosing the threshold: precision vs recall<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A threshold of 0.5 is only a default. In real projects you choose it based on which mistake costs more. Missing a cancer case is far worse than a false alarm, so a screening model uses a low threshold. A spam filter that sends your job offer to spam is worse than letting one spam email through, so it uses a high threshold.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Below are 20 emails with the spam probability a logistic regression model gave each one. Move the threshold and watch the four outcomes change. This 2 \u00d7 2 table is called a <strong>confusion matrix<\/strong>.<\/p>\n\n\n\n<div class=\"cdai cd-lg-thr\"><span class=\"cd-tag\">Try it<\/span><h4 class=\"cd-h\">Tune a spam filter<\/h4><p class=\"cd-sub\">Red dots are real spam, green dots are genuine emails.<\/p><canvas><\/canvas>\n<label class=\"cd-lab\"><span>Threshold<\/span><span class=\"cd-thr-tv\"><\/span><\/label><input type=\"range\" class=\"cd-thr-t\" min=\"5\" max=\"95\" step=\"1\" value=\"50\" aria-label=\"Threshold\">\n<div class=\"cd-grid2\" style=\"margin-top:6px;align-items:start\">\n<div class=\"cd-cm\"><div><\/div><div class=\"cd-cm-h\">Actually spam<\/div><div class=\"cd-cm-h\">Actually genuine<\/div>\n<div class=\"cd-cm-h\">Flagged as spam<\/div><div class=\"cd-cm-c cd-cm-good\"><b class=\"cd-cm-tp\"><\/b>True positive<\/div><div class=\"cd-cm-c cd-cm-bad\"><b class=\"cd-cm-fp\"><\/b>False positive<\/div>\n<div class=\"cd-cm-h\">Let through<\/div><div class=\"cd-cm-c cd-cm-bad\"><b class=\"cd-cm-fn\"><\/b>False negative<\/div><div class=\"cd-cm-c cd-cm-good\"><b class=\"cd-cm-tn\"><\/b>True negative<\/div><\/div>\n<div class=\"cd-card\" style=\"display:grid;gap:8px\"><div class=\"cd-row\" style=\"justify-content:space-between\"><span class=\"cd-small\">Accuracy<\/span><b class=\"cd-thr-acc\"><\/b><\/div><div class=\"cd-row\" style=\"justify-content:space-between\"><span class=\"cd-small\">Precision (flagged that were really spam)<\/span><b class=\"cd-thr-prec\"><\/b><\/div><div class=\"cd-row\" style=\"justify-content:space-between\"><span class=\"cd-small\">Recall (spam that got caught)<\/span><b class=\"cd-thr-rec\"><\/b><\/div><\/div>\n<\/div>\n<p class=\"cd-small cd-thr-msg\" style=\"margin:10px 0 0\"><\/p><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-cost\">Cost function: log loss<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Linear regression measures error with mean squared error. Logistic regression cannot, because squared error combined with the sigmoid creates a bumpy error surface with many local minimums, and gradient descent can get stuck. Instead it uses <strong>log loss<\/strong>, also called binary cross-entropy:<\/p>\n\n\n\n<div class=\"cdai\" style=\"padding:16px;display:grid;gap:10px;justify-items:center\"><span class=\"cd-eq\">Log loss = \u2212(1\/n) \u00d7 \u03a3 [ y \u00d7 ln(p) + (1 \u2212 y) \u00d7 ln(1 \u2212 p) ]<\/span><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">It looks complicated, but only one half is active for each example. If the true label is 1, the penalty is \u2212ln(p). If the true label is 0, it is \u2212ln(1 \u2212 p). Try it below and compare it with squared error, shown as the dashed line.<\/p>\n\n\n\n<div class=\"cdai cd-lg-loss\"><span class=\"cd-tag\">Try it<\/span><h4 class=\"cd-h\">How log loss punishes mistakes<\/h4><p class=\"cd-sub\">Choose the true label, then change the model&#8217;s prediction.<\/p><div class=\"cd-row\" role=\"group\" aria-label=\"True label\"><button type=\"button\" class=\"cd-chip\" data-a=\"1\" aria-pressed=\"true\">True label: 1 (pass)<\/button><button type=\"button\" class=\"cd-chip\" data-a=\"0\" aria-pressed=\"false\">True label: 0 (fail)<\/button><\/div>\n<canvas style=\"margin-top:12px\"><\/canvas>\n<label class=\"cd-lab\"><span>Model&#8217;s predicted probability of class 1<\/span><span class=\"cd-loss-pv\"><\/span><\/label><input type=\"range\" class=\"cd-loss-p\" min=\"1\" max=\"99\" step=\"1\" value=\"70\" aria-label=\"Predicted probability\">\n<div class=\"cd-grid2\" style=\"margin-top:10px;grid-template-columns:repeat(auto-fit,minmax(140px,1fr))\"><div class=\"cd-card\"><div class=\"cd-small\">Log loss (solid line)<\/div><div class=\"cd-meter cd-loss-ll\"><\/div><\/div><div class=\"cd-card\"><div class=\"cd-small\">Squared error (dashed)<\/div><div class=\"cd-meter cd-loss-se\"><\/div><\/div><\/div>\n<p class=\"cd-small cd-loss-msg\" style=\"margin:10px 0 0\"><\/p><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Being confident and wrong is extremely expensive under log loss. That pressure is exactly what pushes the model towards honest, well-calibrated probabilities.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-training\">How logistic regression learns: maximum likelihood and gradient descent<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Training means finding the weights that make the observed data most likely. This idea is called <strong>maximum likelihood estimation (MLE)<\/strong>, and minimising log loss is the same thing as maximising likelihood. There is no neat formula for the answer like there is for linear regression, so the weights are found step by step with gradient descent. The update rule is surprisingly simple:<\/p>\n\n\n\n<div class=\"cdai\" style=\"padding:16px;display:grid;gap:10px;justify-items:center\"><span class=\"cd-eq\">w = w \u2212 learning rate \u00d7 mean( (p \u2212 y) \u00d7 x )<\/span><span class=\"cd-eq\">b = b \u2212 learning rate \u00d7 mean( p \u2212 y )<\/span><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Press Run and watch a flat 50% line bend into the S-curve as the log loss falls.<\/p>\n\n\n\n<div class=\"cdai cd-lg-train\"><span class=\"cd-tag\">Try it<\/span><h4 class=\"cd-h\">Watch logistic regression train<\/h4><p class=\"cd-sub\">Left: the model&#8217;s curve. Right: log loss falling over time.<\/p><div class=\"cd-grid2\"><canvas><\/canvas><canvas><\/canvas><\/div>\n<label class=\"cd-lab\"><span>Learning rate<\/span><span class=\"cd-tr-lrv\">0.10<\/span><\/label><input type=\"range\" class=\"cd-tr-lr\" min=\"0.01\" max=\"1\" step=\"0.01\" value=\"0.1\" aria-label=\"Learning rate\">\n<div class=\"cd-row\" style=\"margin-top:10px\"><button type=\"button\" class=\"cd-btn cd-primary cd-tr-run\">Run<\/button><button type=\"button\" class=\"cd-btn cd-tr-one\">One step<\/button><button type=\"button\" class=\"cd-btn cd-tr-reset\">Reset<\/button><\/div>\n<div class=\"cd-grid2\" style=\"margin-top:12px;grid-template-columns:repeat(auto-fit,minmax(110px,1fr))\"><div class=\"cd-card\"><div class=\"cd-small\">weight w<\/div><div class=\"cd-meter cd-tr-w\"><\/div><\/div><div class=\"cd-card\"><div class=\"cd-small\">bias b<\/div><div class=\"cd-meter cd-tr-b\"><\/div><\/div><div class=\"cd-card\"><div class=\"cd-small\">log loss<\/div><div class=\"cd-meter cd-tr-l\"><\/div><\/div><div class=\"cd-card\"><div class=\"cd-small\">steps<\/div><div class=\"cd-meter cd-tr-n\"><\/div><\/div><\/div>\n<p class=\"cd-small cd-tr-msg\" style=\"margin:10px 0 0\"><\/p><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-types\">Types of logistic regression<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>Binary logistic regression:<\/strong> two classes, like spam or not spam. This is what most of this guide covers.<\/li>\n\n\n<li><strong>Multinomial logistic regression:<\/strong> three or more classes with no natural order, like classifying news into sports, politics or tech. It is also called nominal or softmax regression.<\/li>\n\n\n<li><strong>Ordinal logistic regression:<\/strong> three or more classes that do have an order, like movie ratings from 1 to 5 or survey answers from &#8220;disagree&#8221; to &#8220;agree&#8221;.<\/li>\n\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Multinomial logistic regression computes one score per class and uses the <strong>softmax<\/strong> function to turn the scores into probabilities that add up to 1. Here a model is predicting which course track a student will choose:<\/p>\n\n\n\n<div class=\"cdai cd-lg-soft\"><span class=\"cd-tag\">Try it<\/span><h4 class=\"cd-h\">Softmax: from scores to probabilities<\/h4><p class=\"cd-sub\">Change each class&#8217;s score and watch the probabilities rebalance.<\/p><div class=\"cd-grid2\" style=\"grid-template-columns:repeat(auto-fit,minmax(160px,1fr))\">\n<div><label class=\"cd-lab\"><span>Score: DSA<\/span><span class=\"cd-sm-z0\"><\/span><\/label><input type=\"range\" min=\"-3\" max=\"5\" step=\"0.1\" value=\"1.2\" aria-label=\"DSA score\"><\/div>\n<div><label class=\"cd-lab\"><span>Score: Web dev<\/span><span class=\"cd-sm-z1\"><\/span><\/label><input type=\"range\" min=\"-3\" max=\"5\" step=\"0.1\" value=\"0.4\" aria-label=\"Web development score\"><\/div>\n<div><label class=\"cd-lab\"><span>Score: AI and ML<\/span><span class=\"cd-sm-z2\"><\/span><\/label><input type=\"range\" min=\"-3\" max=\"5\" step=\"0.1\" value=\"2.1\" aria-label=\"AI and ML score\"><\/div><\/div>\n<div class=\"cd-bars\"><\/div><p class=\"cd-small cd-sm-msg\" style=\"margin:10px 0 0\"><\/p><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-assumptions\">Assumptions of logistic regression<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Logistic regression needs fewer assumptions than <a href=\"https:\/\/codeanddebug.in\/blog\/linear-regression-in-machine-learning\/\">linear regression<\/a>. It does not need normally distributed errors or equal variance. It does need these:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li><strong>The right kind of target:<\/strong> binary for binary logistic regression, categories for multinomial, ordered categories for ordinal.<\/li>\n\n\n<li><strong>Independent observations:<\/strong> one row should not influence another, so no repeated measurements of the same person treated as separate people.<\/li>\n\n\n<li><strong>Little multicollinearity:<\/strong> features should not be strongly correlated with each other, or the coefficients become unstable.<\/li>\n\n\n<li><strong>Linear relationship with the log-odds:<\/strong> each continuous feature should relate roughly linearly to the log-odds of the outcome.<\/li>\n\n\n<li><strong>Enough data:<\/strong> a common rule of thumb is at least 10 examples of the rarer class for every feature.<\/li>\n\n\n<li><strong>No extreme outliers<\/strong> in the features, since they can pull the boundary off course.<\/li>\n\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-vs-linear\">Linear regression vs logistic regression<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These two get compared all the time because their names and formulas look so similar. Our <a href=\"https:\/\/codeanddebug.in\/blog\/linear-regression-in-machine-learning\/\">linear regression guide<\/a> has a demo showing a straight line predicting a 144% chance of passing, which is exactly the problem logistic regression solves. Here is the full comparison:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th><\/th><th>Linear regression<\/th><th>Logistic regression<\/th><\/tr><\/thead><tbody><tr><td>Problem type<\/td><td>Regression<\/td><td>Classification<\/td><\/tr><tr><td>Output<\/td><td>Any real number<\/td><td>Probability between 0 and 1, then a class<\/td><\/tr><tr><td>Curve<\/td><td>Straight line<\/td><td>S-shaped sigmoid<\/td><\/tr><tr><td>Core equation<\/td><td>y = b\u2080 + b\u2081x\u2081 + \u2026 + b\u2099x\u2099<\/td><td>log-odds = b\u2080 + b\u2081x\u2081 + \u2026 + b\u2099x\u2099<\/td><\/tr><tr><td>Loss function<\/td><td>Mean squared error<\/td><td>Log loss (cross-entropy)<\/td><\/tr><tr><td>How it is solved<\/td><td>Exact formula or gradient descent<\/td><td>Gradient descent (maximum likelihood)<\/td><\/tr><tr><td>Evaluation<\/td><td>MAE, RMSE, R\u00b2<\/td><td>Accuracy, precision, recall, F1, ROC-AUC<\/td><\/tr><tr><td>Example<\/td><td>Predict a flat&#8217;s price<\/td><td>Predict if a loan will default<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-python\">Logistic regression in Python with scikit-learn<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You need NumPy and scikit-learn (<code>pip install numpy scikit-learn<\/code>). Every output below comes from actually running the code.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Simple example: will the student pass?<\/h3>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"import numpy as np\nfrom sklearn.linear_model import LogisticRegression\n\n# Hours studied and whether the student passed (1) or failed (0)\nhours = np.array([0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5,\n                  5.5, 6, 6.5, 7, 8, 9.5]).reshape(-1, 1)\npassed = np.array([0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1])\n\nmodel = LogisticRegression()\nmodel.fit(hours, passed)\n\nprint(&quot;Weight (w):&quot;, round(model.coef_[0][0], 3))\nprint(&quot;Bias (b):&quot;, round(model.intercept_[0], 3))\n\nfor h in [2, 4.5, 7]:\n    p = model.predict_proba([[h]])[0][1]\n    print(f&quot;{h} hours -&gt; {p:.0%} chance of passing -&gt; predicted class {model.predict([[h]])[0]}&quot;)\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> numpy <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> np<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> sklearn.linear_model <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> LogisticRegression<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\"># Hours studied and whether the student passed (1) or failed (0)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">hours = np.array([<\/span><span style=\"color: #B5CEA8\">0.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">2.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">3.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">4<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">4.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">5<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                  <\/span><span style=\"color: #B5CEA8\">5.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">6<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">6.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">7<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">8<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">9.5<\/span><span style=\"color: #D4D4D4\">]).reshape(-<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">passed = np.array([<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">])<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">model = LogisticRegression()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">model.fit(hours, passed)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Weight (w):&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">round<\/span><span style=\"color: #D4D4D4\">(model.coef_[<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">][<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">], <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Bias (b):&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">round<\/span><span style=\"color: #D4D4D4\">(model.intercept_[<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">], <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> h <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> [<\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">4.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">7<\/span><span style=\"color: #D4D4D4\">]:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    p = model.predict_proba([[h]])[<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">][<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">f<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #569CD6\">{<\/span><span style=\"color: #D4D4D4\">h<\/span><span style=\"color: #569CD6\">}<\/span><span style=\"color: #CE9178\"> hours -&gt; <\/span><span style=\"color: #569CD6\">{<\/span><span style=\"color: #D4D4D4\">p<\/span><span style=\"color: #569CD6\">:.0%}<\/span><span style=\"color: #CE9178\"> chance of passing -&gt; predicted class <\/span><span style=\"color: #569CD6\">{<\/span><span style=\"color: #D4D4D4\">model.predict([[h]])[<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">]<\/span><span style=\"color: #569CD6\">}<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Output:<\/strong><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">Weight (w): 0.892<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Bias (b): -3.814<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">2 hours -&gt; 12% chance of passing -&gt; predicted class 0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">4.5 hours -&gt; 55% chance of passing -&gt; predicted class 1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">7 hours -&gt; 92% chance of passing -&gt; predicted class 1<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><code>predict_proba<\/code> gives the probability of each class, and <code>predict<\/code> applies the 0.5 threshold for you. To use a different threshold, take the probabilities and compare them yourself, for example <code>(model.predict_proba(X)[:, 1] &gt;= 0.3)<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Real dataset: breast cancer classification<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">scikit-learn ships with a real medical dataset of 569 tumours, each described by 30 measurements. Scaling the features first helps the solver converge.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"from sklearn.datasets import load_breast_cancer\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import accuracy_score, confusion_matrix, classification_report\n\n# 569 tumour samples, 30 measurements each. Target: 0 = malignant, 1 = benign\nX, y = load_breast_cancer(return_X_y=True)\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.2, random_state=42, stratify=y)\n\n# Scale the features, then fit logistic regression\nmodel = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))\nmodel.fit(X_train, y_train)\npred = model.predict(X_test)\n\nprint(&quot;Accuracy:&quot;, round(accuracy_score(y_test, pred), 3))\nprint(&quot;Confusion matrix:&quot;)\nprint(confusion_matrix(y_test, pred))\nprint(classification_report(y_test, pred, target_names=[&quot;malignant&quot;, &quot;benign&quot;]))\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> sklearn.datasets <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> load_breast_cancer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> sklearn.model_selection <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> train_test_split<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> sklearn.pipeline <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> make_pipeline<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> sklearn.preprocessing <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> StandardScaler<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> sklearn.linear_model <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> LogisticRegression<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> sklearn.metrics <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> accuracy_score, confusion_matrix, classification_report<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\"># 569 tumour samples, 30 measurements each. Target: 0 = malignant, 1 = benign<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">X, y = load_breast_cancer(<\/span><span style=\"color: #9CDCFE\">return_X_y<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #569CD6\">True<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">X_train, X_test, y_train, y_test = train_test_split(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    X, y, <\/span><span style=\"color: #9CDCFE\">test_size<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #B5CEA8\">0.2<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">random_state<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #B5CEA8\">42<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">stratify<\/span><span style=\"color: #D4D4D4\">=y)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\"># Scale the features, then fit logistic regression<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">model = make_pipeline(StandardScaler(), LogisticRegression(<\/span><span style=\"color: #9CDCFE\">max_iter<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #B5CEA8\">1000<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">model.fit(X_train, y_train)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">pred = model.predict(X_test)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Accuracy:&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">round<\/span><span style=\"color: #D4D4D4\">(accuracy_score(y_test, pred), <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Confusion matrix:&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(confusion_matrix(y_test, pred))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(classification_report(y_test, pred, <\/span><span style=\"color: #9CDCFE\">target_names<\/span><span style=\"color: #D4D4D4\">=[<\/span><span style=\"color: #CE9178\">&quot;malignant&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;benign&quot;<\/span><span style=\"color: #D4D4D4\">]))<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Output:<\/strong><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">Accuracy: 0.982<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Confusion matrix:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">[[41  1]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> [ 1 71]]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">              precision    recall  f1-score   support<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"><\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   malignant       0.98      0.98      0.98        42<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      benign       0.99      0.99      0.99        72<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"><\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    accuracy                           0.98       114<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   macro avg       0.98      0.98      0.98       114<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">weighted avg       0.98      0.98      0.98       114<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The model gets 98% of the test tumours right, misclassifying only 2 out of 114. In the confusion matrix, rows are the true classes and columns are the predicted ones, so the top-right 1 is a malignant tumour predicted as benign. In a real medical project that is the most dangerous mistake, and you would lower the threshold to push it towards zero.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Logistic regression from scratch with NumPy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is the same gradient descent you watched in the training demo:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"import numpy as np\n\nx = np.array([0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5,\n              5.5, 6, 6.5, 7, 8, 9.5])\ny = np.array([0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1])\n\ndef sigmoid(z):\n    return 1 \/ (1 + np.exp(-z))\n\nw, b = 0.0, 0.0\nlr = 0.1\n\nfor step in range(20000):\n    p = sigmoid(w * x + b)          # predicted probabilities\n    dw = np.mean((p - y) * x)       # gradient of log loss for w\n    db = np.mean(p - y)             # gradient of log loss for b\n    w -= lr * dw\n    b -= lr * db\n\nloss = -np.mean(y * np.log(p) + (1 - y) * np.log(1 - p))\nprint(&quot;w =&quot;, round(w, 3), &quot; b =&quot;, round(b, 3), &quot; log loss =&quot;, round(loss, 3))\nprint(&quot;Hours needed for a 50% chance:&quot;, round(-b \/ w, 2))\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> numpy <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> np<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">x = np.array([<\/span><span style=\"color: #B5CEA8\">0.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">2.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">3.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">4<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">4.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">5<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">              <\/span><span style=\"color: #B5CEA8\">5.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">6<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">6.5<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">7<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">8<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">9.5<\/span><span style=\"color: #D4D4D4\">])<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">y = np.array([<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">])<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">sigmoid<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">z<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\"> \/ (<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\"> + np.exp(-z))<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">w, b = <\/span><span style=\"color: #B5CEA8\">0.0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">0.0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">lr = <\/span><span style=\"color: #B5CEA8\">0.1<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> step <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">range<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">20000<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    p = sigmoid(w * x + b)          <\/span><span style=\"color: #6A9955\"># predicted probabilities<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    dw = np.mean((p - y) * x)       <\/span><span style=\"color: #6A9955\"># gradient of log loss for w<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    db = np.mean(p - y)             <\/span><span style=\"color: #6A9955\"># gradient of log loss for b<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    w -= lr * dw<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    b -= lr * db<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">loss = -np.mean(y * np.log(p) + (<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\"> - y) * np.log(<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\"> - p))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;w =&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">round<\/span><span style=\"color: #D4D4D4\">(w, <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #CE9178\">&quot; b =&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">round<\/span><span style=\"color: #D4D4D4\">(b, <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #CE9178\">&quot; log loss =&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">round<\/span><span style=\"color: #D4D4D4\">(loss, <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Hours needed for a 50<\/span><span style=\"color: #569CD6\">% c<\/span><span style=\"color: #CE9178\">hance:&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">round<\/span><span style=\"color: #D4D4D4\">(-b \/ w, <\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Output:<\/strong><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">w = 1.087  b = -4.632  log loss = 0.353<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Hours needed for a 50% chance: 4.26<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The weights differ from the scikit-learn example (1.087 here vs 0.892 there) because scikit-learn adds <strong>L2 regularisation<\/strong> by default (the <code>C=1.0<\/code> parameter), which gently shrinks weights to reduce overfitting. Set <code>LogisticRegression(C=1e9)<\/code> to switch it off and you get 1.087 and \u22124.633, exactly matching the NumPy version.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-pros-cons\">Advantages and limitations<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>Gives probabilities,<\/strong> not just labels, so you can set your own threshold and rank cases by risk.<\/li>\n\n\n<li><strong>Easy to interpret.<\/strong> Each coefficient converts into an odds ratio that a manager or doctor can understand.<\/li>\n\n\n<li><strong>Fast and light.<\/strong> It trains in seconds on millions of rows and is a strong baseline for any classification problem.<\/li>\n\n\n<li><strong>Only draws straight boundaries<\/strong> unless you engineer extra features.<\/li>\n\n\n<li><strong>Struggles with highly correlated features<\/strong> and needs care with imbalanced classes, for example using <code>class_weight=\"balanced\"<\/code>.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-quiz\">Test yourself<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Six questions. Five or more correct and you are ready to use logistic regression on a real problem.<\/p>\n\n\n\n<div class=\"cdai cd-lg-quiz\"><span class=\"cd-tag\">Quiz<\/span><h4 class=\"cd-h\">Logistic regression quiz<\/h4><div class=\"cd-lgq-body\"><p class=\"cd-sub\">Takes about two minutes.<\/p><button type=\"button\" class=\"cd-btn cd-primary cd-lgq-start\">Start the quiz<\/button><\/div><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-faq\">Frequently asked questions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Is logistic regression supervised or unsupervised learning?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Supervised. It learns from examples where the correct class is already known, such as emails already labelled as spam or not spam.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Is logistic regression a classification or regression algorithm?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">It is a classification algorithm. It predicts the probability of a class and then assigns the class using a threshold, usually 0.5.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why is logistic regression called regression if it does classification?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Because its core is a linear regression on the log-odds of the outcome. The logistic (sigmoid) function then converts that value into a probability. The name comes from statistics and predates its use as a classifier.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is the sigmoid function in logistic regression?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The sigmoid function \u03c3(z) = 1 \/ (1 + e^\u2212z) maps any real number to a value between 0 and 1. Logistic regression applies it to the weighted sum of features so the output can be read as a probability.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is the cost function of logistic regression?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Log loss, also called binary cross-entropy: \u2212(1\/n) \u03a3 [y ln(p) + (1 \u2212 y) ln(1 \u2212 p)]. It heavily penalises confident wrong predictions and gives a convex error surface that gradient descent can minimise reliably.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is the difference between linear and logistic regression?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Linear regression predicts a continuous number with a straight line and minimises squared error. Logistic regression predicts the probability of a class with an S-shaped sigmoid curve and minimises log loss.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can logistic regression handle more than two classes?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. Multinomial logistic regression uses the softmax function to handle three or more unordered classes, and ordinal logistic regression handles ordered classes such as ratings.<\/p>\n\n\n\n<script type=\"application\/ld+json\">{\"@context\": \"https:\/\/schema.org\", \"@type\": \"FAQPage\", \"mainEntity\": [{\"@type\": \"Question\", \"name\": \"Is logistic regression supervised or unsupervised learning?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Supervised. It learns from examples where the correct class is already known, such as emails already labelled as spam or not spam.\"}}, {\"@type\": \"Question\", \"name\": \"Is logistic regression a classification or regression algorithm?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"It is a classification algorithm. It predicts the probability of a class and then assigns the class using a threshold, usually 0.5.\"}}, {\"@type\": \"Question\", \"name\": \"Why is logistic regression called regression if it does classification?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Because its core is a linear regression on the log-odds of the outcome. The logistic (sigmoid) function then converts that value into a probability. The name comes from statistics and predates its use as a classifier.\"}}, {\"@type\": \"Question\", \"name\": \"What is the sigmoid function in logistic regression?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"The sigmoid function \u03c3(z) = 1 \/ (1 + e^\u2212z) maps any real number to a value between 0 and 1. Logistic regression applies it to the weighted sum of features so the output can be read as a probability.\"}}, {\"@type\": \"Question\", \"name\": \"What is the cost function of logistic regression?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Log loss, also called binary cross-entropy: \u2212(1\/n) \u03a3 [y ln(p) + (1 \u2212 y) ln(1 \u2212 p)]. It heavily penalises confident wrong predictions and gives a convex error surface that gradient descent can minimise reliably.\"}}, {\"@type\": \"Question\", \"name\": \"What is the difference between linear and logistic regression?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Linear regression predicts a continuous number with a straight line and minimises squared error. Logistic regression predicts the probability of a class with an S-shaped sigmoid curve and minimises log loss.\"}}, {\"@type\": \"Question\", \"name\": \"Can logistic regression handle more than two classes?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Yes. Multinomial logistic regression uses the softmax function to handle three or more unordered classes, and ordinal logistic regression handles ordered classes such as ratings.\"}}]}<\/script>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cd-next\">What to learn next<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You now know how to build a classifier and why the threshold matters. The natural next topics are the confusion matrix and its metrics in more depth, then decision trees and random forests, which can draw curved boundaries. Our <a href=\"https:\/\/codeanddebug.in\/blog\/how-to-learn-ai-ml-from-scratch-roadmap\/\">interactive AI and ML roadmap<\/a> shows where each of these fits, and the <a href=\"https:\/\/codeanddebug.in\/blog\/linear-regression-in-machine-learning\/\">linear regression guide<\/a> covers the regression side.<\/p>\n\n\n\n<script src=\"data:text\/javascript;charset=utf-8;base64,KGZ1bmN0aW9uKCl7CiJ1c2Ugc3RyaWN0IjsKdmFyIFJNPXdpbmRvdy5tYXRjaE1lZGlhJiZ3aW5kb3cubWF0Y2hNZWRpYSgiKHByZWZlcnMtcmVkdWNlZC1tb3Rpb246IHJlZHVjZSkiKS5tYXRjaGVzOwpmdW5jdGlvbiAkKHMscil7cmV0dXJuIChyfHxkb2N1bWVudCkucXVlcnlTZWxlY3RvcihzKX0KZnVuY3Rpb24gJCQocyxyKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoKHJ8fGRvY3VtZW50KS5xdWVyeVNlbGVjdG9yQWxsKHMpKX0KZnVuY3Rpb24gY3NzKGVsLG4pe3JldHVybiBnZXRDb21wdXRlZFN0eWxlKGVsKS5nZXRQcm9wZXJ0eVZhbHVlKG4pLnRyaW0oKX0KZnVuY3Rpb24gY2FudmFzRm9yKGN2LGgpe3ZhciBkcHI9TWF0aC5taW4od2luZG93LmRldmljZVBpeGVsUmF0aW98fDEsMiksdz1jdi5jbGllbnRXaWR0aHx8NjAwO2N2LndpZHRoPXcqZHByO2N2LmhlaWdodD1oKmRwcjtjdi5zdHlsZS5oZWlnaHQ9aCsicHgiO3ZhciBjPWN2LmdldENvbnRleHQoIjJkIik7Yy5zZXRUcmFuc2Zvcm0oZHByLDAsMCxkcHIsMCwwKTtyZXR1cm4ge2M6Yyx3OncsaDpofX0KZnVuY3Rpb24gY29sb3JzKGVsKXtyZXR1cm4ge2luazpjc3MoZWwsIi0tY2QtaW5rIiksbXV0OmNzcyhlbCwiLS1jZC1tdXRlZCIpLGxpbmU6Y3NzKGVsLCItLWNkLWxpbmUiKSxicjpjc3MoZWwsIi0tY2QtYnJhbmQiKSxiYWQ6Y3NzKGVsLCItLWNkLWJhZCIpLGdvb2Q6Y3NzKGVsLCItLWNkLWdvb2QiKSxjYXJkOmNzcyhlbCwiLS1jZC1jYXJkIil9fQpmdW5jdGlvbiBmMSh2LGQpe3JldHVybiAoTWF0aC5yb3VuZCh2Kk1hdGgucG93KDEwLGQpKS9NYXRoLnBvdygxMCxkKSkudG9GaXhlZChkKX0KZnVuY3Rpb24gc2lnKHope3JldHVybiAxLygxK01hdGguZXhwKC16KSl9CmZ1bmN0aW9uIHJuZyhzZWVkKXt2YXIgcz1zZWVkO3JldHVybiBmdW5jdGlvbigpe3M9KHMqMTY2NDUyNSsxMDEzOTA0MjIzKSU0Mjk0OTY3Mjk2O3JldHVybiBzLzQyOTQ5NjcyOTZ9fQpmdW5jdGlvbiBnYXVzcyhyKXt2YXIgdT0wLHY9MDt3aGlsZSh1PT09MCl1PXIoKTt3aGlsZSh2PT09MCl2PXIoKTtyZXR1cm4gTWF0aC5zcXJ0KC0yKk1hdGgubG9nKHUpKSpNYXRoLmNvcygyKk1hdGguUEkqdil9CmZ1bmN0aW9uIGdyaWQoYyxTLG8pe2Muc3Ryb2tlU3R5bGU9by5jb2wubGluZTtjLmxpbmVXaWR0aD0xO2MuZm9udD0iMTFweCBJbnRlcixzYW5zLXNlcmlmIjtjLmZpbGxTdHlsZT1vLmNvbC5tdXQ7CiBvLnh0LmZvckVhY2goZnVuY3Rpb24odil7dmFyIHg9by5zeCh2KTtjLmdsb2JhbEFscGhhPS42O2MuYmVnaW5QYXRoKCk7Yy5tb3ZlVG8oeCxvLlQpO2MubGluZVRvKHgsUy5oLW8uQik7Yy5zdHJva2UoKTtjLmdsb2JhbEFscGhhPTE7Yy5maWxsVGV4dCh2LHgtNSxTLmgtby5CKzE0KX0pOwogby55dC5mb3JFYWNoKGZ1bmN0aW9uKHYpe3ZhciB5PW8uc3kodik7Yy5nbG9iYWxBbHBoYT0uNjtjLmJlZ2luUGF0aCgpO2MubW92ZVRvKG8uTCx5KTtjLmxpbmVUbyhTLnctby5SLHkpO2Muc3Ryb2tlKCk7Yy5nbG9iYWxBbHBoYT0xO2MuZmlsbFRleHQodiw0LHkrNCl9KTsKIGlmKG8ueGwpYy5maWxsVGV4dChvLnhsLFMudy1vLlItYy5tZWFzdXJlVGV4dChvLnhsKS53aWR0aCxTLmgtMyk7aWYoby55bCljLmZpbGxUZXh0KG8ueWwsby5MKzQsby5ULTUpfQp2YXIgSD1bMC41LDEsMS41LDIsMi41LDMsMy41LDQsNC41LDUsNS41LDYsNi41LDcsOCw5LjVdLFk9WzAsMCwwLDAsMCwxLDAsMCwxLDEsMCwxLDEsMSwxLDFdLFdCPVsxLjA4NywtNC42MzNdOwpmdW5jdGlvbiBsb2dsb3NzKHcsYil7dmFyIHM9MDtmb3IodmFyIGk9MDtpPEgubGVuZ3RoO2krKyl7dmFyIHA9TWF0aC5taW4oMS0xZS0xMixNYXRoLm1heCgxZS0xMixzaWcodypIW2ldK2IpKSk7cys9LShZW2ldKk1hdGgubG9nKHApKygxLVlbaV0pKk1hdGgubG9nKDEtcCkpfXJldHVybiBzL0gubGVuZ3RofQpmdW5jdGlvbiBjdXJ2ZShjLG8sdyxiLHhtYXgpe2MuYmVnaW5QYXRoKCk7Zm9yKHZhciB4PTA7eDw9eG1heDt4Kz0wLjA1KXt2YXIgeT1vLnN5KHNpZyh3KngrYikpO3g9PT0wP2MubW92ZVRvKG8uc3goeCkseSk6Yy5saW5lVG8oby5zeCh4KSx5KX1jLnN0cm9rZSgpfQoKLyogMS4gU2lnbW9pZCBleHBsb3JlciAqLwokJCgiLmNkYWkuY2QtbGctc2lnIikuZm9yRWFjaChmdW5jdGlvbihib3gpewogdmFyIGN2PSQoImNhbnZhcyIsYm94KSxTLHc9MC40LGI9LTEsYW5pbT1udWxsLGNvbCxvOwogZnVuY3Rpb24gZHJhdygpe2lmKCFTKXtTPWNhbnZhc0ZvcihjdiwyNzApO289e0w6MzQsUjoxMixUOjIwLEI6Mjh9fWNvbD1jb2xvcnMoYm94KTtvLmNvbD1jb2w7dmFyIGM9Uy5jOwogIG8uc3g9ZnVuY3Rpb24odil7cmV0dXJuIG8uTCt2LzEwKihTLnctby5MLW8uUil9O28uc3k9ZnVuY3Rpb24odil7cmV0dXJuIFMuaC1vLkItdiooUy5oLW8uVC1vLkIpfTtvLnh0PVswLDIsNCw2LDgsMTBdO28ueXQ9WzAsMC41LDFdO28ueGw9ImhvdXJzIHN0dWRpZWQiO28ueWw9InByb2JhYmlsaXR5IG9mIHBhc3NpbmciOwogIGMuY2xlYXJSZWN0KDAsMCxTLncsUy5oKTtncmlkKGMsUyxvKTsKICB2YXIgbWlkPS1iL3c7aWYodz4wJiZtaWQ+MCYmbWlkPDEwKXtjLnN0cm9rZVN0eWxlPWNvbC5tdXQ7Yy5zZXRMaW5lRGFzaChbNCw0XSk7Yy5iZWdpblBhdGgoKTtjLm1vdmVUbyhvLnN4KG1pZCksby5UKTtjLmxpbmVUbyhvLnN4KG1pZCksUy5oLW8uQik7Yy5zdHJva2UoKTtjLnNldExpbmVEYXNoKFtdKTtjLmZpbGxTdHlsZT1jb2wubXV0O2MuZmlsbFRleHQoIjUwJSBhdCAiK2YxKG1pZCwxKSsiIGhycyIsby5zeChtaWQpKzUsby5UKzEyKX0KICBjLnN0cm9rZVN0eWxlPWNvbC5icjtjLmxpbmVXaWR0aD0zO2N1cnZlKGMsbyx3LGIsMTApO2MubGluZVdpZHRoPTE7CiAgSC5mb3JFYWNoKGZ1bmN0aW9uKGgsaSl7Yy5maWxsU3R5bGU9WVtpXT9jb2wuZ29vZDpjb2wuaW5rO2MuYmVnaW5QYXRoKCk7Yy5hcmMoby5zeChoKSxvLnN5KFlbaV0pLDUuNSwwLDcpO2MuZmlsbCgpfSk7CiAgJCgiLmNkLXNpZy13Iixib3gpLnZhbHVlPXc7JCgiLmNkLXNpZy1iIixib3gpLnZhbHVlPWI7JCgiLmNkLXNpZy13diIsYm94KS50ZXh0Q29udGVudD1mMSh3LDIpOyQoIi5jZC1zaWctYnYiLGJveCkudGV4dENvbnRlbnQ9ZjEoYiwyKTsKICB2YXIgTD1sb2dsb3NzKHcsYik7JCgiLmNkLXNpZy1sb3NzIixib3gpLnRleHRDb250ZW50PWYxKEwsMyk7CiAgJCgiLmNkLXNpZy1lcSIsYm94KS50ZXh0Q29udGVudD0icCA9IDEgLyAoMSArIGVe4oiSKCIrZjEodywyKSsiIMOXIGhvdXJzICIrKGI8MD8i4oiSICI6IisgIikrZjEoTWF0aC5hYnMoYiksMikrIikpIjsKICAkKCIuY2Qtc2lnLW1zZyIsYm94KS50ZXh0Q29udGVudD1MPDAuMzY\/IlRoYXQgaXMgdGhlIGJlc3QgZml0LiBUaGUgY3VydmUgaHVncyB0aGUgcGFzc2VzIGF0IHRoZSB0b3AgYW5kIHRoZSBmYWlscyBhdCB0aGUgYm90dG9tLiI6dzwwLjM\/IldlaWdodCBpcyBzbWFsbCwgc28gdGhlIGN1cnZlIGlzIGFsbW9zdCBmbGF0LiBFdmVyeSBzdHVkZW50IGdldHMgYSBzaW1pbGFyIHByb2JhYmlsaXR5LiI6dz4yLjI\/IldlaWdodCBpcyB2ZXJ5IGxhcmdlLCBzbyB0aGUgY3VydmUgYmVjb21lcyBhIHNoYXJwIHN0ZXAuIFRoZSBtb2RlbCBpcyBvdmVyY29uZmlkZW50LiI6Ik1vdmUgdGhlIHNsaWRlcnMgdG8gbG93ZXIgdGhlIGxvZyBsb3NzLCBvciBsZXQgdGhlIG1vZGVsIGZpdCBpdC4ifQogJCgiLmNkLXNpZy13Iixib3gpLmFkZEV2ZW50TGlzdGVuZXIoImlucHV0IixmdW5jdGlvbihlKXt3PStlLnRhcmdldC52YWx1ZTtkcmF3KCl9KTsKICQoIi5jZC1zaWctYiIsYm94KS5hZGRFdmVudExpc3RlbmVyKCJpbnB1dCIsZnVuY3Rpb24oZSl7Yj0rZS50YXJnZXQudmFsdWU7ZHJhdygpfSk7CiAkKCIuY2Qtc2lnLWZpdCIsYm94KS5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsZnVuY3Rpb24oKXtjYW5jZWxBbmltYXRpb25GcmFtZShhbmltKTt2YXIgdzA9dyxiMD1iLHQ9MDsoZnVuY3Rpb24gZ28oKXt0Kz1STT8xOjAuMDM7dmFyIGs9MS1NYXRoLnBvdygxLU1hdGgubWluKHQsMSksMyk7dz13MCsoV0JbMF0tdzApKms7Yj1iMCsoV0JbMV0tYjApKms7ZHJhdygpO2lmKHQ8MSlhbmltPXJlcXVlc3RBbmltYXRpb25GcmFtZShnbyl9KSgpfSk7CiAkKCIuY2Qtc2lnLXJlc2V0Iixib3gpLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixmdW5jdGlvbigpe2NhbmNlbEFuaW1hdGlvbkZyYW1lKGFuaW0pO3c9MC40O2I9LTE7ZHJhdygpfSk7CiB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigicmVzaXplIixmdW5jdGlvbigpe1M9bnVsbDtkcmF3KCl9KTtkcmF3KCk7Cn0pOwoKLyogMi4gT2RkcyBjb252ZXJ0ZXIgKi8KJCQoIi5jZGFpLmNkLWxnLW9kZHMiKS5mb3JFYWNoKGZ1bmN0aW9uKGJveCl7CiB2YXIgaW5wPSQoIi5jZC1vZGRzLXAiLGJveCksZG90cz0kKCIuY2Qtb2Rkcy1kb3RzIixib3gpLGN2PSQoImNhbnZhcyIsYm94KSxTLGNvbDsKIGRvdHMuaW5uZXJIVE1MPUFycmF5LmFwcGx5KG51bGwsQXJyYXkoMjApKS5tYXAoZnVuY3Rpb24oKXtyZXR1cm4gJzxpPjwvaT4nfSkuam9pbigiIik7CiBmdW5jdGlvbiBkcmF3KCl7dmFyIHA9K2lucC52YWx1ZS8xMDAsb2Rkcz1wLygxLXApLGxvPU1hdGgubG9nKG9kZHMpO2NvbD1jb2xvcnMoYm94KTsKICAkKCIuY2Qtb2Rkcy1wdiIsYm94KS50ZXh0Q29udGVudD1NYXRoLnJvdW5kKHAqMTAwKSsiJSI7CiAgJCgiLmNkLW9kZHMtbyIsYm94KS50ZXh0Q29udGVudD1vZGRzPj0xP2YxKG9kZHMsMikrIiB0byAxIjoiMSB0byAiK2YxKDEvb2RkcywyKTsKICAkKCIuY2Qtb2Rkcy1sIixib3gpLnRleHRDb250ZW50PWYxKGxvLDIpOwogIHZhciBrPU1hdGgucm91bmQocCoyMCk7JCQoImkiLGRvdHMpLmZvckVhY2goZnVuY3Rpb24oZCxpKXtkLnN0eWxlLmJhY2tncm91bmQ9aTxrP2NvbC5nb29kOmNvbC5saW5lfSk7CiAgJCgiLmNkLW9kZHMtbXNnIixib3gpLnRleHRDb250ZW50PU1hdGgucm91bmQocCoxMDApPT09NTA\/IjUwJSBtZWFucyBvZGRzIG9mIDEgdG8gMSBhbmQgbG9nLW9kZHMgb2YgZXhhY3RseSAwLiBUaGlzIGlzIHRoZSBkZWNpc2lvbiBwb2ludC4iOnA+MC41PyJPdXQgb2YgZXZlcnkgMjAgc2ltaWxhciBzdHVkZW50cywgYWJvdXQgIitrKyIgcGFzcyBhbmQgIisoMjAtaykrIiBmYWlsLiBPZGRzIGFib3ZlIDEgZ2l2ZSBwb3NpdGl2ZSBsb2ctb2Rkcy4iOiJGZXdlciBwYXNzZXMgdGhhbiBmYWlscywgc28gdGhlIG9kZHMgYXJlIGJlbG93IDEgYW5kIHRoZSBsb2ctb2RkcyB0dXJuIG5lZ2F0aXZlLiI7CiAgaWYoIVMpUz1jYW52YXNGb3IoY3YsNzApO3ZhciBjPVMuYyxMPTE2LFI9MTY7Yy5jbGVhclJlY3QoMCwwLFMudyxTLmgpO2Z1bmN0aW9uIHN4KHYpe3JldHVybiBMKyh2KzUpLzEwKihTLnctTC1SKX0KICBjLnN0cm9rZVN0eWxlPWNvbC5tdXQ7Yy5saW5lV2lkdGg9MS41O2MuYmVnaW5QYXRoKCk7Yy5tb3ZlVG8oc3goLTUpLDM0KTtjLmxpbmVUbyhzeCg1KSwzNCk7Yy5zdHJva2UoKTtjLmZpbGxTdHlsZT1jb2wubXV0O2MuZm9udD0iMTFweCBJbnRlcixzYW5zLXNlcmlmIjsKICBbLTQsLTIsMCwyLDRdLmZvckVhY2goZnVuY3Rpb24odil7Yy5iZWdpblBhdGgoKTtjLm1vdmVUbyhzeCh2KSwyOSk7Yy5saW5lVG8oc3godiksMzkpO2Muc3Ryb2tlKCk7Yy5maWxsVGV4dCh2LHN4KHYpLSh2PDA\/NjozKSw1NCl9KTtjLmZpbGxUZXh0KCJsb2ctb2RkcyAod2hhdCB0aGUgbGluZWFyIHBhcnQgcHJlZGljdHMpIixMLDE0KTsKICBjLmZpbGxTdHlsZT1jb2wuYnI7Yy5iZWdpblBhdGgoKTtjLmFyYyhzeChNYXRoLm1heCgtNSxNYXRoLm1pbig1LGxvKSkpLDM0LDgsMCw3KTtjLmZpbGwoKX0KIGlucC5hZGRFdmVudExpc3RlbmVyKCJpbnB1dCIsZHJhdyk7d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoInJlc2l6ZSIsZnVuY3Rpb24oKXtTPW51bGw7ZHJhdygpfSk7ZHJhdygpOwp9KTsKCi8qIDMuIERlY2lzaW9uIGJvdW5kYXJ5IDJEICovCiQkKCIuY2RhaS5jZC1sZy0yZCIpLmZvckVhY2goZnVuY3Rpb24oYm94KXsKIHZhciBjdj0kKCJjYW52YXMiLGJveCksUyxjb2wscj1ybmcoMTEpLHB0cz1bXSxhZGRDbHM9MSx0aHI9MC41LFc9WzAsMCwwXTsKIGZvcih2YXIgaT0wO2k8MzY7aSsrKXt2YXIgaHg9cigpKjEwLGF0PTQ1K3IoKSo1NSx6PTAuOSooaHgtNSkrMC4wOSooYXQtNzIpK2dhdXNzKHIpKjEuMTtwdHMucHVzaChbaHgsYXQsej4wPzE6MF0pfQogZnVuY3Rpb24gbngocCl7cmV0dXJuIFsocFswXS01KS8zLChwWzFdLTcyKS8xNl19CiBmdW5jdGlvbiB0cmFpbigpe1c9WzAsMCwwXTtmb3IodmFyIGl0PTA7aXQ8MjUwMDtpdCsrKXt2YXIgZz1bMCwwLDBdO3B0cy5mb3JFYWNoKGZ1bmN0aW9uKHApe3ZhciB2PW54KHApLGU9c2lnKFdbMF0qdlswXStXWzFdKnZbMV0rV1syXSktcFsyXTtnWzBdKz1lKnZbMF07Z1sxXSs9ZSp2WzFdO2dbMl0rPWV9KTtmb3IodmFyIGs9MDtrPDM7aysrKVdba10tPTAuNSooZ1trXS9wdHMubGVuZ3RoKzAuMDAyKihrPDI\/V1trXTowKSl9fQogZnVuY3Rpb24gcHJvYihoLGEpe3ZhciB2PW54KFtoLGFdKTtyZXR1cm4gc2lnKFdbMF0qdlswXStXWzFdKnZbMV0rV1syXSl9CiB2YXIgTD0zOCxSPTEwLFQ9MTQsQj0yODtmdW5jdGlvbiBzeCh2KXtyZXR1cm4gTCt2LzEwKihTLnctTC1SKX1mdW5jdGlvbiBzeSh2KXtyZXR1cm4gUy5oLUItKHYtNDApLzYwKihTLmgtVC1CKX1mdW5jdGlvbiBpeChweCl7cmV0dXJuIChweC1MKS8oUy53LUwtUikqMTB9ZnVuY3Rpb24gaXkocHkpe3JldHVybiA0MCsoUy5oLUItcHkpLyhTLmgtVC1CKSo2MH0KIGZ1bmN0aW9uIGRyYXcoKXtpZighUylTPWNhbnZhc0ZvcihjdiwzMDApO2NvbD1jb2xvcnMoYm94KTt2YXIgYz1TLmM7Yy5jbGVhclJlY3QoMCwwLFMudyxTLmgpOwogIHZhciBzdGVwPTg7Zm9yKHZhciB4PUw7eDxTLnctUjt4Kz1zdGVwKWZvcih2YXIgeT1UO3k8Uy5oLUI7eSs9c3RlcCl7dmFyIHA9cHJvYihpeCh4K3N0ZXAvMiksaXkoeStzdGVwLzIpKTtjLmZpbGxTdHlsZT1wPj10aHI\/Y29sLmdvb2Q6Y29sLmJhZDtjLmdsb2JhbEFscGhhPTAuMDgrTWF0aC5hYnMocC10aHIpKjAuMjI7Yy5maWxsUmVjdCh4LHksc3RlcCxzdGVwKX1jLmdsb2JhbEFscGhhPTE7CiAgZ3JpZChjLFMse2NvbDpjb2wsc3g6c3gsc3k6c3kseHQ6WzAsMiw0LDYsOCwxMF0seXQ6WzQwLDYwLDgwLDEwMF0sTDpMLFI6UixUOlQsQjpCLHhsOiJob3VycyBzdHVkaWVkIix5bDoiIn0pO2MuZmlsbFN0eWxlPWNvbC5tdXQ7Yy5maWxsVGV4dCgiYXR0ZW5kYW5jZSAlIixMKzQsVCsxMCk7CiAgdmFyIGxnPU1hdGgubG9nKHRoci8oMS10aHIpKTtjLnN0cm9rZVN0eWxlPWNvbC5pbms7Yy5saW5lV2lkdGg9Mi41O2MuYmVnaW5QYXRoKCk7dmFyIGZpcnN0PXRydWU7CiAgZm9yKHZhciBoeD0wO2h4PD0xMDtoeCs9MC4xKXt2YXIgdjA9KGh4LTUpLzMsdjE9KGxnLVdbMl0tV1swXSp2MCkvV1sxXSxhdD12MSoxNis3MjtpZihhdDw0MHx8YXQ+MTAwKXtmaXJzdD10cnVlO2NvbnRpbnVlfWZpcnN0P2MubW92ZVRvKHN4KGh4KSxzeShhdCkpOmMubGluZVRvKHN4KGh4KSxzeShhdCkpO2ZpcnN0PWZhbHNlfWMuc3Ryb2tlKCk7Yy5saW5lV2lkdGg9MTsKICB2YXIgcmlnaHQ9MDtwdHMuZm9yRWFjaChmdW5jdGlvbihwKXt2YXIgcHI9cHJvYihwWzBdLHBbMV0pPj10aHI\/MTowO2lmKHByPT09cFsyXSlyaWdodCsrO2MuZmlsbFN0eWxlPXBbMl0\/Y29sLmdvb2Q6Y29sLmJhZDtjLmJlZ2luUGF0aCgpO2MuYXJjKHN4KHBbMF0pLHN5KHBbMV0pLDUuNSwwLDcpO2MuZmlsbCgpO2lmKHByIT09cFsyXSl7Yy5zdHJva2VTdHlsZT1jb2wuaW5rO2MubGluZVdpZHRoPTI7Yy5iZWdpblBhdGgoKTtjLmFyYyhzeChwWzBdKSxzeShwWzFdKSw5LDAsNyk7Yy5zdHJva2UoKTtjLmxpbmVXaWR0aD0xfX0pOwogICQoIi5jZC0yZC1hY2MiLGJveCkudGV4dENvbnRlbnQ9cmlnaHQrIiAvICIrcHRzLmxlbmd0aDskKCIuY2QtMmQtdGhyIixib3gpLnRleHRDb250ZW50PU1hdGgucm91bmQodGhyKjEwMCkrIiUiOwogICQkKCIuY2QtY2hpcCIsYm94KS5mb3JFYWNoKGZ1bmN0aW9uKGNoKXtjaC5zZXRBdHRyaWJ1dGUoImFyaWEtcHJlc3NlZCIsK2NoLmRhdGFzZXQuYz09PWFkZENscz8idHJ1ZSI6ImZhbHNlIil9KX0KIGN2LmFkZEV2ZW50TGlzdGVuZXIoInBvaW50ZXJkb3duIixmdW5jdGlvbihlKXt2YXIgcmM9Y3YuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksaD1peChlLmNsaWVudFgtcmMubGVmdCksYT1peShlLmNsaWVudFktcmMudG9wKTtpZihoPDB8fGg+MTB8fGE8NDB8fGE+MTAwKXJldHVybjtwdHMucHVzaChbaCxhLGFkZENsc10pO3RyYWluKCk7ZHJhdygpfSk7CiAkJCgiLmNkLWNoaXAiLGJveCkuZm9yRWFjaChmdW5jdGlvbihjaCl7Y2guYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLGZ1bmN0aW9uKCl7YWRkQ2xzPStjaC5kYXRhc2V0LmM7ZHJhdygpfSl9KTsKICQoIi5jZC0yZC10Iixib3gpLmFkZEV2ZW50TGlzdGVuZXIoImlucHV0IixmdW5jdGlvbihlKXt0aHI9K2UudGFyZ2V0LnZhbHVlLzEwMDtkcmF3KCl9KTsKICQoIi5jZC0yZC1yZXNldCIsYm94KS5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsZnVuY3Rpb24oKXtwdHM9cHRzLnNsaWNlKDAsMzYpO3RyYWluKCk7ZHJhdygpfSk7CiB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigicmVzaXplIixmdW5jdGlvbigpe1M9bnVsbDtkcmF3KCl9KTt0cmFpbigpO2RyYXcoKTsKfSk7CgovKiA0LiBUaHJlc2hvbGQgYW5kIGNvbmZ1c2lvbiBtYXRyaXggKi8KJCQoIi5jZGFpLmNkLWxnLXRociIpLmZvckVhY2goZnVuY3Rpb24oYm94KXsKIHZhciBQPVswLjAzLDAuMDgsMC4xMiwwLjE1LDAuMjIsMC4yNywwLjMxLDAuMzgsMC40MiwwLjQ3LDAuNTIsMC41OCwwLjYxLDAuNjYsMC43MiwwLjc5LDAuODQsMC45LDAuOTQsMC45OF0sQT1bMCwwLDAsMCwwLDEsMCwwLDEsMCwwLDEsMCwxLDEsMSwxLDEsMSwxXSxjdj0kKCJjYW52YXMiLGJveCksUyxjb2w7CiBmdW5jdGlvbiBkcmF3KCl7dmFyIHQ9KyQoIi5jZC10aHItdCIsYm94KS52YWx1ZS8xMDAsdHA9MCxmcD0wLGZuPTAsdG49MDtQLmZvckVhY2goZnVuY3Rpb24ocCxpKXt2YXIgcHI9cD49dD8xOjA7aWYocHImJkFbaV0pdHArKztlbHNlIGlmKHByKWZwKys7ZWxzZSBpZihBW2ldKWZuKys7ZWxzZSB0bisrfSk7CiAgJCgiLmNkLWNtLXRwIixib3gpLnRleHRDb250ZW50PXRwOyQoIi5jZC1jbS1mcCIsYm94KS50ZXh0Q29udGVudD1mcDskKCIuY2QtY20tZm4iLGJveCkudGV4dENvbnRlbnQ9Zm47JCgiLmNkLWNtLXRuIixib3gpLnRleHRDb250ZW50PXRuOwogIHZhciBhY2M9KHRwK3RuKS8yMCxwcmVjPXRwK2ZwP3RwLyh0cCtmcCk6MCxyZWM9dHArZm4\/dHAvKHRwK2ZuKTowOyQoIi5jZC10aHItYWNjIixib3gpLnRleHRDb250ZW50PU1hdGgucm91bmQoYWNjKjEwMCkrIiUiOyQoIi5jZC10aHItcHJlYyIsYm94KS50ZXh0Q29udGVudD10cCtmcD9NYXRoLnJvdW5kKHByZWMqMTAwKSsiJSI6Im4vYSI7JCgiLmNkLXRoci1yZWMiLGJveCkudGV4dENvbnRlbnQ9TWF0aC5yb3VuZChyZWMqMTAwKSsiJSI7JCgiLmNkLXRoci10diIsYm94KS50ZXh0Q29udGVudD1NYXRoLnJvdW5kKHQqMTAwKSsiJSI7CiAgJCgiLmNkLXRoci1tc2ciLGJveCkudGV4dENvbnRlbnQ9dD49MC43PyJIaWdoIHRocmVzaG9sZDogdGhlIGZpbHRlciBvbmx5IGZsYWdzIGVtYWlscyBpdCBpcyB2ZXJ5IHN1cmUgYWJvdXQuIEFsbW9zdCBubyByZWFsIGVtYWlsIGxhbmRzIGluIHNwYW0gKGhpZ2ggcHJlY2lzaW9uKSwgYnV0IG1vcmUgc3BhbSBzbGlwcyB0aHJvdWdoIChsb3dlciByZWNhbGwpLiI6dDw9MC4zPyJMb3cgdGhyZXNob2xkOiBhbG1vc3QgYWxsIHNwYW0gZ2V0cyBjYXVnaHQgKGhpZ2ggcmVjYWxsKSwgYnV0IGdlbnVpbmUgZW1haWxzIGxpa2UgeW91ciBpbnRlcm5zaGlwIG9mZmVyIGdldCBmbGFnZ2VkIHRvbyAobG93IHByZWNpc2lvbikuIjoiQSBiYWxhbmNlZCB0aHJlc2hvbGQuIE1vdmUgaXQgZWl0aGVyIHdheSBhbmQgd2F0Y2ggcHJlY2lzaW9uIGFuZCByZWNhbGwgdHJhZGUgcGxhY2VzLiI7CiAgaWYoIVMpUz1jYW52YXNGb3IoY3YsMTIwKTtjb2w9Y29sb3JzKGJveCk7dmFyIGM9Uy5jLEw9NzIsUj0xMjtjLmNsZWFyUmVjdCgwLDAsUy53LFMuaCk7ZnVuY3Rpb24gc3godil7cmV0dXJuIEwrdiooUy53LUwtUil9CiAgYy5maWxsU3R5bGU9Y29sLmJyO2MuZ2xvYmFsQWxwaGE9LjE7Yy5maWxsUmVjdChzeCh0KSwyMixTLnctUi1zeCh0KSw3NCk7Yy5nbG9iYWxBbHBoYT0xO2MuZm9udD0iMTFweCBJbnRlcixzYW5zLXNlcmlmIjtjLmZpbGxTdHlsZT1jb2wuYnI7Yy5maWxsVGV4dCgiZmxhZ2dlZCBhcyBzcGFtIOKGkiIsTWF0aC5taW4oc3godCkrNCxTLnctUi0xMDApLDE0KTsKICBjLmZpbGxTdHlsZT1jb2wubXV0O2MuZmlsbFRleHQoInNwYW0iLDgsNDYpO2MuZmlsbFRleHQoImdlbnVpbmUiLDgsODIpO2MuZmlsbFRleHQoIjAlIixMLTYsMTE0KTtjLmZpbGxUZXh0KCIxMDAlIixTLnctUi0yNiwxMTQpO2MuZmlsbFRleHQoInNwYW0gcHJvYmFiaWxpdHkiLFMudy8yLTMwLDExNCk7CiAgUC5mb3JFYWNoKGZ1bmN0aW9uKHAsaSl7dmFyIHk9QVtpXT80Mjo3ODtjLmZpbGxTdHlsZT1BW2ldP2NvbC5iYWQ6Y29sLmdvb2Q7Yy5iZWdpblBhdGgoKTtjLmFyYyhzeChwKSx5LDYuNSwwLDcpO2MuZmlsbCgpfSk7CiAgYy5zdHJva2VTdHlsZT1jb2wuaW5rO2MubGluZVdpZHRoPTIuNTtjLmJlZ2luUGF0aCgpO2MubW92ZVRvKHN4KHQpLDIwKTtjLmxpbmVUbyhzeCh0KSw5OCk7Yy5zdHJva2UoKTtjLmxpbmVXaWR0aD0xfQogJCgiLmNkLXRoci10Iixib3gpLmFkZEV2ZW50TGlzdGVuZXIoImlucHV0IixkcmF3KTt3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigicmVzaXplIixmdW5jdGlvbigpe1M9bnVsbDtkcmF3KCl9KTtkcmF3KCk7Cn0pOwoKLyogNS4gTG9nIGxvc3MgZXhwbG9yZXIgKi8KJCQoIi5jZGFpLmNkLWxnLWxvc3MiKS5mb3JFYWNoKGZ1bmN0aW9uKGJveCl7CiB2YXIgY3Y9JCgiY2FudmFzIixib3gpLFMsY29sLGFjdHVhbD0xOwogZnVuY3Rpb24gZHJhdygpe2lmKCFTKVM9Y2FudmFzRm9yKGN2LDIyMCk7Y29sPWNvbG9ycyhib3gpO3ZhciBjPVMuYyxwPSskKCIuY2QtbG9zcy1wIixib3gpLnZhbHVlLzEwMCxMPTM0LFI9MTIsVD0xOCxCPTI4LHltYXg9NTsKICBmdW5jdGlvbiBzeCh2KXtyZXR1cm4gTCt2KihTLnctTC1SKX1mdW5jdGlvbiBzeSh2KXtyZXR1cm4gUy5oLUItTWF0aC5taW4odix5bWF4KS95bWF4KihTLmgtVC1CKX0KICBjLmNsZWFyUmVjdCgwLDAsUy53LFMuaCk7Z3JpZChjLFMse2NvbDpjb2wsc3g6c3gsc3k6c3kseHQ6WzAsMC4yNSwwLjUsMC43NSwxXSx5dDpbMCwxLDIsMyw0LDVdLEw6TCxSOlIsVDpULEI6Qix4bDoicHJlZGljdGVkIHByb2JhYmlsaXR5IG9mIGNsYXNzIDEiLHlsOiJwZW5hbHR5In0pOwogIGMuc3Ryb2tlU3R5bGU9Y29sLmJyO2MubGluZVdpZHRoPTM7Yy5iZWdpblBhdGgoKTtmb3IodmFyIHg9MC4wMDU7eDw9MC45OTU7eCs9MC4wMDUpe3ZhciB2PWFjdHVhbD8tTWF0aC5sb2coeCk6LU1hdGgubG9nKDEteCk7eD09PTAuMDA1P2MubW92ZVRvKHN4KHgpLHN5KHYpKTpjLmxpbmVUbyhzeCh4KSxzeSh2KSl9Yy5zdHJva2UoKTsKICBjLnN0cm9rZVN0eWxlPWNvbC5tdXQ7Yy5zZXRMaW5lRGFzaChbNSw0XSk7Yy5saW5lV2lkdGg9MS41O2MuYmVnaW5QYXRoKCk7Zm9yKHZhciB4Mj0wO3gyPD0xO3gyKz0wLjAxKXt2YXIgdjI9YWN0dWFsPygxLXgyKSooMS14Mik6eDIqeDI7eDI9PT0wP2MubW92ZVRvKHN4KHgyKSxzeSh2MikpOmMubGluZVRvKHN4KHgyKSxzeSh2MikpfWMuc3Ryb2tlKCk7Yy5zZXRMaW5lRGFzaChbXSk7Yy5saW5lV2lkdGg9MTsKICB2YXIgbGw9YWN0dWFsPy1NYXRoLmxvZyhwKTotTWF0aC5sb2coMS1wKSxzZT1hY3R1YWw\/KDEtcCkqKDEtcCk6cCpwO2MuZmlsbFN0eWxlPWNvbC5iYWQ7Yy5iZWdpblBhdGgoKTtjLmFyYyhzeChwKSxzeShsbCksNywwLDcpO2MuZmlsbCgpOwogICQoIi5jZC1sb3NzLXB2Iixib3gpLnRleHRDb250ZW50PU1hdGgucm91bmQocCoxMDApKyIlIjskKCIuY2QtbG9zcy1sbCIsYm94KS50ZXh0Q29udGVudD1mMShsbCwyKTskKCIuY2QtbG9zcy1zZSIsYm94KS50ZXh0Q29udGVudD1mMShzZSwyKTsKICB2YXIgd3Jvbmc9YWN0dWFsP3A8MC41OnA+MC41LGNvbmY9YWN0dWFsPzEtcDpwOwogICQoIi5jZC1sb3NzLW1zZyIsYm94KS50ZXh0Q29udGVudD0hd3Jvbmc\/IlRoZSBtb2RlbCBsZWFucyB0aGUgcmlnaHQgd2F5LCBzbyB0aGUgcGVuYWx0eSBpcyBzbWFsbC4iOmNvbmY+MC45PyJDb25maWRlbnRseSB3cm9uZy4gTG9nIGxvc3Mgc2hvb3RzIHVwIHRvICIrZjEobGwsMikrIiB3aGlsZSBzcXVhcmVkIGVycm9yIGJhcmVseSByZWFjaGVzIDEuIFRoYXQgaHVnZSBwZW5hbHR5IGlzIHdoYXQgcHVzaGVzIHRoZSBtb2RlbCB0byBmaXggdGhpcyBtaXN0YWtlIGZpcnN0LiI6Ildyb25nIHNpZGUgb2YgNTAlLiBUaGUgcGVuYWx0eSBncm93cyBxdWlja2x5IGFzIHRoZSBtb2RlbCBiZWNvbWVzIG1vcmUgY29uZmlkZW50IGluIHRoZSB3cm9uZyBhbnN3ZXIuIjsKICAkJCgiLmNkLWNoaXAiLGJveCkuZm9yRWFjaChmdW5jdGlvbihjaCl7Y2guc2V0QXR0cmlidXRlKCJhcmlhLXByZXNzZWQiLCtjaC5kYXRhc2V0LmE9PT1hY3R1YWw\/InRydWUiOiJmYWxzZSIpfSl9CiAkKCIuY2QtbG9zcy1wIixib3gpLmFkZEV2ZW50TGlzdGVuZXIoImlucHV0IixkcmF3KTskJCgiLmNkLWNoaXAiLGJveCkuZm9yRWFjaChmdW5jdGlvbihjaCl7Y2guYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLGZ1bmN0aW9uKCl7YWN0dWFsPStjaC5kYXRhc2V0LmE7ZHJhdygpfSl9KTsKIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJyZXNpemUiLGZ1bmN0aW9uKCl7Uz1udWxsO2RyYXcoKX0pO2RyYXcoKTsKfSk7CgovKiA2LiBUcmFpbmluZyBhbmltYXRpb24gKi8KJCQoIi5jZGFpLmNkLWxnLXRyYWluIikuZm9yRWFjaChmdW5jdGlvbihib3gpewogdmFyIGN2cz0kJCgiY2FudmFzIixib3gpLEEsQjIsdz0wLGI9MCxscj0wLjEsc3RlcD0wLGhpc3Q9W10sdGltZXI9bnVsbCxjb2w7CiBmdW5jdGlvbiBvbmUoKXt2YXIgZHc9MCxkYj0wO2Zvcih2YXIgaT0wO2k8SC5sZW5ndGg7aSsrKXt2YXIgZT1zaWcodypIW2ldK2IpLVlbaV07ZHcrPWUqSFtpXTtkYis9ZX13LT1scipkdy9ILmxlbmd0aDtiLT1scipkYi9ILmxlbmd0aDtzdGVwKys7aGlzdC5wdXNoKGxvZ2xvc3ModyxiKSl9CiBmdW5jdGlvbiBkcmF3KCl7aWYoIUEpe0E9Y2FudmFzRm9yKGN2c1swXSwyMjApO0IyPWNhbnZhc0ZvcihjdnNbMV0sMjIwKX1jb2w9Y29sb3JzKGJveCk7dmFyIGM9QS5jLG89e0w6MzAsUjoxMCxUOjE2LEI6MjYsY29sOmNvbH07CiAgby5zeD1mdW5jdGlvbih2KXtyZXR1cm4gby5MK3YvMTAqKEEudy1vLkwtby5SKX07by5zeT1mdW5jdGlvbih2KXtyZXR1cm4gQS5oLW8uQi12KihBLmgtby5ULW8uQil9O28ueHQ9WzAsNSwxMF07by55dD1bMCwwLjUsMV07by54bD0iaG91cnMiO28ueWw9IlAocGFzcykiOwogIGMuY2xlYXJSZWN0KDAsMCxBLncsQS5oKTtncmlkKGMsQSxvKTtjLnN0cm9rZVN0eWxlPWNvbC5icjtjLmxpbmVXaWR0aD0zO2N1cnZlKGMsbyx3LGIsMTApO2MubGluZVdpZHRoPTE7CiAgSC5mb3JFYWNoKGZ1bmN0aW9uKGgsaSl7Yy5maWxsU3R5bGU9WVtpXT9jb2wuZ29vZDpjb2wuaW5rO2MuYmVnaW5QYXRoKCk7Yy5hcmMoby5zeChoKSxvLnN5KFlbaV0pLDUsMCw3KTtjLmZpbGwoKX0pOwogIHZhciBkPUIyLmMsaD1oaXN0Lmxlbmd0aD9oaXN0Oltsb2dsb3NzKHcsYildLE49TWF0aC5tYXgoMTAwLGgubGVuZ3RoKSxteD0wLjc1O2QuY2xlYXJSZWN0KDAsMCxCMi53LEIyLmgpOwogIGZ1bmN0aW9uIHB4KGkpe3JldHVybiAzNCtpL04qKEIyLnctNDQpfWZ1bmN0aW9uIHB5KHYpe3JldHVybiBCMi5oLTI2LU1hdGgubWluKHYsbXgpL214KihCMi5oLTQ0KX0KICBncmlkKGQsQjIse2NvbDpjb2wsc3g6ZnVuY3Rpb24oKXtyZXR1cm4gMH0sc3k6cHkseHQ6W10seXQ6WzAsMC4yNSwwLjUsMC43NV0sTDozNCxSOjEwLFQ6MTgsQjoyNix4bDoic3RlcHMg4oaSIix5bDoibG9nIGxvc3MifSk7CiAgZC5zdHJva2VTdHlsZT1jb2wuYmFkO2QubGluZVdpZHRoPTIuNTtkLmJlZ2luUGF0aCgpO2guZm9yRWFjaChmdW5jdGlvbih2LGkpe2k\/ZC5saW5lVG8ocHgoaSkscHkodikpOmQubW92ZVRvKHB4KGkpLHB5KHYpKX0pO2Quc3Ryb2tlKCk7CiAgdmFyIEw9bG9nbG9zcyh3LGIpOyQoIi5jZC10ci13Iixib3gpLnRleHRDb250ZW50PWYxKHcsMyk7JCgiLmNkLXRyLWIiLGJveCkudGV4dENvbnRlbnQ9ZjEoYiwzKTskKCIuY2QtdHItbCIsYm94KS50ZXh0Q29udGVudD1mMShMLDMpOyQoIi5jZC10ci1uIixib3gpLnRleHRDb250ZW50PXN0ZXA7CiAgJCgiLmNkLXRyLW1zZyIsYm94KS50ZXh0Q29udGVudD1zdGVwPT09MD8iU3RhcnRzIHdpdGggdyA9IDAgYW5kIGIgPSAwLCBzbyBldmVyeSBzdHVkZW50IGdldHMgYSA1MCUgY2hhbmNlLiBQcmVzcyBSdW4uIjpMPDAuMzUzMDU4PyJDb252ZXJnZWQgYXQgdyA9ICIrZjEodywyKSsiIGFuZCBiID0gIitmMShiLDIpKyIuIFRoZSBOdW1QeSBjb2RlIGxhdGVyIGluIHRoaXMgZ3VpZGUgZmluZHMgMS4wODcgYW5kIOKIkjQuNjMzIGFmdGVyIDIwLDAwMCBzdGVwcywgc28gdGhpcyBpcyBlc3NlbnRpYWxseSB0aGUgc2FtZSBhbnN3ZXIuIjoiRWFjaCBzdGVwIG51ZGdlcyB3IGFuZCBiIHRvIGxvd2VyIHRoZSBsb2cgbG9zcy4gVGhlIGN1cnZlIHNsb3dseSBiZW5kcyBpbnRvIGFuIFMuIn0KIGZ1bmN0aW9uIHN0b3AoKXtjbGVhckludGVydmFsKHRpbWVyKTt0aW1lcj1udWxsOyQoIi5jZC10ci1ydW4iLGJveCkudGV4dENvbnRlbnQ9IlJ1biJ9CiBmdW5jdGlvbiB0aWNrKCl7Zm9yKHZhciBrPTA7azwoc3RlcDw0MD8xOnN0ZXA8NDAwPzEwOjEyMCk7aysrKW9uZSgpO2RyYXcoKTtpZihsb2dsb3NzKHcsYik8MC4zNTMwNTh8fHN0ZXA+NDAwMDApc3RvcCgpfQogJCgiLmNkLXRyLXJ1biIsYm94KS5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsZnVuY3Rpb24oKXtpZih0aW1lcilyZXR1cm4gc3RvcCgpO3RoaXMudGV4dENvbnRlbnQ9IlBhdXNlIjt0aW1lcj1zZXRJbnRlcnZhbCh0aWNrLFJNPzEwOjUwKX0pOwogJCgiLmNkLXRyLW9uZSIsYm94KS5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsZnVuY3Rpb24oKXtvbmUoKTtkcmF3KCl9KTsKICQoIi5jZC10ci1yZXNldCIsYm94KS5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsZnVuY3Rpb24oKXtzdG9wKCk7dz0wO2I9MDtzdGVwPTA7aGlzdD1bXTtkcmF3KCl9KTsKICQoIi5jZC10ci1sciIsYm94KS5hZGRFdmVudExpc3RlbmVyKCJpbnB1dCIsZnVuY3Rpb24oZSl7bHI9K2UudGFyZ2V0LnZhbHVlOyQoIi5jZC10ci1scnYiLGJveCkudGV4dENvbnRlbnQ9bHIudG9GaXhlZCgyKTtzdG9wKCk7dz0wO2I9MDtzdGVwPTA7aGlzdD1bXTtkcmF3KCl9KTsKIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJyZXNpemUiLGZ1bmN0aW9uKCl7QT1udWxsO2RyYXcoKX0pO2RyYXcoKTsKfSk7CgovKiA3LiBTb2Z0bWF4ICovCiQkKCIuY2RhaS5jZC1sZy1zb2Z0IikuZm9yRWFjaChmdW5jdGlvbihib3gpewogdmFyIG5hbWVzPVsiRFNBIiwiV2ViIGRldmVsb3BtZW50IiwiQUkgYW5kIE1MIl0sc2w9JCQoImlucHV0W3R5cGU9cmFuZ2VdIixib3gpOwogZnVuY3Rpb24gZHJhdygpe3ZhciB6PXNsLm1hcChmdW5jdGlvbihzKXtyZXR1cm4gK3MudmFsdWV9KSxtPU1hdGgubWF4LmFwcGx5KG51bGwseiksZT16Lm1hcChmdW5jdGlvbih2KXtyZXR1cm4gTWF0aC5leHAodi1tKX0pLHM9ZS5yZWR1Y2UoZnVuY3Rpb24oYSxiKXtyZXR1cm4gYStifSwwKSxwPWUubWFwKGZ1bmN0aW9uKHYpe3JldHVybiB2L3N9KSxiZXN0PXAuaW5kZXhPZihNYXRoLm1heC5hcHBseShudWxsLHApKTsKICBzbC5mb3JFYWNoKGZ1bmN0aW9uKHMsaSl7JCgiLmNkLXNtLXoiK2ksYm94KS50ZXh0Q29udGVudD1mMSh6W2ldLDEpfSk7CiAgJCgiLmNkLWJhcnMiLGJveCkuaW5uZXJIVE1MPXAubWFwKGZ1bmN0aW9uKHYsaSl7cmV0dXJuICc8ZGl2IGNsYXNzPSJjZC1iYXItcm93Ij48YiBzdHlsZT0iZm9udC1mYW1pbHk6aW5oZXJpdCI+JytuYW1lc1tpXSsnPC9iPjxkaXYgY2xhc3M9ImNkLXRsLXRyYWNrIj48ZGl2IGNsYXNzPSJjZC10bC1iYXIiIHN0eWxlPSJ3aWR0aDonKyh2KjEwMCkudG9GaXhlZCgxKSsnJSI+PC9kaXY+PC9kaXY+PHNwYW4gY2xhc3M9ImNkLXRsLXciPicrKHYqMTAwKS50b0ZpeGVkKDEpKyclPC9zcGFuPjwvZGl2Pid9KS5qb2luKCIiKTsKICAkKCIuY2Qtc20tbXNnIixib3gpLnRleHRDb250ZW50PSJQcmVkaWN0aW9uOiAiK25hbWVzW2Jlc3RdKyIuIFRoZSB0aHJlZSBwcm9iYWJpbGl0aWVzIGFsd2F5cyBhZGQgdXAgdG8gMTAwJSwgaG93ZXZlciB5b3UgbW92ZSB0aGUgc2NvcmVzLiJ9CiBzbC5mb3JFYWNoKGZ1bmN0aW9uKHMpe3MuYWRkRXZlbnRMaXN0ZW5lcigiaW5wdXQiLGRyYXcpfSk7ZHJhdygpOwp9KTsKCi8qIDguIFF1aXogKi8KJCQoIi5jZGFpLmNkLWxnLXF1aXoiKS5mb3JFYWNoKGZ1bmN0aW9uKGJveCl7CiB2YXIgUT1bCiB7cToiTG9naXN0aWMgcmVncmVzc2lvbiBpcyBtYWlubHkgdXNlZCBmb3Igd2hpY2gga2luZCBvZiBwcm9ibGVtPyIsbzpbIlJlZ3Jlc3Npb24gKHByZWRpY3RpbmcgYSBudW1iZXIpIiwiQ2xhc3NpZmljYXRpb24gKHByZWRpY3RpbmcgYSBjYXRlZ29yeSkiLCJDbHVzdGVyaW5nIiwiRGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIl0sYToxLGU6IkRlc3BpdGUgdGhlIG5hbWUsIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaXMgYSBjbGFzc2lmaWNhdGlvbiBhbGdvcml0aG0uIEl0IHByZWRpY3RzIHRoZSBwcm9iYWJpbGl0eSBvZiBhIGNsYXNzLiJ9LAoge3E6IldoYXQgZG9lcyB0aGUgc2lnbW9pZCBmdW5jdGlvbiBkbz8iLG86WyJTcXVhcmVzIHRoZSBlcnJvciIsIlR1cm5zIGFueSBudW1iZXIgaW50byBhIHZhbHVlIGJldHdlZW4gMCBhbmQgMSIsIlNvcnRzIHRoZSBkYXRhIiwiUmVtb3ZlcyBvdXRsaWVycyJdLGE6MSxlOiJTaWdtb2lkIHNxdWFzaGVzIGFueSByZWFsIG51bWJlciBpbnRvIHRoZSByYW5nZSAwIHRvIDEsIHNvIHRoZSBvdXRwdXQgY2FuIGJlIHJlYWQgYXMgYSBwcm9iYWJpbGl0eS4ifSwKIHtxOiJJZiB0aGUgcHJvYmFiaWxpdHkgb2YgcGFzc2luZyBpcyA4MCUsIHdoYXQgYXJlIHRoZSBvZGRzPyIsbzpbIjAuOCB0byAxIiwiNCB0byAxIiwiOCB0byAyIGFnYWluc3QiLCIxIHRvIDQiXSxhOjEsZToiT2RkcyA9IHAgLyAoMSDiiJIgcCkgPSAwLjggLyAwLjIgPSA0LiBTbyBwYXNzaW5nIGlzIGZvdXIgdGltZXMgYXMgbGlrZWx5IGFzIGZhaWxpbmcuIn0sCiB7cToiV2hpY2ggbG9zcyBmdW5jdGlvbiBkb2VzIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbWluaW1pc2U\/IixvOlsiTWVhbiBzcXVhcmVkIGVycm9yIiwiTWVhbiBhYnNvbHV0ZSBlcnJvciIsIkxvZyBsb3NzIChiaW5hcnkgY3Jvc3MtZW50cm9weSkiLCJIaW5nZSBsb3NzIl0sYToyLGU6IkxvZyBsb3NzIGhlYXZpbHkgcHVuaXNoZXMgY29uZmlkZW50IHdyb25nIHByZWRpY3Rpb25zLCBhbmQgaXQga2VlcHMgdGhlIG9wdGltaXNhdGlvbiBwcm9ibGVtIGNvbnZleC4ifSwKIHtxOiJGb3IgY2FuY2VyIHNjcmVlbmluZywgeW91IGxvd2VyIHRoZSB0aHJlc2hvbGQgZnJvbSAwLjUgdG8gMC4yLiBXaGF0IGhhcHBlbnM\/IixvOlsiUmVjYWxsIGdvZXMgdXAgYW5kIHByZWNpc2lvbiB1c3VhbGx5IGdvZXMgZG93biIsIlByZWNpc2lvbiBnb2VzIHVwIGFuZCByZWNhbGwgZ29lcyBkb3duIiwiQWNjdXJhY3kgYWx3YXlzIGltcHJvdmVzIiwiTm90aGluZyBjaGFuZ2VzIl0sYTowLGU6Ik1vcmUgY2FzZXMgZ2V0IGZsYWdnZWQsIHNvIGZld2VyIHJlYWwgY2FuY2VycyBhcmUgbWlzc2VkIChoaWdoZXIgcmVjYWxsKSwgYXQgdGhlIGNvc3Qgb2YgbW9yZSBmYWxzZSBhbGFybXMgKGxvd2VyIHByZWNpc2lvbikuIn0sCiB7cToiWW91IG5lZWQgdG8gY2xhc3NpZnkgbmV3cyBhcnRpY2xlcyBpbnRvIHNwb3J0cywgcG9saXRpY3MgYW5kIHRlY2guIFdoaWNoIHZhcmlhbnQgZml0cz8iLG86WyJCaW5hcnkgbG9naXN0aWMgcmVncmVzc2lvbiIsIk11bHRpbm9taWFsIGxvZ2lzdGljIHJlZ3Jlc3Npb24iLCJPcmRpbmFsIGxvZ2lzdGljIHJlZ3Jlc3Npb24iLCJMaW5lYXIgcmVncmVzc2lvbiJdLGE6MSxlOiJUaHJlZSBvciBtb3JlIHVub3JkZXJlZCBjbGFzc2VzIGNhbGwgZm9yIG11bHRpbm9taWFsIGxvZ2lzdGljIHJlZ3Jlc3Npb24sIHdoaWNoIHVzZXMgdGhlIHNvZnRtYXggZnVuY3Rpb24uIn1dOwogdmFyIGk9MCxzY29yZT0wLGJvZHk9JCgiLmNkLWxncS1ib2R5Iixib3gpOwogZnVuY3Rpb24gc2hvdygpe3ZhciBpdD1RW2ldO2JvZHkuaW5uZXJIVE1MPSc8cCBjbGFzcz0iY2Qtc21hbGwiPlF1ZXN0aW9uICcrKGkrMSkrJyBvZiAnK1EubGVuZ3RoKycgfCBTY29yZSAnK3Njb3JlKyc8L3A+PGRpdiBjbGFzcz0iY2QtZ2FtZS1jYXJkIiBzdHlsZT0ibWluLWhlaWdodDo2NHB4Ij4nK2l0LnErJzwvZGl2PjxkaXYgY2xhc3M9ImNkLXEtb3B0cyI+JytpdC5vLm1hcChmdW5jdGlvbihvLGspe3JldHVybiAnPGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJjZC1idG4iIGRhdGEtaz0iJytrKyciPicrbysnPC9idXR0b24+J30pLmpvaW4oIiIpKyc8L2Rpdj48ZGl2IGNsYXNzPSJjZC1mZWVkYmFjayIgaGlkZGVuPjwvZGl2PjxkaXYgc3R5bGU9Im1hcmdpbi10b3A6MTJweCI+PGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJjZC1idG4gY2QtcHJpbWFyeSBjZC1sZ3EtbmV4dCIgaGlkZGVuPicrKGk8US5sZW5ndGgtMT8iTmV4dCBxdWVzdGlvbiI6IlNlZSBteSBzY29yZSIpKyc8L2J1dHRvbj48L2Rpdj4nOwogICQkKCIuY2QtcS1vcHRzIGJ1dHRvbiIsYm9keSkuZm9yRWFjaChmdW5jdGlvbihidCl7YnQuYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLGZ1bmN0aW9uKCl7dmFyIGs9K2J0LmRhdGFzZXQuayxvaz1rPT09aXQuYTtpZihvaylzY29yZSsrOyQkKCIuY2QtcS1vcHRzIGJ1dHRvbiIsYm9keSkuZm9yRWFjaChmdW5jdGlvbih4LGope3guZGlzYWJsZWQ9dHJ1ZTtpZihqPT09aXQuYSl4LmNsYXNzTGlzdC5hZGQoImNkLXJpZ2h0Iik7ZWxzZSBpZihqPT09ayl4LmNsYXNzTGlzdC5hZGQoImNkLXdyb25nIil9KTsKICAgdmFyIGZiPSQoIi5jZC1mZWVkYmFjayIsYm9keSk7ZmIuaGlkZGVuPWZhbHNlO2ZiLmNsYXNzTmFtZT0iY2QtZmVlZGJhY2sgIisob2s\/ImNkLW9rIjoiY2Qtbm8iKTtmYi5pbm5lckhUTUw9IjxiPiIrKG9rPyJDb3JyZWN0LiI6Ik5vdCBxdWl0ZS4iKSsiPC9iPiAiK2l0LmU7JCgiLmNkLWxncS1uZXh0Iixib2R5KS5oaWRkZW49ZmFsc2V9KX0pOwogICQoIi5jZC1sZ3EtbmV4dCIsYm9keSkuYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLGZ1bmN0aW9uKCl7aSsrO2lmKGk8US5sZW5ndGgpc2hvdygpO2Vsc2UgZG9uZSgpfSl9CiBmdW5jdGlvbiBkb25lKCl7Ym9keS5pbm5lckhUTUw9JzxkaXYgY2xhc3M9ImNkLWZlZWRiYWNrIGNkLW9rIj48Yj5Zb3Ugc2NvcmVkICcrc2NvcmUrJyBvdXQgb2YgJytRLmxlbmd0aCsnLjwvYj4gJysoc2NvcmU+PTU\/IllvdSBhcmUgcmVhZHkgdG8gdXNlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gb24gYSByZWFsIGRhdGFzZXQuIjpzY29yZT49Mz8iR29vZCBiYXNlLiBSZXZpc2l0IHRoZSBvZGRzIGFuZCB0aHJlc2hvbGQgc2VjdGlvbnMgb25jZSBtb3JlLiI6IlNjcm9sbCBiYWNrIHVwLCBwbGF5IHdpdGggdGhlIHdpZGdldHMgYWdhaW4sIHRoZW4gcmV0cnkuIikrJzwvZGl2PjxkaXYgc3R5bGU9Im1hcmdpbi10b3A6MTJweCI+PGJ1dHRvbiB0eXBlPSJidXR0b24iIGNsYXNzPSJjZC1idG4gY2QtbGdxLWFnYWluIj5UcnkgYWdhaW48L2J1dHRvbj48L2Rpdj4nOyQoIi5jZC1sZ3EtYWdhaW4iLGJvZHkpLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixmdW5jdGlvbigpe2k9MDtzY29yZT0wO3Nob3coKX0pfQogJCgiLmNkLWxncS1zdGFydCIsYm94KS5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsc2hvdyk7Cn0pOwoKLyogQ29weSBidXR0b25zICovCiQkKCIuY2RhaS5jZC1jb2RlYm94IikuZm9yRWFjaChmdW5jdGlvbihib3gpe3ZhciBidD0kKCIuY2QtY29weSIsYm94KTtpZighYnQpcmV0dXJuO2J0LmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixmdW5jdGlvbigpe3ZhciB0PSQoInByZSBjb2RlIixib3gpLnRleHRDb250ZW50O2Z1bmN0aW9uIG9rKCl7YnQudGV4dENvbnRlbnQ9IkNvcGllZCI7c2V0VGltZW91dChmdW5jdGlvbigpe2J0LnRleHRDb250ZW50PSJDb3B5In0sMTUwMCl9CiBmdW5jdGlvbiBzZWwoKXt2YXIgcj1kb2N1bWVudC5jcmVhdGVSYW5nZSgpO3Iuc2VsZWN0Tm9kZUNvbnRlbnRzKCQoInByZSBjb2RlIixib3gpKTt2YXIgcz13aW5kb3cuZ2V0U2VsZWN0aW9uKCk7cy5yZW1vdmVBbGxSYW5nZXMoKTtzLmFkZFJhbmdlKHIpO2J0LnRleHRDb250ZW50PSJQcmVzcyBDdHJsK0MifQogaWYobmF2aWdhdG9yLmNsaXBib2FyZCYmbmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQpe25hdmlnYXRvci5jbGlwYm9hcmQud3JpdGVUZXh0KHQpLnRoZW4ob2ssc2VsKX1lbHNlIHNlbCgpfSl9KTsKfSkoKTsK\"><\/script>\n","protected":false},"excerpt":{"rendered":"<p>Learn logistic regression by playing with it: bend the sigmoid curve, convert odds, draw a decision boundary, tune a spam filter threshold and run Python code with scikit-learn.<\/p>\n","protected":false},"author":1,"featured_media":1164,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[47],"tags":[],"class_list":["post-1165","post","type-post","status-publish","format-standard","has-post-thumbnail","category-ai-machine-learning"],"featured_image_src":"https:\/\/codeanddebug.in\/blog\/wp-content\/uploads\/2026\/10\/logistic-regression-in-machine-learning.jpg","author_info":{"display_name":"codeanddebug","author_link":"https:\/\/codeanddebug.in\/blog\/author\/codeanddebug\/"},"_links":{"self":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/1165","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/comments?post=1165"}],"version-history":[{"count":2,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/1165\/revisions"}],"predecessor-version":[{"id":1182,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/1165\/revisions\/1182"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/media\/1164"}],"wp:attachment":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/media?parent=1165"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/categories?post=1165"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/tags?post=1165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}