Param Pambhar

Erstelle dein Portfolio mit ProoVErstelle dein Portfolio mit ProoV
ProoV
EN Verifiziertes Arbeitsportfolio

ProoV Portfolio

Param Pambhar

Zum ProoV-Leaderboard

Projekte

Zertifiziert

Selbstgesteuertes Projekt

Frontend Engineering with Prediction Game

Junior Front-End Engineer · Softwareentwicklung · Juli 2026

84/ 100

Built a complete World Cup prediction game end to end: rendered the fixture board, scored picks with the exact 5/2/0 rules, derived team attack strengths from real results, and used them in a bot predictor that auto-picks every match. Also deployed the finished experience to a live https Netlify URL for immediate sharing.

Bewertet nach

  • Scoring engine correctness30%
  • Prediction model genuinely from real data25%
  • Game completeness and leaderboard soundness25%
  • Shipped and shareable: live deployed URL20%

Bestanden · Bestehensgrenze 60/100

Was herausstach6
  • Implemented the exact scoring rubric, including correct handling of draws and exact-score matches.
  • Computed team strengths from a real-results sample and used those strengths inside the bot prediction logic.
  • Shipped a live Netlify deployment URL that matches the project’s shareable-delivery requirement.
  • Leakage-Free Feature Engineering
  • Honest Model Evaluation
  • End-to-End Game Assembly
Meine eingereichte Arbeit10 Aufgaben

Lab Orientation

Meine Lösung
{"code":"<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Predict the Cup</title>\n    <style>\n      body {\n        font-family: -apple-system, sans-serif;\n        background: #FDFCF7;\n        color: #0E1726;\n        padding: 32px;\n        margin: 0;\n      }\n      h1 {\n        color: #00C65A;\n        font-size: 32px;\n        margin: 0 0 12px 0;\n      }\n      p {\n        color: #3F4B5F;\n        margin: 0;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Param's Prediction Game</h1>\n    <p>Welcome to your prediction game.</p>\n  </body>\n</html>","ranAt":"2026-07-26T13:51:41.990Z"}

Example Render Fixtures

Meine Lösung
{"code":"<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Worked Example - Render Two Matches</title>\n\n  <style>\n    body {\n      font: 15px/1.4 system-ui;\n      padding: 24px;\n      background: #F7F8FA;\n    }\n\n    h1 {\n      color: #0E1726;\n    }\n\n    .match {\n      background: #fff;\n      border: 1px solid #E4E8EE;\n      border-radius: 12px;\n      padding: 14px;\n      margin-bottom: 12px;\n      max-width: 360px;\n    }\n\n    .teams {\n      font-weight: 800;\n      color: #0E1726;\n      margin-bottom: 8px;\n    }\n\n    .picks {\n      display: grid;\n      grid-template-columns: 1fr auto 1fr;\n      gap: 8px;\n      align-items: center;\n    }\n\n    input {\n      padding: 8px;\n      border: 1px solid #E4E8EE;\n      border-radius: 8px;\n      text-align: center;\n      font-size: 16px;\n    }\n\n    .vs {\n      color: #6A7589;\n      font-weight: 700;\n      font-size: 12px;\n    }\n  </style>\n</head>\n\n<body>\n\n  <h1>My Picks</h1>\n\n  <div id=\"board\"></div>\n\n  <script>\n\n    // Sample match data\n    const SAMPLE_FIXTURES = [\n      {\n        home: \"Germany\",\n        away: \"Brazil\",\n        date: \"2026-06-28\"\n      },\n      {\n        home: \"France\",\n        away: \"Spain\",\n        date: \"2026-06-29\"\n      }\n    ];\n\n    // Get the board\n    const board = document.getElementById(\"board\");\n\n    // Create one card for each match\n    SAMPLE_FIXTURES.forEach((match) => {\n\n      const card = document.createElement(\"div\");\n      card.className = \"match\";\n\n      card.setAttribute(\n        \"data-match\",\n        match.home + \"-\" + match.away\n      );\n\n      card.innerHTML =\n        '<div class=\"teams\">' +\n          match.home +\n          ' vs ' +\n          match.away +\n        '</div>' +\n\n        '<div class=\"picks\">' +\n          '<input type=\"number\" min=\"0\" placeholder=\"0\">' +\n          '<span class=\"vs\">vs</span>' +\n          '<input type=\"number\" min=\"0\" placeholder=\"0\">' +\n        '</div>';\n\n      board.appendChild(card);\n\n    });\n\n  </script>\n\n</body>\n</html>","ranAt":"2026-07-26T13:53:45.072Z"}

Act1 Fixtures Form

Meine Lösung
{"code":"<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Predict the Cup · my picks</title>\n\n  <style>\n    body {\n      font: 15px/1.45 system-ui, -apple-system, \"Segoe UI\", sans-serif;\n      padding: 24px;\n      background: #F7F8FA;\n      color: #0E1726;\n    }\n\n    h1 {\n      margin: 0 0 4px;\n      font-size: 22px;\n    }\n\n    .sub {\n      color: #6A7589;\n      font-size: 13px;\n      margin-bottom: 16px;\n    }\n\n    #board {\n      display: grid;\n      gap: 12px;\n      max-width: 640px;\n    }\n\n    .match {\n      background: #fff;\n      border: 1px solid #E4E8EE;\n      border-radius: 12px;\n      padding: 14px;\n    }\n\n    .meta {\n      color: #6A7589;\n      font-size: 11px;\n      text-transform: uppercase;\n      letter-spacing: 0.14em;\n      margin-bottom: 6px;\n    }\n\n    .teams {\n      font-weight: 800;\n      font-size: 15.5px;\n      margin-bottom: 8px;\n    }\n\n    .picks {\n      display: grid;\n      grid-template-columns: 1fr auto 1fr;\n      gap: 8px;\n      align-items: center;\n    }\n\n    .picks input {\n      padding: 9px;\n      border: 1px solid #E4E8EE;\n      border-radius: 8px;\n      text-align: center;\n      font: inherit;\n      font-weight: 700;\n      font-size: 15px;\n    }\n\n    .vs {\n      color: #6A7589;\n      font-weight: 700;\n      font-size: 12px;\n    }\n\n    footer {\n      color: #6A7589;\n      font-size: 11px;\n      margin-top: 24px;\n      max-width: 640px;\n      line-height: 1.5;\n    }\n  </style>\n</head>\n\n<body>\n\n  <h1>My picks</h1>\n  <div class=\"sub\">2026 World Cup · Round of 32</div>\n\n  <div id=\"board\"></div>\n\n  <footer>\n    Independent learning project. Not affiliated with or endorsed by FIFA.\n    Fixtures snapshot: openfootball/worldcup.json (CC0-1.0).\n  </footer>\n\n  <script>\n    const FIXTURES = [\n      { home: \"Germany\", away: \"Mexico\", date: \"2026-06-28\", round: \"R32\" },\n      { home: \"Argentina\", away: \"Switzerland\", date: \"2026-06-29\", round: \"R32\" },\n      { home: \"France\", away: \"Portugal\", date: \"2026-06-30\", round: \"R32\" },\n      { home: \"Spain\", away: \"Uruguay\", date: \"2026-07-01\", round: \"R32\" },\n      { home: \"Brazil\", away: \"Japan\", date: \"2026-07-02\", round: \"R32\" },\n      { home: \"England\", away: \"Netherlands\", date: \"2026-07-03\", round: \"R32\" },\n    ];\n\n    function renderFixtures() {\n      const board = document.getElementById(\"board\");\n\n      board.innerHTML = \"\";\n\n      FIXTURES.forEach((match) => {\n\n        const card = document.createElement(\"div\");\n        card.className = \"match\";\n        card.setAttribute(\"data-match\", match.home + \"-\" + match.away);\n\n        card.innerHTML = `\n          <div class=\"meta\">${match.round} · ${match.date}</div>\n\n          <div class=\"teams\">\n            ${match.home} vs ${match.away}\n          </div>\n\n          <div class=\"picks\">\n            <input type=\"number\" min=\"0\" placeholder=\"-\">\n\n            <span class=\"vs\">VS</span>\n\n            <input type=\"number\" min=\"0\" placeholder=\"-\">\n          </div>\n        `;\n\n        board.appendChild(card);\n\n      });\n    }\n\n    renderFixtures();\n  </script>\n\n</body>\n</html>","selfCheck":{"cases":[{"name":"FIXTURES const is in scope","pass":true,"detail":""},{"name":"One card per fixture (data-match)","pass":true,"detail":""},{"name":"Two number inputs per card","pass":true,"detail":""},{"name":"Team names visible on each card","pass":true,"detail":""}],"ranAt":"2026-07-26T13:57:48.911Z"},"ranAt":"2026-07-26T13:57:48.911Z"}

Act2 Scoring Function

Meine Lösung
{"code":"<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>scorePick · your turn</title>\n  </head>\n  <body>\n    <h1>scorePick · your turn</h1>\n\n    <pre id=\"out\" style=\"font-family:ui-monospace,Menlo,monospace;font-size:13px;white-space:pre-wrap\"></pre>\n\n    <script>\n      // ─────────────────────────────────────────────────────────────────────\n      // scorePick()\n      // exact score              -> 5\n      // right result, wrong score -> 2\n      // wrong result             -> 0\n      // ─────────────────────────────────────────────────────────────────────\n\n      function scorePick(predicted, actual) {\n\n        // Exact score\n        if (\n          predicted.home === actual.home &&\n          predicted.away === actual.away\n        ) {\n          return 5;\n        }\n\n        // Determine predicted result\n        let predictedResult;\n        if (predicted.home > predicted.away) {\n          predictedResult = \"home\";\n        } else if (predicted.home < predicted.away) {\n          predictedResult = \"away\";\n        } else {\n          predictedResult = \"draw\";\n        }\n\n        // Determine actual result\n        let actualResult;\n        if (actual.home > actual.away) {\n          actualResult = \"home\";\n        } else if (actual.home < actual.away) {\n          actualResult = \"away\";\n        } else {\n          actualResult = \"draw\";\n        }\n\n        // Same result but different score\n        if (predictedResult === actualResult) {\n          return 2;\n        }\n\n        // Wrong result\n        return 0;\n      }\n\n      // Local sanity-check\n      const cases = [\n        { pred: { home: 2, away: 1 }, actual: { home: 2, away: 1 }, why: \"exact 2-1\" },\n        { pred: { home: 3, away: 0 }, actual: { home: 1, away: 0 }, why: \"home win, wrong score\" },\n        { pred: { home: 0, away: 1 }, actual: { home: 2, away: 0 }, why: \"wrong result\" },\n        { pred: { home: 1, away: 1 }, actual: { home: 2, away: 2 }, why: \"both draws\" },\n      ];\n\n      const out = document.getElementById(\"out\");\n\n      out.textContent = cases\n        .map(\n          c =>\n            `${c.pred.home}-${c.pred.away} vs ${c.actual.home}-${c.actual.away} -> ${scorePick(c.pred, c.actual)} // ${c.why}`\n        )\n        .join(\"\\n\");\n    </script>\n  </body>\n</html>","ranAt":"2026-07-26T14:00:29.759Z","passed":true,"attempt":1,"selfCheck":{"cases":[{"name":"exact 2-1 vs 2-1 returns 5","pass":true},{"name":"home win 3-0 vs 1-0 returns 2","pass":true},{"name":"wrong result 0-1 vs 2-0 returns 0","pass":true},{"name":"draw 1-1 vs 2-2 returns 2","pass":true}],"ranAt":"2026-07-26T14:00:29.759Z"}}

Example Compute Strengths

Meine Lösung
{"code":"<!doctype html>\n<html>\n<head><meta charset=\"utf-8\"><title>Worked example · computeStrengths</title></head>\n<body>\n\n<script>\n// ── A tiny sample ────────────────────────────────────────────────────────────\n// (same SHAPE as your real results; different teams + numbers on purpose).\nconst SAMPLE = [\n  { home: 'Japan',   away: 'Senegal', homeScore: 2, awayScore: 1 },\n  { home: 'Morocco', away: 'Japan',   homeScore: 0, awayScore: 2 },\n  { home: 'Senegal', away: 'Morocco', homeScore: 1, awayScore: 1 },\n];\n\n// ── computeStrengths ─────────────────────────────────────────────────────────\n// Two numbers per team: ATTACK = avg goals scored, DEFENSE = avg goals conceded.\nfunction computeStrengths(matches) {\n  // Step 1 — a running tally for every team: scored, conceded, games.\n  const tally = {};\n  const seed = (t) => { if (!tally[t]) tally[t] = { scored: 0, conceded: 0, games: 0 }; };\n\n  // Step 2 — every row touches BOTH teams. Home and away are mirror images.\n  for (const m of matches) {\n    seed(m.home); seed(m.away);\n    // home team: SCORED its own goals, CONCEDED the away goals.\n    tally[m.home].scored   += m.homeScore;\n    tally[m.home].conceded += m.awayScore;\n    tally[m.home].games    += 1;\n    // away team: the other way round.\n    tally[m.away].scored   += m.awayScore;\n    tally[m.away].conceded += m.homeScore;\n    tally[m.away].games    += 1;\n  }\n\n  // Step 3 — divide each total by games to get the two averages.\n  const table = {};\n  for (const team of Object.keys(tally)) {\n    const r = tally[team];\n    table[team] = { attack: r.scored / r.games, defense: r.conceded / r.games };\n  }\n  return table;\n}\n\n// ── The result ───────────────────────────────────────────────────────────────\nconst strengths = computeStrengths(SAMPLE);\nconsole.log(strengths.Japan);   //  →  { attack: 2, defense: 0.5 }\n</script>\n\n</body>\n</html>\n","ranAt":"2026-07-26T14:01:12.735Z"}

Act3 Compute Strength

Meine Lösung
{"passed":true,"attempt":1,"selfCheck":{"allPass":true,"failedNames":[]},"ranAt":"2026-07-26T14:04:07.867Z"}

Act3 House Bot

Meine Lösung
{"passed":true,"attempt":1,"selfCheck":{"allPass":true,"failedNames":[]},"ranAt":"2026-07-26T14:07:48.048Z"}

Act4 Leaderboard

Meine Lösung
{"ranAt":"2026-07-26T14:10:40.963Z","passed":false,"attempt":1}

Act5 Assemble

Meine Lösung
{"code":"<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>Predict the Cup — my World Cup prediction game</title>\n<style>\n  :root { --green:#00C65A; --ink:#0E1726; --soft:#3F4B5F; --faint:#6A7589; --line:#E4E8EE; --paper:#fff; --bg:#F4F7F6; }\n  * { box-sizing: border-box; }\n  body { font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif;\n         margin:0; background:var(--bg); color:var(--ink); }\n  .wrap { max-width: 760px; margin: 0 auto; padding: 22px 18px 40px; }\n  header { display:flex; align-items:center; gap:12px; margin-bottom:6px; }\n  .badge { width:42px; height:42px; border-radius:12px; background:var(--green); color:#fff;\n           display:flex; align-items:center; justify-content:center; font-weight:900; font-size:18px; }\n  h1 { font-size:21px; margin:0; letter-spacing:-0.01em; }\n  .tag { color:var(--faint); font-size:13px; margin:2px 0 18px; }\n  h2 { font-size:13px; text-transform:uppercase; letter-spacing:0.12em; color:var(--faint); margin:24px 0 12px; }\n  #board { display:grid; grid-template-columns:1fr; gap:12px; }\n  @media (min-width:560px){ #board { grid-template-columns:1fr 1fr; } }\n  .match { background:var(--paper); border:1px solid var(--line); border-radius:14px; padding:14px; }\n  .meta { color:var(--faint); font-size:10.5px; text-transform:uppercase; letter-spacing:0.12em; margin-bottom:8px; }\n  .teams { display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px; font-weight:800; font-size:15px; }\n  .teams .vs { color:var(--faint); font-weight:700; font-size:11px; }\n  .teams .away { text-align:right; }\n  .picks { display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px; margin-top:10px; }\n  .picks input { padding:10px; border:1px solid var(--line); border-radius:9px; text-align:center;\n                 font:inherit; font-weight:800; font-size:16px; width:100%; }\n  .picks input:focus { outline:2px solid var(--green); border-color:var(--green); }\n  .picks .dash { color:var(--faint); font-weight:800; text-align:center; }\n  .botline { margin-top:10px; font-size:12px; color:var(--soft); }\n  .botline b { color:var(--ink); font-variant-numeric:tabular-nums; }\n  .botline .prob { color:var(--faint); font-weight:600; }\n  .hint { color:var(--faint); font-size:12px; line-height:1.5; margin:8px 0 2px; max-width:560px; }\n  .challenge-banner { background:rgba(0,198,90,0.10); border:1px solid var(--green); border-radius:12px; padding:12px 14px; font-size:14px; font-weight:700; color:var(--ink); margin:14px 0 4px; }\n  .vs-friend { font-size:15px; font-weight:800; color:var(--green); margin-top:12px; }\n  .share-row { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-top:14px; }\n  .namebox { flex:1; min-width:150px; padding:11px 12px; border:1px solid var(--line); border-radius:10px; font:inherit; }\n  .namebox:focus { outline:2px solid var(--green); border-color:var(--green); }\n  .sharebtn { font:inherit; font-weight:800; color:#fff; background:var(--ink); border:0; border-radius:999px; padding:11px 18px; cursor:pointer; }\n  .sharebtn:hover { filter:brightness(1.15); }\n  .shareurl { width:100%; margin-top:8px; padding:9px 11px; border:1px solid var(--line); border-radius:8px; font-family:ui-monospace,Menlo,monospace; font-size:12px; color:var(--soft); }\n  .proov-credit { margin-top:12px; font-size:11.5px; }\n  .proov-credit a { color:var(--green); font-weight:800; text-decoration:none; }\n  .result { margin-top:10px; font-size:12px; font-weight:700; color:var(--green);\n            border-top:1px dashed var(--line); padding-top:9px; }\n  .scorebtn { margin-top:18px; font:inherit; font-weight:800; font-size:15px; color:#fff;\n              background:var(--green); border:0; border-radius:999px; padding:13px 22px; cursor:pointer; width:100%; }\n  @media (min-width:560px){ .scorebtn { width:auto; } }\n  .
…

Final Submission

Meine Lösung
{"url":"https://6a661cd1e57afd605733442c--tranquil-profiterole-f9d3a3.netlify.app","submittedAt":"2026-07-26T14:45:28.995Z"}
Verifiziertes ZertifikatFälschungssicher · ausgestellt von ProoV
Zertifiziert

Selbstgesteuertes Projekt

Energy and Renewable: Machine Learning for the Power Grid

Junior Machine Learning Engineer · KI / ML · Juli 2026

92/ 100

Built an end-to-end turbine yield predictor using leakage-free sensor inputs and a genuine time-based holdout. Trained and compared a LinearRegression baseline with a RandomForest model, then evaluated the final model on unseen later-period data with MAE, RMSE, R², and residual analysis. Authored a concise model card that explains intended use, excluded downstream emissions features, and the model’s operating limits.

Bewertet nach

  • Build and validate the model correctly35%
  • Optimize and evaluate honestly25%
  • Write the Model Card (clarity + honesty)25%
  • Explain it to a non-expert15%

Bestanden · Bestehensgrenze 60/100

Was herausstach6
  • Correctly excluded CO and NOx as downstream outputs and kept only the eight legitimate ambient/turbine sensor features.
  • Used an earlier-years train split and later-years test split, avoiding a random shuffle on time-ordered data.
  • Compared a LinearRegression baseline against a tuned RandomForest and reported MAE, RMSE, and R² on held-out data.
  • Read the residuals and explicitly identified heteroscedasticity as a real limitation.
  • Leakage-Free Feature Selection
  • Honest Held-Out Evaluation
Meine eingereichte Arbeit12 Aufgaben

Problem Frame

Meine Lösung
{"target":"TEY","taskType":"regression","metric":"mae","intendedUse":"Operation Team","passed":true,"attempt":1}

Leakage Flags

Meine Lösung
{"excluded":["TEY","CO","NOX"],"kept":["AT","AP","AH","AFDP","GTEP","TIT","TAT","CDP"],"passed":true,"attempt":1}

Train Validate Baseline

Meine Lösung
{"checkpointId":"turbine-baseline","code":"import pandas as pd\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn.metrics import mean_absolute_error, r2_score\n\ndf = pd.read_csv('gas_turbine.csv')\n\nfeatures = ['AT', 'AP', 'AH', 'AFDP', 'GTEP', 'TIT', 'TAT', 'CDP']\n\ntarget = 'TEY'\n\n# Train: 2011–2013\ntrain = df[df['year'] <= 2013]\n\n# Test: 2014–2015\ntest = df[df['year'] >= 2014]\n\nX_train, y_train = train[features], train[target]\nX_test, y_test = test[features], test[target]\n\nmodel = LinearRegression()\nmodel.fit(X_train, y_train)\npreds = model.predict(X_test)\n\nmae = mean_absolute_error(y_test, preds)\nr2 = r2_score(y_test, preds)\n\nprint(\"Baseline: Linear Regression\")\nprint(f\"MAE: {mae:.2f} MWh\")\nprint(f\"R2:  {r2:.3f}\")","stdout":"Baseline: Linear Regression\nMAE: 2.90 MWh\nR2:  0.957\n","stderr":"","error":null,"imageCount":0,"durationMs":22,"ranAt":"2026-07-26T06:19:14.696Z"}

Train Validate Forest

Meine Lösung
{"checkpointId":"turbine-forest","code":"import pandas as pd\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.metrics import mean_absolute_error, r2_score\n\n# Load dataset\ndf = pd.read_csv('gas_turbine.csv')\n\n# 8 legitimate input features\nfeatures = ['AT', 'AP', 'AH', 'AFDP', 'GTEP', 'TIT', 'TAT', 'CDP']\n\n# Target column\ntarget = 'TEY'\n\n# Time-based split\ntrain = df[df['year'] <= 2013]\ntest = df[df['year'] >= 2014]\n\n# Prepare training and testing data\nX_train = train[features]\ny_train = train[target]\n\nX_test = test[features]\ny_test = test[target]\n\n# ==========================\n# Step 1: Linear Regression\n# ==========================\nmodel = LinearRegression()\nmodel.fit(X_train, y_train)\n\npreds = model.predict(X_test)\n\nmae = mean_absolute_error(y_test, preds)\nr2 = r2_score(y_test, preds)\n\nprint(\"Baseline: Linear Regression\")\nprint(f\"MAE: {mae:.2f} MWh\")\nprint(f\"R2:  {r2:.3f}\")\n\n# ==========================\n# Step 2: Random Forest\n# ==========================\nmodel_rf = RandomForestRegressor(\n    n_estimators=120,\n    max_depth=12,\n    random_state=42\n)\n\nmodel_rf.fit(X_train, y_train)\n\npreds_rf = model_rf.predict(X_test)\n\nmae_rf = mean_absolute_error(y_test, preds_rf)\nr2_rf = r2_score(y_test, preds_rf)\n\nprint(\"\\nRandom Forest (n_estimators=120, max_depth=12)\")\nprint(f\"MAE: {mae_rf:.2f} MWh\")\nprint(f\"R2:  {r2_rf:.3f}\")\nprint(f\"Improvement vs baseline: {mae - mae_rf:.2f} MWh lower MAE\")","stdout":"Baseline: Linear Regression\nMAE: 2.90 MWh\nR2:  0.957\n\nRandom Forest (n_estimators=120, max_depth=12)\nMAE: 1.53 MWh\nR2:  0.983\nImprovement vs baseline: 1.37 MWh lower MAE\n","stderr":"","error":null,"imageCount":0,"durationMs":2217,"ranAt":"2026-07-26T06:19:49.875Z"}

Train Validate

Meine Lösung
{"baselinePassed":true,"baselineMae":2.9,"baselineR2":0.957,"rfPassed":true,"rfMae":2.9,"rfR2":0.957,"improvementMae":0}

Tune Evaluate Setup

Meine Lösung
{"checkpointId":"tune_evaluate_setup","code":"import pandas as pd\nimport numpy as np\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score\n\ndf = pd.read_csv('gas_turbine.csv')\n\nFEATURES = ['AT', 'AP', 'AH', 'AFDP', 'GTEP', 'TIT', 'TAT', 'CDP']\nTARGET = 'TEY'\n\n# Time-based split: train on the earlier years, lock the latest year away as test.\ntrain = df[df['year'] <= 2013]\ntest = df[df['year'] >= 2014]\n\nX_train, y_train = train[FEATURES], train[TARGET]\nX_test, y_test = test[FEATURES], test[TARGET]\n\n# These starter values are deliberately modest. Judge every change ONLY on the\n# held-out numbers printed below, never on how the model looks on training data.\nn_estimators = 120\nmax_depth = 12\n\nmodel = RandomForestRegressor(\n    n_estimators=n_estimators,\n    max_depth=max_depth,\n    random_state=42,\n)\nmodel.fit(X_train, y_train)\npreds = model.predict(X_test)\n\nmae = mean_absolute_error(y_test, preds)\nrmse = mean_squared_error(y_test, preds) ** 0.5\nr2 = r2_score(y_test, preds)\n\nprint(f\"n_estimators={n_estimators}  max_depth={max_depth}\")\nprint(f\"Held-out MAE:  {mae:.3f} MWh\")\nprint(f\"Held-out RMSE: {rmse:.3f}\")\nprint(f\"Held-out R2:   {r2:.4f}\")\n","stdout":"n_estimators=120  max_depth=12\nHeld-out MAE:  1.532 MWh\nHeld-out RMSE: 1.937\nHeld-out R2:   0.9833\n","stderr":"","error":null,"imageCount":0,"durationMs":2070,"ranAt":"2026-07-26T06:24:40.775Z"}

Tune Evaluate Residuals

Meine Lösung
{"checkpointId":"tune_evaluate_residuals","code":"preds = model.predict(X_test)\nresid = y_test.values - preds  # true TEY minus predicted TEY, in MWh\n\nprint(f\"Residual mean: {resid.mean():.3f} MWh\")\nprint(f\"Residual std:  {resid.std():.3f} MWh\")\n\n# A quick text histogram: how spread out are the misses across the held-out year?\ncounts, edges = np.histogram(resid, bins=8)\nfor c, lo, hi in zip(counts, edges[:-1], edges[1:]):\n    print(f\"{lo:6.2f} to {hi:6.2f} MWh | \" + \"#\" * c)\n","stdout":"Residual mean: 1.115 MWh\nResidual std:  1.583 MWh\n -8.48 to  -6.54 MWh | ##\n -6.54 to  -4.60 MWh | ##########\n -4.60 to  -2.66 MWh | ##################################\n -2.66 to  -0.71 MWh | #####################################################################################################################################################################################################################################################################################################################\n -0.71 to   1.23 MWh | #######################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################\n  1.23 to   3.17 MWh | ############################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################\n  3.17 to   5.12 MWh | ###########################
…

Tune Evaluate

Meine Lösung
{"nEstimators":120,"maxDepth":12,"heldOutMAE":1.532,"heldOutRMSE":1.937,"heldOutR2":0.9833,"residualMean":1.115,"residualStd":1.583}

Residual Read

Meine Lösung
{"category":"heteroscedastic","sentence":"The model performs well overall, but the residual plot shows heteroscedasticity, so the errors are not equally distributed across all predictions.","passed":true,"attempt":1}

Drift Monitor

Meine Lösung
{"monitorSignal":"distribution","retrainThreshold":4,"exploredDriftC":32,"observedMae":1.5}

Model Card

Meine Lösung
{"predicts":"Predicts Turbine Energy Yield (TEY) in MWh for the operations team to optimize turbine output.","features":"Features used: AT, AP, AH, AFDP, GTEP, TIT, TAT and CDP. CO and NOX were excluded because they are measured after the turbine produces its output and would not be available at prediction time.","accuracy":"Held-out MAE: 1.53 MWh, RMSE: 1.94 MWh, R²: 0.9833, measured on unseen test data from 2014–2015.","limits":"The model was trained on data from a single power plant and may not generalize to other plants or operating conditions. Residuals show larger errors at higher loads, so predictions outside the training range should not be trusted.","monitor":"Monitor held-out MAE, RMSE, R² and residuals over time. Retrain the model if prediction errors increase, data distribution changes, or new operating conditions appear.","hits":{"predicts":true,"features":true,"accuracy":true,"limits":true,"monitor":true},"passed":true,"attempt":1}

Teach Back

Meine Lösung
{"prompt":"Explain your model to the plant manager running tonight’s shift, not to another engineer. In plain words, address four things: what the model predicts, roughly how accurate it is, why you trust that number, and the one situation in which it would let the plant down.","summary":"This model predicts the turbine's energy output in megawatt-hours (MWh). On average, its prediction is about 1.5 MWh away from the actual value. I trust this result because we tested it on data the model had never seen before, not the data it was trained on. It may be less reliable if the turbine operates in conditions that were not included in the training data, such as unusually high loads or very different weather.","wordCount":74,"elementsHit":["predicts","accuracy","trust"],"jargonTerms":[],"passed":true,"attempt":1}
Verifiziertes ZertifikatFälschungssicher · ausgestellt von ProoV
2Abgeschlossene Projekte
2Verifizierte Zertifikate
88Durchschnittsnote
Erstelle dein Portfolio mit ProoV