[{"data":1,"prerenderedAt":1767},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-production-yield-and-scrap-report":3,"surround:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-production-yield-and-scrap-report":1732,"ancestors:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-production-yield-and-scrap-report":1741,"children:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-production-yield-and-scrap-report":1746,"related:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-production-yield-and-scrap-report":1747},{"id":4,"title":5,"body":6,"dateModified":1698,"datePublished":1698,"description":1699,"extension":1700,"faq":1701,"keyword":1710,"kind":1711,"meta":1712,"navigation":101,"path":1721,"seo":1722,"slug":1725,"stem":1726,"topics":1727,"type":1730,"__hash__":1731},"docs\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-production-yield-and-scrap-report\u002Findex.md","Build a Production Yield and Scrap Report",{"type":7,"value":8,"toc":1686},"minimark",[9,32,37,66,69,73,360,363,367,610,620,734,928,931,935,1179,1186,1190,1193,1197,1494,1501,1577,1581,1616,1620,1623,1627,1633,1639,1645,1651,1655,1682],[10,11,12,13,17,18,21,22,25,26,31],"p",{},"Every production line loses some of what it makes: parts that fail inspection and are scrapped, and parts that fail but can be reworked into good ones at extra cost. ",[14,15,16],"em",{},"Yield"," — the share of what went in that came out good — and ",[14,19,20],{},"scrap cost"," are the two numbers a production meeting looks at every week, and the conversation is always about ",[14,23,24],{},"why",": which line, which product, which shift, and above all which defect is costing the most. The data comes from production orders, usually exported from a shop-floor system or typed in by supervisors: quantity started, quantity good first time, quantity reworked, quantity scrapped and a reason code for the scrap. This page builds the report with pandas: checks that the recorded quantities add up, yield and first-pass yield by line, product and shift, scrap cost at standard cost, a Pareto of scrap reasons, and a weekly trend against target. It belongs to ",[27,28,30],"a",{"href":29},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002F","Building Finance and Operations Reports",".",[33,34,36],"h2",{"id":35},"prerequisites","Prerequisites",[38,39,44],"pre",{"className":40,"code":41,"language":42,"meta":43,"style":43},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[45,46,47],"code",{"__ignoreMap":43},[48,49,52,56,60,63],"span",{"class":50,"line":51},"line",1,[48,53,55],{"class":54},"sMTad","pip",[48,57,59],{"class":58},"srMev"," install",[48,61,62],{"class":58}," pandas",[48,64,65],{"class":58}," openpyxl\n",[10,67,68],{},"The export covers eight weeks of production orders on three moulding lines, two shifts a day, with the quantity started, good first time, reworked and scrapped, and the main reason for scrap on each order. A second sheet gives each product's standard cost, used to value the scrap. The yield target is 95%.",[33,70,72],{"id":71},"step-1-check-the-quantities-add-up","Step 1 — Check the quantities add up",[38,74,78],{"className":75,"code":76,"language":77,"meta":43,"style":43},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\npo = pd.read_excel(\"production_orders.xlsx\", parse_dates=[\"Date\"])\ncosts = pd.read_excel(\"standard_costs.xlsx\").set_index(\"Product\")[\"Standard cost\"]\n\npo[\"Accounted\"] = po[\"Good first time\"] + po[\"Reworked\"] + po[\"Scrapped\"]\nmismatch = po[po[\"Accounted\"] != po[\"Started\"]]\nprint(f\"{len(po)} orders; {len(mismatch)} where good + reworked + scrapped ≠ started\")\nprint(mismatch[[\"Order\", \"Date\", \"Line\", \"Started\", \"Good first time\", \"Reworked\", \"Scrapped\", \"Accounted\"]].to_string(index=False))\npo = po[po[\"Accounted\"] == po[\"Started\"]].copy()\n","python",[45,79,80,96,103,136,164,169,210,236,283,337],{"__ignoreMap":43},[48,81,82,86,90,93],{"class":50,"line":51},[48,83,85],{"class":84},"s-kum","import",[48,87,89],{"class":88},"skGVy"," pandas ",[48,91,92],{"class":84},"as",[48,94,95],{"class":88}," pd\n",[48,97,99],{"class":50,"line":98},2,[48,100,102],{"emptyLinePlaceholder":101},true,"\n",[48,104,106,109,112,115,118,121,125,127,130,133],{"class":50,"line":105},3,[48,107,108],{"class":88},"po ",[48,110,111],{"class":84},"=",[48,113,114],{"class":88}," pd.read_excel(",[48,116,117],{"class":58},"\"production_orders.xlsx\"",[48,119,120],{"class":88},", ",[48,122,124],{"class":123},"sa561","parse_dates",[48,126,111],{"class":84},[48,128,129],{"class":88},"[",[48,131,132],{"class":58},"\"Date\"",[48,134,135],{"class":88},"])\n",[48,137,139,142,144,146,149,152,155,158,161],{"class":50,"line":138},4,[48,140,141],{"class":88},"costs ",[48,143,111],{"class":84},[48,145,114],{"class":88},[48,147,148],{"class":58},"\"standard_costs.xlsx\"",[48,150,151],{"class":88},").set_index(",[48,153,154],{"class":58},"\"Product\"",[48,156,157],{"class":88},")[",[48,159,160],{"class":58},"\"Standard cost\"",[48,162,163],{"class":88},"]\n",[48,165,167],{"class":50,"line":166},5,[48,168,102],{"emptyLinePlaceholder":101},[48,170,172,175,178,181,183,186,189,191,194,196,199,201,203,205,208],{"class":50,"line":171},6,[48,173,174],{"class":88},"po[",[48,176,177],{"class":58},"\"Accounted\"",[48,179,180],{"class":88},"] ",[48,182,111],{"class":84},[48,184,185],{"class":88}," po[",[48,187,188],{"class":58},"\"Good first time\"",[48,190,180],{"class":88},[48,192,193],{"class":84},"+",[48,195,185],{"class":88},[48,197,198],{"class":58},"\"Reworked\"",[48,200,180],{"class":88},[48,202,193],{"class":84},[48,204,185],{"class":88},[48,206,207],{"class":58},"\"Scrapped\"",[48,209,163],{"class":88},[48,211,213,216,218,221,223,225,228,230,233],{"class":50,"line":212},7,[48,214,215],{"class":88},"mismatch ",[48,217,111],{"class":84},[48,219,220],{"class":88}," po[po[",[48,222,177],{"class":58},[48,224,180],{"class":88},[48,226,227],{"class":84},"!=",[48,229,185],{"class":88},[48,231,232],{"class":58},"\"Started\"",[48,234,235],{"class":88},"]]\n",[48,237,239,243,246,249,252,256,259,262,265,268,270,272,275,277,280],{"class":50,"line":238},8,[48,240,242],{"class":241},"sP0c6","print",[48,244,245],{"class":88},"(",[48,247,248],{"class":84},"f",[48,250,251],{"class":58},"\"",[48,253,255],{"class":254},"sSjpA","{",[48,257,258],{"class":241},"len",[48,260,261],{"class":88},"(po)",[48,263,264],{"class":254},"}",[48,266,267],{"class":58}," orders; ",[48,269,255],{"class":254},[48,271,258],{"class":241},[48,273,274],{"class":88},"(mismatch)",[48,276,264],{"class":254},[48,278,279],{"class":58}," where good + reworked + scrapped ≠ started\"",[48,281,282],{"class":88},")\n",[48,284,286,288,291,294,296,298,300,303,305,307,309,311,313,315,317,319,321,323,326,329,331,334],{"class":50,"line":285},9,[48,287,242],{"class":241},[48,289,290],{"class":88},"(mismatch[[",[48,292,293],{"class":58},"\"Order\"",[48,295,120],{"class":88},[48,297,132],{"class":58},[48,299,120],{"class":88},[48,301,302],{"class":58},"\"Line\"",[48,304,120],{"class":88},[48,306,232],{"class":58},[48,308,120],{"class":88},[48,310,188],{"class":58},[48,312,120],{"class":88},[48,314,198],{"class":58},[48,316,120],{"class":88},[48,318,207],{"class":58},[48,320,120],{"class":88},[48,322,177],{"class":58},[48,324,325],{"class":88},"]].to_string(",[48,327,328],{"class":123},"index",[48,330,111],{"class":84},[48,332,333],{"class":241},"False",[48,335,336],{"class":88},"))\n",[48,338,340,342,344,346,348,350,353,355,357],{"class":50,"line":339},10,[48,341,108],{"class":88},[48,343,111],{"class":84},[48,345,220],{"class":88},[48,347,177],{"class":58},[48,349,180],{"class":88},[48,351,352],{"class":84},"==",[48,354,185],{"class":88},[48,356,232],{"class":58},[48,358,359],{"class":88},"]].copy()\n",[10,361,362],{},"Every unit started must end up as good first time, reworked or scrapped, so the three must add up to the quantity started. When they do not, a count was mistyped or a batch was recorded twice, and every yield figure that includes the order is wrong. The check lists the orders that fail — here one order claims forty more good parts than could have been made — so a supervisor can correct them, and they are left out of the yield figures until then. Excluding them is better than including them, because a single inflated order can hide a real problem on a line.",[33,364,366],{"id":365},"step-2-yield-and-first-pass-yield-by-line-product-and-shift","Step 2 — Yield and first-pass yield by line, product and shift",[38,368,370],{"className":75,"code":369,"language":77,"meta":43,"style":43},"po[\"Good\"] = po[\"Good first time\"] + po[\"Reworked\"]\npo[\"Scrap cost\"] = po[\"Scrapped\"] * po[\"Product\"].map(costs)\n\ndef yields(g):\n    return pd.Series({\"Started\": g[\"Started\"].sum(), \"Yield %\": g[\"Good\"].sum() \u002F g[\"Started\"].sum() * 100,\n                      \"First-pass %\": g[\"Good first time\"].sum() \u002F g[\"Started\"].sum() * 100,\n                      \"Scrap cost\": g[\"Scrap cost\"].sum()})\n\nby_line = po.groupby(\"Line\").apply(yields, include_groups=False).round(1)\nby_line_shift = po.groupby([\"Line\", \"Shift\"]).apply(yields, include_groups=False)[\"Yield %\"].unstack().round(1)\nprint(by_line.to_string())\nprint(by_line_shift.to_string())\n",[45,371,372,397,424,428,440,486,511,523,527,557,594,602],{"__ignoreMap":43},[48,373,374,376,379,381,383,385,387,389,391,393,395],{"class":50,"line":51},[48,375,174],{"class":88},[48,377,378],{"class":58},"\"Good\"",[48,380,180],{"class":88},[48,382,111],{"class":84},[48,384,185],{"class":88},[48,386,188],{"class":58},[48,388,180],{"class":88},[48,390,193],{"class":84},[48,392,185],{"class":88},[48,394,198],{"class":58},[48,396,163],{"class":88},[48,398,399,401,404,406,408,410,412,414,417,419,421],{"class":50,"line":98},[48,400,174],{"class":88},[48,402,403],{"class":58},"\"Scrap cost\"",[48,405,180],{"class":88},[48,407,111],{"class":84},[48,409,185],{"class":88},[48,411,207],{"class":58},[48,413,180],{"class":88},[48,415,416],{"class":84},"*",[48,418,185],{"class":88},[48,420,154],{"class":58},[48,422,423],{"class":88},"].map(costs)\n",[48,425,426],{"class":50,"line":105},[48,427,102],{"emptyLinePlaceholder":101},[48,429,430,433,437],{"class":50,"line":138},[48,431,432],{"class":84},"def",[48,434,436],{"class":435},"s_Opv"," yields",[48,438,439],{"class":88},"(g):\n",[48,441,442,445,448,450,453,455,458,461,463,465,468,471,474,476,478,480,483],{"class":50,"line":166},[48,443,444],{"class":84},"    return",[48,446,447],{"class":88}," pd.Series({",[48,449,232],{"class":58},[48,451,452],{"class":88},": g[",[48,454,232],{"class":58},[48,456,457],{"class":88},"].sum(), ",[48,459,460],{"class":58},"\"Yield %\"",[48,462,452],{"class":88},[48,464,378],{"class":58},[48,466,467],{"class":88},"].sum() ",[48,469,470],{"class":84},"\u002F",[48,472,473],{"class":88}," g[",[48,475,232],{"class":58},[48,477,467],{"class":88},[48,479,416],{"class":84},[48,481,482],{"class":241}," 100",[48,484,485],{"class":88},",\n",[48,487,488,491,493,495,497,499,501,503,505,507,509],{"class":50,"line":171},[48,489,490],{"class":58},"                      \"First-pass %\"",[48,492,452],{"class":88},[48,494,188],{"class":58},[48,496,467],{"class":88},[48,498,470],{"class":84},[48,500,473],{"class":88},[48,502,232],{"class":58},[48,504,467],{"class":88},[48,506,416],{"class":84},[48,508,482],{"class":241},[48,510,485],{"class":88},[48,512,513,516,518,520],{"class":50,"line":212},[48,514,515],{"class":58},"                      \"Scrap cost\"",[48,517,452],{"class":88},[48,519,403],{"class":58},[48,521,522],{"class":88},"].sum()})\n",[48,524,525],{"class":50,"line":238},[48,526,102],{"emptyLinePlaceholder":101},[48,528,529,532,534,537,539,542,545,547,549,552,555],{"class":50,"line":285},[48,530,531],{"class":88},"by_line ",[48,533,111],{"class":84},[48,535,536],{"class":88}," po.groupby(",[48,538,302],{"class":58},[48,540,541],{"class":88},").apply(yields, ",[48,543,544],{"class":123},"include_groups",[48,546,111],{"class":84},[48,548,333],{"class":241},[48,550,551],{"class":88},").round(",[48,553,554],{"class":241},"1",[48,556,282],{"class":88},[48,558,559,562,564,567,569,571,574,577,579,581,583,585,587,590,592],{"class":50,"line":339},[48,560,561],{"class":88},"by_line_shift ",[48,563,111],{"class":84},[48,565,566],{"class":88}," po.groupby([",[48,568,302],{"class":58},[48,570,120],{"class":88},[48,572,573],{"class":58},"\"Shift\"",[48,575,576],{"class":88},"]).apply(yields, ",[48,578,544],{"class":123},[48,580,111],{"class":84},[48,582,333],{"class":241},[48,584,157],{"class":88},[48,586,460],{"class":58},[48,588,589],{"class":88},"].unstack().round(",[48,591,554],{"class":241},[48,593,282],{"class":88},[48,595,597,599],{"class":50,"line":596},11,[48,598,242],{"class":241},[48,600,601],{"class":88},"(by_line.to_string())\n",[48,603,605,607],{"class":50,"line":604},12,[48,606,242],{"class":241},[48,608,609],{"class":88},"(by_line_shift.to_string())\n",[10,611,612,613,615,616,619],{},"Two yields tell different stories. ",[14,614,16],{}," counts reworked parts as good — they shipped in the end — and is what determines how much material is lost. ",[14,617,618],{},"First-pass yield"," counts only parts that were right first time, and the gap between the two is the rework the line had to do, which costs labour even though it saves material. Both are calculated from summed quantities rather than by averaging each order's percentage, so large orders weigh more than small ones, as they should. Line 2 is clearly the weakest, and splitting it by shift shows where: its night shift yields several points lower than its day shift, while Lines 1 and 3 run about the same on both shifts. That points at something specific to Line 2 at night — set-up, staffing or a machine that runs hotter overnight — rather than at the product.",[621,622,630,631,630,635,630,639,630,647,630,657,630,664,630,669,630,674,630,679,630,683,630,688,630,692,630,696,630,699,630,704,630,709,630,713,630,717,630,720,630,725,630,730],"svg",{"viewBox":623,"role":624,"ariaLabelledBy":625,"xmlns":628,"style":629},"84 0 592 376","img",[626,627],"yield-defs-t","yield-defs-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:592px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[632,633,634],"title",{"id":626},"Where the started units go",[636,637,638],"desc",{"id":627},"Every unit started is good first time, reworked or scrapped. First-pass yield counts only the units good first time. Yield counts good first time plus reworked units. Scrap is what is left and is valued at standard cost.",[640,641],"rect",{"x":642,"y":643,"width":644,"height":645,"fill":646},"84","0","592","376","#ffffff",[640,648],{"x":649,"y":650,"width":651,"height":652,"rx":653,"fill":654,"stroke":655,"style":656},"100.0","16.0","560.0","59.0","12","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[658,659,663],"text",{"x":660,"y":661,"style":662},"380.0","41.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Good first time",[658,665,668],{"x":660,"y":666,"style":667},"61.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","first-pass yield",[50,670],{"x1":660,"y1":671,"x2":660,"y2":672,"stroke":673,"style":656},"80.0","102.0","var(--brand,#5b5cf0)",[675,676],"polygon",{"points":677,"fill":678},"380.0,106.0 375.0,97.0 385.0,97.0","#5b5cf0",[640,680],{"x":649,"y":681,"width":651,"height":652,"rx":653,"fill":682,"stroke":673,"style":656},"111.0","#f0f4ff",[658,684,687],{"x":660,"y":685,"style":686},"136.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","+ Reworked",[658,689,691],{"x":660,"y":690,"style":667},"156.0","= yield (good in the end)",[50,693],{"x1":660,"y1":694,"x2":660,"y2":695,"stroke":673,"style":656},"175.0","197.0",[675,697],{"points":698,"fill":678},"380.0,201.0 375.0,192.0 385.0,192.0",[640,700],{"x":649,"y":701,"width":651,"height":652,"rx":653,"fill":702,"stroke":703,"style":656},"206.0","#fce9e9","var(--danger,#dc2626)",[658,705,708],{"x":660,"y":706,"style":707},"231.5","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Scrapped",[658,710,712],{"x":660,"y":711,"style":667},"251.0","× standard cost = scrap cost",[50,714],{"x1":660,"y1":715,"x2":660,"y2":716,"stroke":673,"style":656},"270.0","292.0",[675,718],{"points":719,"fill":678},"380.0,296.0 375.0,287.0 385.0,287.0",[640,721],{"x":649,"y":722,"width":651,"height":652,"rx":653,"fill":723,"stroke":724,"style":656},"301.0","#e7ebef","var(--line,#cdd5e6)",[658,726,729],{"x":660,"y":727,"style":728},"326.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","= Started",[658,731,733],{"x":660,"y":732,"style":667},"346.0","must add up",[621,735,630,741,630,744,630,747,630,752,630,758,630,761,630,767,630,771,630,775,630,779,630,783,630,787,630,791,630,795,630,799,630,803,630,806,630,809,630,813,630,815,630,818,630,820,630,823,630,825,630,828,630,830,630,833,630,836,630,840,630,842,630,846,630,848,630,851,630,853,630,855,630,857,630,859,630,861,630,864,630,867,630,871,630,873,630,876,630,878,630,881,630,883,630,887,630,889,630,892,630,894,630,897,630,900,630,904,630,906,630,909,630,911,630,914,630,916,630,919,630,921,630,923,630,925],{"viewBox":736,"role":624,"ariaLabelledBy":737,"xmlns":628,"style":740},"154 0 451 168",[738,739],"yield-lines-t","yield-lines-d","width:100%;max-width:451px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[632,742,743],{"id":738},"Yield by line and shift",[636,745,746],{"id":739},"Line 1 yields 97.7 percent on both shifts. Line 2 yields 94.4 percent on days and 92.7 percent on nights, below the 95 percent target on both. Line 3 yields about 96 percent on both shifts. Line 2 has by far the highest scrap cost.",[640,748],{"x":749,"y":643,"width":750,"height":751,"fill":646},"154","451","168",[640,753],{"x":754,"y":650,"width":755,"height":756,"rx":643,"fill":723,"stroke":724,"style":757},"170.9","32.0","24.0","stroke-width:1px",[640,759],{"x":760,"y":650,"width":666,"height":756,"rx":643,"fill":723,"stroke":724,"style":757},"202.9",[658,762,766],{"x":763,"y":764,"style":765},"233.4","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[640,768],{"x":769,"y":650,"width":770,"height":756,"rx":643,"fill":723,"stroke":724,"style":757},"263.9","78.9",[658,772,774],{"x":773,"y":764,"style":765},"303.4","B",[640,776],{"x":777,"y":650,"width":778,"height":756,"rx":643,"fill":723,"stroke":724,"style":757},"342.8","88.4",[658,780,782],{"x":781,"y":764,"style":765},"387.0","C",[640,784],{"x":785,"y":650,"width":786,"height":756,"rx":643,"fill":723,"stroke":724,"style":757},"431.2","68.1",[658,788,790],{"x":789,"y":764,"style":765},"465.2","D",[640,792],{"x":793,"y":650,"width":794,"height":756,"rx":643,"fill":723,"stroke":724,"style":757},"499.3","89.8",[658,796,798],{"x":797,"y":764,"style":765},"544.2","E",[640,800],{"x":754,"y":801,"width":755,"height":802,"rx":643,"fill":723,"stroke":724,"style":757},"40.0","28.0",[658,804,554],{"x":805,"y":652,"style":765},"186.9",[640,807],{"x":760,"y":801,"width":666,"height":802,"rx":643,"fill":682,"stroke":673,"style":808},"stroke-width:1.5px",[658,810,812],{"x":763,"y":652,"style":811},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Line",[640,814],{"x":769,"y":801,"width":770,"height":802,"rx":643,"fill":682,"stroke":673,"style":808},[658,816,817],{"x":773,"y":652,"style":811},"Day shift",[640,819],{"x":777,"y":801,"width":778,"height":802,"rx":643,"fill":682,"stroke":673,"style":808},[658,821,822],{"x":781,"y":652,"style":811},"Night shift",[640,824],{"x":785,"y":801,"width":786,"height":802,"rx":643,"fill":682,"stroke":673,"style":808},[658,826,827],{"x":789,"y":652,"style":811},"Overall",[640,829],{"x":793,"y":801,"width":794,"height":802,"rx":643,"fill":682,"stroke":673,"style":808},[658,831,832],{"x":797,"y":652,"style":811},"Scrap cost",[640,834],{"x":754,"y":835,"width":755,"height":802,"rx":643,"fill":723,"stroke":724,"style":757},"68.0",[658,837,839],{"x":805,"y":838,"style":765},"87.0","2",[640,841],{"x":760,"y":835,"width":666,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,843,845],{"x":763,"y":838,"style":844},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Line 1",[640,847],{"x":769,"y":835,"width":770,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,849,850],{"x":773,"y":838,"style":844},"97.7%",[640,852],{"x":777,"y":835,"width":778,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,854,850],{"x":781,"y":838,"style":844},[640,856],{"x":785,"y":835,"width":786,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,858,850],{"x":789,"y":838,"style":844},[640,860],{"x":793,"y":835,"width":794,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,862,863],{"x":797,"y":838,"style":844},"£8,330",[640,865],{"x":754,"y":866,"width":755,"height":802,"rx":643,"fill":723,"stroke":724,"style":757},"96.0",[658,868,870],{"x":805,"y":869,"style":765},"115.0","3",[640,872],{"x":760,"y":866,"width":666,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,874,875],{"x":763,"y":869,"style":844},"Line 2",[640,877],{"x":769,"y":866,"width":770,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,879,880],{"x":773,"y":869,"style":844},"94.4%",[640,882],{"x":777,"y":866,"width":778,"height":802,"rx":643,"fill":702,"stroke":703,"style":808},[658,884,886],{"x":781,"y":869,"style":885},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","92.7%",[640,888],{"x":785,"y":866,"width":786,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,890,891],{"x":789,"y":869,"style":844},"93.6%",[640,893],{"x":793,"y":866,"width":794,"height":802,"rx":643,"fill":702,"stroke":703,"style":808},[658,895,896],{"x":797,"y":869,"style":885},"£23,438",[640,898],{"x":754,"y":899,"width":755,"height":802,"rx":643,"fill":723,"stroke":724,"style":757},"124.0",[658,901,903],{"x":805,"y":902,"style":765},"143.0","4",[640,905],{"x":760,"y":899,"width":666,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,907,908],{"x":763,"y":902,"style":844},"Line 3",[640,910],{"x":769,"y":899,"width":770,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,912,913],{"x":773,"y":902,"style":844},"96.0%",[640,915],{"x":777,"y":899,"width":778,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,917,918],{"x":781,"y":902,"style":844},"95.9%",[640,920],{"x":785,"y":899,"width":786,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,922,913],{"x":789,"y":902,"style":844},[640,924],{"x":793,"y":899,"width":794,"height":802,"rx":643,"fill":646,"stroke":724,"style":757},[658,926,927],{"x":797,"y":902,"style":844},"£16,477",[10,929,930],{},"In money, Line 2 scrapped £23,438 of product over the eight weeks, nearly three times Line 1's £8,330, even though the two lines started a similar number of parts. That figure, rather than the yield percentage, is usually what gets a problem onto the engineering team's list: at this rate the gap between Line 2 and Line 1 is worth close to £100,000 a year.",[33,932,934],{"id":933},"step-3-which-scrap-reasons-matter","Step 3 — Which scrap reasons matter?",[38,936,938],{"className":75,"code":937,"language":77,"meta":43,"style":43},"pareto = po.groupby(\"Scrap reason\").agg(units=(\"Scrapped\", \"sum\"), cost=(\"Scrap cost\", \"sum\")).sort_values(\"cost\", ascending=False)\npareto[\"Share\"] = pareto[\"cost\"] \u002F pareto[\"cost\"].sum()\npareto[\"Cumulative\"] = pareto[\"Share\"].cumsum()\nprint(pareto.assign(Share=pareto[\"Share\"].map(\"{:.0%}\".format), Cumulative=pareto[\"Cumulative\"].map(\"{:.0%}\".format)).round(0).to_string())\n\nby_line_reason = po.pivot_table(index=\"Line\", columns=\"Scrap reason\", values=\"Scrap cost\", aggfunc=\"sum\", fill_value=0).round(0)\nprint(by_line_reason.to_string())\n",[45,939,940,1002,1030,1048,1110,1114,1172],{"__ignoreMap":43},[48,941,942,945,947,949,952,955,958,960,962,964,966,969,972,975,977,979,981,983,985,988,991,993,996,998,1000],{"class":50,"line":51},[48,943,944],{"class":88},"pareto ",[48,946,111],{"class":84},[48,948,536],{"class":88},[48,950,951],{"class":58},"\"Scrap reason\"",[48,953,954],{"class":88},").agg(",[48,956,957],{"class":123},"units",[48,959,111],{"class":84},[48,961,245],{"class":88},[48,963,207],{"class":58},[48,965,120],{"class":88},[48,967,968],{"class":58},"\"sum\"",[48,970,971],{"class":88},"), ",[48,973,974],{"class":123},"cost",[48,976,111],{"class":84},[48,978,245],{"class":88},[48,980,403],{"class":58},[48,982,120],{"class":88},[48,984,968],{"class":58},[48,986,987],{"class":88},")).sort_values(",[48,989,990],{"class":58},"\"cost\"",[48,992,120],{"class":88},[48,994,995],{"class":123},"ascending",[48,997,111],{"class":84},[48,999,333],{"class":241},[48,1001,282],{"class":88},[48,1003,1004,1007,1010,1012,1014,1017,1019,1021,1023,1025,1027],{"class":50,"line":98},[48,1005,1006],{"class":88},"pareto[",[48,1008,1009],{"class":58},"\"Share\"",[48,1011,180],{"class":88},[48,1013,111],{"class":84},[48,1015,1016],{"class":88}," pareto[",[48,1018,990],{"class":58},[48,1020,180],{"class":88},[48,1022,470],{"class":84},[48,1024,1016],{"class":88},[48,1026,990],{"class":58},[48,1028,1029],{"class":88},"].sum()\n",[48,1031,1032,1034,1037,1039,1041,1043,1045],{"class":50,"line":105},[48,1033,1006],{"class":88},[48,1035,1036],{"class":58},"\"Cumulative\"",[48,1038,180],{"class":88},[48,1040,111],{"class":84},[48,1042,1016],{"class":88},[48,1044,1009],{"class":58},[48,1046,1047],{"class":88},"].cumsum()\n",[48,1049,1050,1052,1055,1058,1060,1062,1064,1067,1069,1071,1074,1076,1078,1081,1084,1086,1088,1090,1092,1094,1096,1098,1100,1102,1105,1107],{"class":50,"line":138},[48,1051,242],{"class":241},[48,1053,1054],{"class":88},"(pareto.assign(",[48,1056,1057],{"class":123},"Share",[48,1059,111],{"class":84},[48,1061,1006],{"class":88},[48,1063,1009],{"class":58},[48,1065,1066],{"class":88},"].map(",[48,1068,251],{"class":58},[48,1070,255],{"class":254},[48,1072,1073],{"class":84},":.0%",[48,1075,264],{"class":254},[48,1077,251],{"class":58},[48,1079,1080],{"class":88},".format), ",[48,1082,1083],{"class":123},"Cumulative",[48,1085,111],{"class":84},[48,1087,1006],{"class":88},[48,1089,1036],{"class":58},[48,1091,1066],{"class":88},[48,1093,251],{"class":58},[48,1095,255],{"class":254},[48,1097,1073],{"class":84},[48,1099,264],{"class":254},[48,1101,251],{"class":58},[48,1103,1104],{"class":88},".format)).round(",[48,1106,643],{"class":241},[48,1108,1109],{"class":88},").to_string())\n",[48,1111,1112],{"class":50,"line":166},[48,1113,102],{"emptyLinePlaceholder":101},[48,1115,1116,1119,1121,1124,1126,1128,1130,1132,1135,1137,1139,1141,1144,1146,1148,1150,1153,1155,1157,1159,1162,1164,1166,1168,1170],{"class":50,"line":171},[48,1117,1118],{"class":88},"by_line_reason ",[48,1120,111],{"class":84},[48,1122,1123],{"class":88}," po.pivot_table(",[48,1125,328],{"class":123},[48,1127,111],{"class":84},[48,1129,302],{"class":58},[48,1131,120],{"class":88},[48,1133,1134],{"class":123},"columns",[48,1136,111],{"class":84},[48,1138,951],{"class":58},[48,1140,120],{"class":88},[48,1142,1143],{"class":123},"values",[48,1145,111],{"class":84},[48,1147,403],{"class":58},[48,1149,120],{"class":88},[48,1151,1152],{"class":123},"aggfunc",[48,1154,111],{"class":84},[48,1156,968],{"class":58},[48,1158,120],{"class":88},[48,1160,1161],{"class":123},"fill_value",[48,1163,111],{"class":84},[48,1165,643],{"class":241},[48,1167,551],{"class":88},[48,1169,643],{"class":241},[48,1171,282],{"class":88},[48,1173,1174,1176],{"class":50,"line":212},[48,1175,242],{"class":241},[48,1177,1178],{"class":88},"(by_line_reason.to_string())\n",[10,1180,1181,1182,31],{},"Ranking scrap reasons by cost and adding a cumulative share gives the classic Pareto view: a couple of reasons — short shots and flash, both moulding faults — account for more than half the scrap cost, which tells the engineers where to look first. Ranking by cost rather than by units matters when products have different values: a defect that mostly affects the expensive housing can cost more than a more frequent one on a cheap bracket. The reason-by-line table adds the second dimension: Line 3's scrap is dominated by contamination, unlike the other two lines, which suggests a material-handling problem on that line rather than a moulding one. For the general technique, see ",[27,1183,1185],{"href":1184},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Frun-a-pareto-analysis-on-excel-data-with-pandas\u002F","Run a Pareto Analysis on Excel Data with pandas",[33,1187,1189],{"id":1188},"what-the-scrap-cost-leaves-out","What the scrap cost leaves out",[10,1191,1192],{},"Valuing scrap at standard cost captures the material and the machine time built into each scrapped part, which is what finance books as a scrap write-off. It does not capture everything a defect costs. Reworked parts are counted as good in the yield, but each one took extra labour to fix — the gap between yield and first-pass yield, 1.2 to 1.3 points on every line here, is hours of somebody's time. Scrap found late, after further processing or assembly, costs more than its standard cost at the moulding stage. And capacity used to make parts that are thrown away is capacity not available for orders. Adding a rework cost per unit, and valuing late-found scrap at the cost of the later stage, makes the report a better guide to where improvement pays, though the standard-cost figure remains the one that matches the accounts.",[33,1194,1196],{"id":1195},"step-4-weekly-trend-against-target-and-the-report","Step 4 — Weekly trend against target, and the report",[38,1198,1200],{"className":75,"code":1199,"language":77,"meta":43,"style":43},"TARGET = 95.0\npo[\"Week\"] = po[\"Date\"].dt.to_period(\"W-SUN\").dt.start_time            # a real date, so weeks sort in order\nweekly = po.groupby([\"Week\", \"Line\"]).apply(lambda g: g[\"Good\"].sum() \u002F g[\"Started\"].sum() * 100, include_groups=False).unstack().round(1)\nweekly.index = weekly.index.strftime(\"%d %b\")\nbelow = weekly.lt(TARGET)\nprint(weekly.to_string())\nprint(\"weeks below target:\", {line: list(weekly.index[below[line]]) for line in weekly.columns if below[line].any()})\n\nwith pd.ExcelWriter(\"yield_scrap_report.xlsx\") as xw:\n    by_line.to_excel(xw, sheet_name=\"By line\")\n    by_line_shift.to_excel(xw, sheet_name=\"Line x shift\")\n    pareto.to_excel(xw, sheet_name=\"Scrap reasons\")\n    by_line_reason.to_excel(xw, sheet_name=\"Reason x line\")\n    weekly.to_excel(xw, sheet_name=\"Weekly yield\")\n    mismatch.to_excel(xw, sheet_name=\"Records to correct\", index=False)\n",[45,1201,1202,1213,1241,1296,1318,1332,1339,1375,1379,1398,1413,1427,1441,1456,1471],{"__ignoreMap":43},[48,1203,1204,1207,1210],{"class":50,"line":51},[48,1205,1206],{"class":241},"TARGET",[48,1208,1209],{"class":84}," =",[48,1211,1212],{"class":241}," 95.0\n",[48,1214,1215,1217,1220,1222,1224,1226,1228,1231,1234,1237],{"class":50,"line":98},[48,1216,174],{"class":88},[48,1218,1219],{"class":58},"\"Week\"",[48,1221,180],{"class":88},[48,1223,111],{"class":84},[48,1225,185],{"class":88},[48,1227,132],{"class":58},[48,1229,1230],{"class":88},"].dt.to_period(",[48,1232,1233],{"class":58},"\"W-SUN\"",[48,1235,1236],{"class":88},").dt.start_time            ",[48,1238,1240],{"class":1239},"s-wDw","# a real date, so weeks sort in order\n",[48,1242,1243,1246,1248,1250,1252,1254,1256,1259,1262,1265,1267,1269,1271,1273,1275,1277,1279,1281,1283,1285,1287,1289,1292,1294],{"class":50,"line":105},[48,1244,1245],{"class":88},"weekly ",[48,1247,111],{"class":84},[48,1249,566],{"class":88},[48,1251,1219],{"class":58},[48,1253,120],{"class":88},[48,1255,302],{"class":58},[48,1257,1258],{"class":88},"]).apply(",[48,1260,1261],{"class":84},"lambda",[48,1263,1264],{"class":88}," g: g[",[48,1266,378],{"class":58},[48,1268,467],{"class":88},[48,1270,470],{"class":84},[48,1272,473],{"class":88},[48,1274,232],{"class":58},[48,1276,467],{"class":88},[48,1278,416],{"class":84},[48,1280,482],{"class":241},[48,1282,120],{"class":88},[48,1284,544],{"class":123},[48,1286,111],{"class":84},[48,1288,333],{"class":241},[48,1290,1291],{"class":88},").unstack().round(",[48,1293,554],{"class":241},[48,1295,282],{"class":88},[48,1297,1298,1301,1303,1306,1308,1311,1314,1316],{"class":50,"line":138},[48,1299,1300],{"class":88},"weekly.index ",[48,1302,111],{"class":84},[48,1304,1305],{"class":88}," weekly.index.strftime(",[48,1307,251],{"class":58},[48,1309,1310],{"class":254},"%d",[48,1312,1313],{"class":254}," %b",[48,1315,251],{"class":58},[48,1317,282],{"class":88},[48,1319,1320,1323,1325,1328,1330],{"class":50,"line":166},[48,1321,1322],{"class":88},"below ",[48,1324,111],{"class":84},[48,1326,1327],{"class":88}," weekly.lt(",[48,1329,1206],{"class":241},[48,1331,282],{"class":88},[48,1333,1334,1336],{"class":50,"line":171},[48,1335,242],{"class":241},[48,1337,1338],{"class":88},"(weekly.to_string())\n",[48,1340,1341,1343,1345,1348,1351,1354,1357,1360,1363,1366,1369,1372],{"class":50,"line":212},[48,1342,242],{"class":241},[48,1344,245],{"class":88},[48,1346,1347],{"class":58},"\"weeks below target:\"",[48,1349,1350],{"class":88},", {line: ",[48,1352,1353],{"class":241},"list",[48,1355,1356],{"class":88},"(weekly.index[below[line]]) ",[48,1358,1359],{"class":84},"for",[48,1361,1362],{"class":88}," line ",[48,1364,1365],{"class":84},"in",[48,1367,1368],{"class":88}," weekly.columns ",[48,1370,1371],{"class":84},"if",[48,1373,1374],{"class":88}," below[line].any()})\n",[48,1376,1377],{"class":50,"line":238},[48,1378,102],{"emptyLinePlaceholder":101},[48,1380,1381,1384,1387,1390,1393,1395],{"class":50,"line":285},[48,1382,1383],{"class":84},"with",[48,1385,1386],{"class":88}," pd.ExcelWriter(",[48,1388,1389],{"class":58},"\"yield_scrap_report.xlsx\"",[48,1391,1392],{"class":88},") ",[48,1394,92],{"class":84},[48,1396,1397],{"class":88}," xw:\n",[48,1399,1400,1403,1406,1408,1411],{"class":50,"line":339},[48,1401,1402],{"class":88},"    by_line.to_excel(xw, ",[48,1404,1405],{"class":123},"sheet_name",[48,1407,111],{"class":84},[48,1409,1410],{"class":58},"\"By line\"",[48,1412,282],{"class":88},[48,1414,1415,1418,1420,1422,1425],{"class":50,"line":596},[48,1416,1417],{"class":88},"    by_line_shift.to_excel(xw, ",[48,1419,1405],{"class":123},[48,1421,111],{"class":84},[48,1423,1424],{"class":58},"\"Line x shift\"",[48,1426,282],{"class":88},[48,1428,1429,1432,1434,1436,1439],{"class":50,"line":604},[48,1430,1431],{"class":88},"    pareto.to_excel(xw, ",[48,1433,1405],{"class":123},[48,1435,111],{"class":84},[48,1437,1438],{"class":58},"\"Scrap reasons\"",[48,1440,282],{"class":88},[48,1442,1444,1447,1449,1451,1454],{"class":50,"line":1443},13,[48,1445,1446],{"class":88},"    by_line_reason.to_excel(xw, ",[48,1448,1405],{"class":123},[48,1450,111],{"class":84},[48,1452,1453],{"class":58},"\"Reason x line\"",[48,1455,282],{"class":88},[48,1457,1459,1462,1464,1466,1469],{"class":50,"line":1458},14,[48,1460,1461],{"class":88},"    weekly.to_excel(xw, ",[48,1463,1405],{"class":123},[48,1465,111],{"class":84},[48,1467,1468],{"class":58},"\"Weekly yield\"",[48,1470,282],{"class":88},[48,1472,1474,1477,1479,1481,1484,1486,1488,1490,1492],{"class":50,"line":1473},15,[48,1475,1476],{"class":88},"    mismatch.to_excel(xw, ",[48,1478,1405],{"class":123},[48,1480,111],{"class":84},[48,1482,1483],{"class":58},"\"Records to correct\"",[48,1485,120],{"class":88},[48,1487,328],{"class":123},[48,1489,111],{"class":84},[48,1491,333],{"class":241},[48,1493,282],{"class":88},[10,1495,1496,1497,31],{},"A weekly yield per line, compared with the 95% target, shows whether a problem is constant or recent. Line 2 is below target every week — a persistent issue already visible in the totals — while Line 3, normally comfortably above target, drops below it in the last two weeks, which is the kind of new problem a monthly total would hide for weeks. Taken together with its contamination-heavy scrap, it suggests something changed on Line 3 in mid-September — a new batch of material, a change of granulate supplier, a dryer fault — and the date the dip began is exactly the information needed to find it. The report collects all of this: yield, first-pass yield and scrap cost by line, the line-by-shift yields, the Pareto of reasons, reasons by line, the weekly trend and the orders whose quantities need correcting. Conditional formatting that colours weekly yields below target red makes the trend sheet readable at a glance, as in ",[27,1498,1500],{"href":1499},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-values-outside-a-tolerance-of-target-with-openpyxl\u002F","Highlight Values Outside a Tolerance of Target with openpyxl",[621,1502,630,1508,630,1511,630,1514,630,1518,630,1524,630,1530,630,1535,630,1539,630,1543,630,1547,630,1551,630,1556,630,1561,630,1565,630,1568,630,1571,630,1574],{"viewBox":1503,"role":624,"ariaLabelledBy":1504,"xmlns":628,"style":1507},"4 0 752 199",[1505,1506],"yield-patterns-t","yield-patterns-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[632,1509,1510],{"id":1505},"A persistent problem and a new one",[636,1512,1513],{"id":1506},"Line 2 is below the 95 percent target every week, mostly on the night shift, with short shots and flash as the main scrap reasons, which points to a persistent process issue. Line 3 drops below target only in the last two weeks with contamination as its main reason, which points to something that changed recently.",[640,1515],{"x":903,"y":643,"width":1516,"height":1517,"fill":646},"752","199",[640,1519],{"x":1520,"y":650,"width":1521,"height":1522,"rx":1523,"fill":702,"stroke":703,"style":656},"20.0","351.0","167.0","14",[658,1525,1529],{"x":1526,"y":1527,"style":1528},"195.5","44.0","font-size:14px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Line 2 — persistent",[50,1531],{"x1":1532,"y1":1533,"x2":1534,"y2":1533,"stroke":703,"style":757},"36.0","57.0","355.0",[658,1536,1538],{"x":1526,"y":1537,"style":844},"77.0","below target every week",[658,1540,1542],{"x":1526,"y":1541,"style":844},"103.0","worst on night shift",[658,1544,1546],{"x":1526,"y":1545,"style":844},"129.0","short shots and flash",[658,1548,1550],{"x":1526,"y":1549,"style":844},"155.0","process or set-up issue",[640,1552],{"x":1553,"y":650,"width":1521,"height":1522,"rx":1523,"fill":1554,"stroke":1555,"style":656},"389.0","#fdefd8","var(--gold,#b4740a)",[658,1557,1560],{"x":1558,"y":1527,"style":1559},"564.5","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Line 3 — new",[50,1562],{"x1":1563,"y1":1533,"x2":1564,"y2":1533,"stroke":1555,"style":757},"405.0","724.0",[658,1566,1567],{"x":1558,"y":1537,"style":844},"below target last two weeks",[658,1569,1570],{"x":1558,"y":1541,"style":844},"both shifts",[658,1572,1573],{"x":1558,"y":1545,"style":844},"contamination",[658,1575,1576],{"x":1558,"y":1549,"style":844},"something changed recently",[33,1578,1580],{"id":1579},"common-pitfalls","Common pitfalls",[1582,1583,1584,1592,1598,1604,1610],"ul",{},[1585,1586,1587,1591],"li",{},[1588,1589,1590],"strong",{},"Quantities that do not add up."," Check good + reworked + scrapped = started and correct the records.",[1585,1593,1594,1597],{},[1588,1595,1596],{},"Averaging order percentages."," Sum quantities, then divide.",[1585,1599,1600,1603],{},[1588,1601,1602],{},"Only one yield figure."," Show first-pass yield too; the gap is rework.",[1585,1605,1606,1609],{},[1588,1607,1608],{},"Ranking scrap reasons by units."," Rank by cost when products differ in value.",[1585,1611,1612,1615],{},[1588,1613,1614],{},"Monthly totals only."," A weekly trend shows new problems while they are new.",[33,1617,1619],{"id":1618},"conclusion","Conclusion",[10,1621,1622],{},"A yield and scrap report starts by checking that every order's good, reworked and scrapped quantities add up to what was started. From the clean orders, sum quantities to get yield and first-pass yield by line, product and shift, value scrap at standard cost, rank scrap reasons by cost with a cumulative share, and compare weekly yields with the target. The combination separates persistent problems from new ones and points each at a likely cause.",[33,1624,1626],{"id":1625},"frequently-asked-questions","Frequently asked questions",[10,1628,1629,1632],{},[1588,1630,1631],{},"How do I calculate production yield in pandas?","\nSum good units (first time plus reworked) and units started for each group, and divide the totals.",[10,1634,1635,1638],{},[1588,1636,1637],{},"What is the difference between yield and first-pass yield?","\nYield counts reworked units as good; first-pass yield counts only units that were right the first time.",[10,1640,1641,1644],{},[1588,1642,1643],{},"How do I find the scrap reasons that cost the most?","\nSum scrap cost by reason, sort descending and add a cumulative share — a Pareto table.",[10,1646,1647,1650],{},[1588,1648,1649],{},"Why check that production quantities add up?","\nA mistyped count makes yield wrong for that order and can hide or invent a problem; exclude and correct such orders.",[33,1652,1654],{"id":1653},"related","Related",[1582,1656,1657,1663,1668,1675],{},[1585,1658,1659,1660,1662],{},"Up one level: ",[27,1661,30],{"href":29}," — finance and operations reports.",[1585,1664,1665,1667],{},[27,1666,1185],{"href":1184}," — Pareto in general.",[1585,1669,1670,1674],{},[27,1671,1673],{"href":1672},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-bill-of-materials-cost-rollup\u002F","Build a Bill of Materials Cost Rollup"," — the standard costs.",[1585,1676,1677,1681],{},[27,1678,1680],{"href":1679},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warranty-claims-report\u002F","Build a Warranty Claims Report"," — the defects that escape.",[1683,1684,1685],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":43,"searchDepth":98,"depth":98,"links":1687},[1688,1689,1690,1691,1692,1693,1694,1695,1696,1697],{"id":35,"depth":98,"text":36},{"id":71,"depth":98,"text":72},{"id":365,"depth":98,"text":366},{"id":933,"depth":98,"text":934},{"id":1188,"depth":98,"text":1189},{"id":1195,"depth":98,"text":1196},{"id":1579,"depth":98,"text":1580},{"id":1618,"depth":98,"text":1619},{"id":1625,"depth":98,"text":1626},{"id":1653,"depth":98,"text":1654},"2026-10-02","Turn production order records into a yield and scrap report with pandas: yield and first-pass yield per line, product and shift, scrap units and scrap cost at standard cost, a Pareto of scrap reasons showing the few that matter, weekly trends against a target, and checks that the recorded quantities add up — written to an Excel report for the production meeting.","md",[1702,1704,1706,1708],{"q":1631,"a":1703},"Sum good units (first time plus reworked) and units started for each group, and divide the totals.",{"q":1637,"a":1705},"Yield counts reworked units as good; first-pass yield counts only units that were right the first time.",{"q":1643,"a":1707},"Sum scrap cost by reason, sort descending and add a cumulative share — a Pareto table.",{"q":1649,"a":1709},"A mistyped count makes yield wrong for that order and can hide or invent a problem; exclude and correct such orders.","production yield scrap report python",null,{"breadcrumb":1713},[1714,1716,1719],{"name":1715,"item":470},"Home",{"name":1717,"item":1718},"Automating Reporting Workflows with Python and Excel","\u002Fautomating-reporting-workflows\u002F",{"name":1720,"item":29},"Building Finance and Operations Reports in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-production-yield-and-scrap-report",{"title":1723,"description":1724},"Build a Production Yield and Scrap Report with Python","Yield and scrap reporting with pandas: yield and first-pass yield by line and shift, scrap cost, Pareto of scrap reasons, weekly trend against target, quantity checks and an Excel report.","build-a-production-yield-and-scrap-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-production-yield-and-scrap-report\u002Findex",[1728,1729],"report-layouts","pandas","how-to","Q4Gh42tfTqJJ-L_fP-I1D-EH_Rdnp4xWZ0817gfz91A",[1733,1737],{"title":1734,"path":1735,"stem":1736,"children":-1},"Build a Product Margin Report","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-product-margin-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-product-margin-report\u002Findex",{"title":1738,"path":1739,"stem":1740,"children":-1},"Build a Profit and Loss Statement from a General Ledger","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-profit-and-loss-statement-from-a-general-ledger","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-profit-and-loss-statement-from-a-general-ledger\u002Findex",[1742,1744],{"path":1743,"title":1720},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports",{"path":1745,"title":1717},"\u002Fautomating-reporting-workflows",[],[1748,1752,1755,1758,1761,1764],{"path":1749,"title":1750,"kind":1751},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards","Building Multi-Sheet Excel Dashboards","guide",{"path":1753,"title":1754,"kind":1730},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-data-dictionary-sheet-to-an-excel-report","Add a Data Dictionary Sheet to an Excel Report",{"path":1756,"title":1757,"kind":1730},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-kpi-summary-block-to-an-excel-dashboard","Add a KPI Summary Block to an Excel Dashboard",{"path":1759,"title":1760,"kind":1730},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-table-of-contents-sheet-with-hyperlinks-in-excel","Add a Table of Contents Sheet with Hyperlinks in Excel",{"path":1762,"title":1763,"kind":1730},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-slicer-style-filters-to-an-excel-dashboard","Add a Dropdown Filter That Drives an Excel Dashboard",{"path":1765,"title":1766,"kind":1730},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-summary-sheet-to-excel-report-python","Add a Summary Sheet to an Excel Report with Python",1790972126157]