[{"data":1,"prerenderedAt":1944},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-returns-analysis-report":3,"surround:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-returns-analysis-report":1909,"ancestors:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-returns-analysis-report":1918,"children:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-returns-analysis-report":1923,"related:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-returns-analysis-report":1924},{"id":4,"title":5,"body":6,"dateModified":1875,"datePublished":1875,"description":1876,"extension":1877,"faq":1878,"keyword":1887,"kind":1888,"meta":1889,"navigation":88,"path":1898,"seo":1899,"slug":1902,"stem":1903,"topics":1904,"type":1907,"__hash__":1908},"docs\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-returns-analysis-report\u002Findex.md","Build a Returns Analysis Report",{"type":7,"value":8,"toc":1864},"minimark",[9,19,24,53,56,60,426,433,526,530,749,757,764,1025,1029,1386,1393,1610,1614,1746,1753,1757,1792,1796,1799,1803,1809,1815,1821,1827,1831,1860],[10,11,12,13,18],"p",{},"Returns cost twice: the refund, and the handling, shipping and stock write-offs that come with it. A returns report should say which products and channels are returned most, why, and whether things are getting better. The common spreadsheet version divides the returns booked in a month by the sales booked in the same month — and gets misleading answers, because a return in March usually belongs to a sale in February or January. When sales jump in November and the returns arrive in December, the November rate looks excellent and the December rate terrible, though nothing about the products changed. This page builds the analysis with pandas the right way round: each return is linked to its original sale, rates are calculated by the month of sale, products and channels are compared, reasons are ranked, the small set of products behind most refunds is found, and the most recent months are flagged as incomplete because their returns have not all arrived yet. It belongs to ",[14,15,17],"a",{"href":16},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002F","Building Finance and Operations Reports",".",[20,21,23],"h2",{"id":22},"prerequisites","Prerequisites",[25,26,31],"pre",{"className":27,"code":28,"language":29,"meta":30,"style":30},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47,50],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"sMTad","pip",[35,44,46],{"class":45},"srMev"," install",[35,48,49],{"class":45}," pandas",[35,51,52],{"class":45}," openpyxl\n",[10,54,55],{},"Two exports: sales lines from January to September 2026 with order number, date, product, channel and price, and returns with the order number they relate to, the date the return was received, the reason the customer gave and the refund. Each order here is a single item, which keeps the matching simple; with multi-line orders, match on order and line number instead. June had a large promotion.",[20,57,59],{"id":58},"step-1-link-each-return-to-its-sale","Step 1 — Link each return to its sale",[25,61,65],{"className":62,"code":63,"language":64,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nsales = pd.read_excel(\"sales.xlsx\", parse_dates=[\"Date\"])\nreturns = pd.read_excel(\"returns.xlsx\", parse_dates=[\"Return date\"])\n\nlinked = returns.merge(sales, on=\"Order\", how=\"left\", validate=\"one_to_one\", indicator=True)\nprint(\"returns without a matching sale:\", int((linked[\"_merge\"] != \"both\").sum()))\nlinked[\"Days to return\"] = (linked[\"Return date\"] - linked[\"Date\"]).dt.days\nprint(linked[\"Days to return\"].describe(percentiles=[0.5, 0.9]).round(1)[[\"mean\", \"50%\", \"90%\", \"max\"]].to_dict())\n\nsales[\"Sale month\"] = sales[\"Date\"].dt.to_period(\"M\")\nsales[\"Returned\"] = sales[\"Order\"].isin(returns[\"Order\"])\nsales = sales.merge(returns[[\"Order\", \"Reason\", \"Refund\"]], on=\"Order\", how=\"left\")\n","python",[32,66,67,83,90,123,149,154,207,242,273,331,336,362,385],{"__ignoreMap":30},[35,68,69,73,77,80],{"class":37,"line":38},[35,70,72],{"class":71},"s-kum","import",[35,74,76],{"class":75},"skGVy"," pandas ",[35,78,79],{"class":71},"as",[35,81,82],{"class":75}," pd\n",[35,84,86],{"class":37,"line":85},2,[35,87,89],{"emptyLinePlaceholder":88},true,"\n",[35,91,93,96,99,102,105,108,112,114,117,120],{"class":37,"line":92},3,[35,94,95],{"class":75},"sales ",[35,97,98],{"class":71},"=",[35,100,101],{"class":75}," pd.read_excel(",[35,103,104],{"class":45},"\"sales.xlsx\"",[35,106,107],{"class":75},", ",[35,109,111],{"class":110},"sa561","parse_dates",[35,113,98],{"class":71},[35,115,116],{"class":75},"[",[35,118,119],{"class":45},"\"Date\"",[35,121,122],{"class":75},"])\n",[35,124,126,129,131,133,136,138,140,142,144,147],{"class":37,"line":125},4,[35,127,128],{"class":75},"returns ",[35,130,98],{"class":71},[35,132,101],{"class":75},[35,134,135],{"class":45},"\"returns.xlsx\"",[35,137,107],{"class":75},[35,139,111],{"class":110},[35,141,98],{"class":71},[35,143,116],{"class":75},[35,145,146],{"class":45},"\"Return date\"",[35,148,122],{"class":75},[35,150,152],{"class":37,"line":151},5,[35,153,89],{"emptyLinePlaceholder":88},[35,155,157,160,162,165,168,170,173,175,178,180,183,185,188,190,193,195,198,200,204],{"class":37,"line":156},6,[35,158,159],{"class":75},"linked ",[35,161,98],{"class":71},[35,163,164],{"class":75}," returns.merge(sales, ",[35,166,167],{"class":110},"on",[35,169,98],{"class":71},[35,171,172],{"class":45},"\"Order\"",[35,174,107],{"class":75},[35,176,177],{"class":110},"how",[35,179,98],{"class":71},[35,181,182],{"class":45},"\"left\"",[35,184,107],{"class":75},[35,186,187],{"class":110},"validate",[35,189,98],{"class":71},[35,191,192],{"class":45},"\"one_to_one\"",[35,194,107],{"class":75},[35,196,197],{"class":110},"indicator",[35,199,98],{"class":71},[35,201,203],{"class":202},"sP0c6","True",[35,205,206],{"class":75},")\n",[35,208,210,213,216,219,221,224,227,230,233,236,239],{"class":37,"line":209},7,[35,211,212],{"class":202},"print",[35,214,215],{"class":75},"(",[35,217,218],{"class":45},"\"returns without a matching sale:\"",[35,220,107],{"class":75},[35,222,223],{"class":202},"int",[35,225,226],{"class":75},"((linked[",[35,228,229],{"class":45},"\"_merge\"",[35,231,232],{"class":75},"] ",[35,234,235],{"class":71},"!=",[35,237,238],{"class":45}," \"both\"",[35,240,241],{"class":75},").sum()))\n",[35,243,245,248,251,253,255,258,260,262,265,268,270],{"class":37,"line":244},8,[35,246,247],{"class":75},"linked[",[35,249,250],{"class":45},"\"Days to return\"",[35,252,232],{"class":75},[35,254,98],{"class":71},[35,256,257],{"class":75}," (linked[",[35,259,146],{"class":45},[35,261,232],{"class":75},[35,263,264],{"class":71},"-",[35,266,267],{"class":75}," linked[",[35,269,119],{"class":45},[35,271,272],{"class":75},"]).dt.days\n",[35,274,276,278,281,283,286,289,291,293,296,298,301,304,307,310,313,315,318,320,323,325,328],{"class":37,"line":275},9,[35,277,212],{"class":202},[35,279,280],{"class":75},"(linked[",[35,282,250],{"class":45},[35,284,285],{"class":75},"].describe(",[35,287,288],{"class":110},"percentiles",[35,290,98],{"class":71},[35,292,116],{"class":75},[35,294,295],{"class":202},"0.5",[35,297,107],{"class":75},[35,299,300],{"class":202},"0.9",[35,302,303],{"class":75},"]).round(",[35,305,306],{"class":202},"1",[35,308,309],{"class":75},")[[",[35,311,312],{"class":45},"\"mean\"",[35,314,107],{"class":75},[35,316,317],{"class":45},"\"50%\"",[35,319,107],{"class":75},[35,321,322],{"class":45},"\"90%\"",[35,324,107],{"class":75},[35,326,327],{"class":45},"\"max\"",[35,329,330],{"class":75},"]].to_dict())\n",[35,332,334],{"class":37,"line":333},10,[35,335,89],{"emptyLinePlaceholder":88},[35,337,339,342,345,347,349,352,354,357,360],{"class":37,"line":338},11,[35,340,341],{"class":75},"sales[",[35,343,344],{"class":45},"\"Sale month\"",[35,346,232],{"class":75},[35,348,98],{"class":71},[35,350,351],{"class":75}," sales[",[35,353,119],{"class":45},[35,355,356],{"class":75},"].dt.to_period(",[35,358,359],{"class":45},"\"M\"",[35,361,206],{"class":75},[35,363,365,367,370,372,374,376,378,381,383],{"class":37,"line":364},12,[35,366,341],{"class":75},[35,368,369],{"class":45},"\"Returned\"",[35,371,232],{"class":75},[35,373,98],{"class":71},[35,375,351],{"class":75},[35,377,172],{"class":45},[35,379,380],{"class":75},"].isin(returns[",[35,382,172],{"class":45},[35,384,122],{"class":75},[35,386,388,390,392,395,397,399,402,404,407,410,412,414,416,418,420,422,424],{"class":37,"line":387},13,[35,389,95],{"class":75},[35,391,98],{"class":71},[35,393,394],{"class":75}," sales.merge(returns[[",[35,396,172],{"class":45},[35,398,107],{"class":75},[35,400,401],{"class":45},"\"Reason\"",[35,403,107],{"class":75},[35,405,406],{"class":45},"\"Refund\"",[35,408,409],{"class":75},"]], ",[35,411,167],{"class":110},[35,413,98],{"class":71},[35,415,172],{"class":45},[35,417,107],{"class":75},[35,419,177],{"class":110},[35,421,98],{"class":71},[35,423,182],{"class":45},[35,425,206],{"class":75},[10,427,428,429,432],{},"Every return carries the order number of the sale it came from, so a merge brings the product, channel, price and sale date onto the return. Two checks belong here: ",[32,430,431],{},"validate=\"one_to_one\""," guarantees no order was returned twice or sold twice in the data, and the indicator column counts returns whose order cannot be found — usually returns of sales made before the period the export covers, which should be reported, not silently dropped. In this export every return matches a sale. The time from sale to return is worth seeing on its own: half of returns arrive within 16 days, but one in ten take more than 35 days, and the slowest here took 99. That lag is what makes the month of return a poor denominator, and it decides how long a month must age before its return rate is final. Flagging each sale as returned or not, with the reason and refund attached, gives one table that every view below is built from.",[434,435,443,444,443,448,443,452,443,460,443,470,443,477,443,483,443,488,443,492,443,496,443,500,443,505,443,510,443,514,443,517,443,520,443,523],"svg",{"viewBox":436,"role":437,"ariaLabelledBy":438,"xmlns":441,"style":442},"4 0 752 199","img",[439,440],"ret-denominator-t","ret-denominator-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[445,446,447],"title",{"id":439},"Return month or sale month",[449,450,451],"desc",{"id":440},"Dividing returns received in a month by sales made in that month mixes returns from earlier sales with the current month's sales, so promotions distort it. Dividing the returns of each month's sales by that month's sales measures the same customers' behaviour and is stable.",[453,454],"rect",{"x":455,"y":456,"width":457,"height":458,"fill":459},"4","0","752","199","#ffffff",[453,461],{"x":462,"y":463,"width":464,"height":465,"rx":466,"fill":467,"stroke":468,"style":469},"20.0","16.0","351.0","167.0","14","#fce9e9","var(--danger,#dc2626)","stroke-width:2px",[471,472,476],"text",{"x":473,"y":474,"style":475},"195.5","44.0","font-size:14px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Returns ÷ sales in the same month",[37,478],{"x1":479,"y1":480,"x2":481,"y2":480,"stroke":468,"style":482},"36.0","57.0","355.0","stroke-width:1px",[471,484,487],{"x":473,"y":485,"style":486},"77.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","returns belong to earlier sales",[471,489,491],{"x":473,"y":490,"style":486},"103.0","spikes after promotions",[471,493,495],{"x":473,"y":494,"style":486},"129.0","looks good in a big month",[471,497,499],{"x":473,"y":498,"style":486},"155.0","misleading trend",[453,501],{"x":502,"y":463,"width":464,"height":465,"rx":466,"fill":503,"stroke":504,"style":469},"389.0","#d9f4f1","var(--teal,#0f9488)",[471,506,509],{"x":507,"y":474,"style":508},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Returned share of each month's sales",[37,511],{"x1":512,"y1":480,"x2":513,"y2":480,"stroke":504,"style":482},"405.0","724.0",[471,515,516],{"x":507,"y":485,"style":486},"each return linked to its sale",[471,518,519],{"x":507,"y":490,"style":486},"same customers in numerator and denominator",[471,521,522],{"x":507,"y":494,"style":486},"stable across promotions",[471,524,525],{"x":507,"y":498,"style":486},"recent months still filling",[20,527,529],{"id":528},"step-2-return-rate-by-month-of-sale-with-immature-months-flagged","Step 2 — Return rate by month of sale, with immature months flagged",[25,531,533],{"className":62,"code":532,"language":64,"meta":30,"style":30},"by_month = sales.groupby(\"Sale month\").agg(sold=(\"Order\", \"size\"), returned=(\"Returned\", \"sum\"))\nby_month[\"Return rate\"] = (by_month[\"returned\"] \u002F by_month[\"sold\"]).round(3)\n\nnaive = (linked.groupby(linked[\"Return date\"].dt.to_period(\"M\")).size() \u002F sales.groupby(\"Sale month\").size()).round(3)\nby_month[\"Naive (by return month)\"] = naive\n\nlag_90 = linked[\"Days to return\"].quantile(0.9)\nperiod_end = pd.Timestamp(\"2026-09-30\")\nby_month[\"Mature\"] = (period_end - by_month.index.to_timestamp(how=\"end\")).days >= lag_90\nprint(by_month.to_string())\n",[32,534,535,584,620,624,656,670,674,692,707,742],{"__ignoreMap":30},[35,536,537,540,542,545,547,550,553,555,557,559,561,564,567,570,572,574,576,578,581],{"class":37,"line":38},[35,538,539],{"class":75},"by_month ",[35,541,98],{"class":71},[35,543,544],{"class":75}," sales.groupby(",[35,546,344],{"class":45},[35,548,549],{"class":75},").agg(",[35,551,552],{"class":110},"sold",[35,554,98],{"class":71},[35,556,215],{"class":75},[35,558,172],{"class":45},[35,560,107],{"class":75},[35,562,563],{"class":45},"\"size\"",[35,565,566],{"class":75},"), ",[35,568,569],{"class":110},"returned",[35,571,98],{"class":71},[35,573,215],{"class":75},[35,575,369],{"class":45},[35,577,107],{"class":75},[35,579,580],{"class":45},"\"sum\"",[35,582,583],{"class":75},"))\n",[35,585,586,589,592,594,596,599,602,604,607,610,613,615,618],{"class":37,"line":85},[35,587,588],{"class":75},"by_month[",[35,590,591],{"class":45},"\"Return rate\"",[35,593,232],{"class":75},[35,595,98],{"class":71},[35,597,598],{"class":75}," (by_month[",[35,600,601],{"class":45},"\"returned\"",[35,603,232],{"class":75},[35,605,606],{"class":71},"\u002F",[35,608,609],{"class":75}," by_month[",[35,611,612],{"class":45},"\"sold\"",[35,614,303],{"class":75},[35,616,617],{"class":202},"3",[35,619,206],{"class":75},[35,621,622],{"class":37,"line":92},[35,623,89],{"emptyLinePlaceholder":88},[35,625,626,629,631,634,636,638,640,643,645,647,649,652,654],{"class":37,"line":125},[35,627,628],{"class":75},"naive ",[35,630,98],{"class":71},[35,632,633],{"class":75}," (linked.groupby(linked[",[35,635,146],{"class":45},[35,637,356],{"class":75},[35,639,359],{"class":45},[35,641,642],{"class":75},")).size() ",[35,644,606],{"class":71},[35,646,544],{"class":75},[35,648,344],{"class":45},[35,650,651],{"class":75},").size()).round(",[35,653,617],{"class":202},[35,655,206],{"class":75},[35,657,658,660,663,665,667],{"class":37,"line":151},[35,659,588],{"class":75},[35,661,662],{"class":45},"\"Naive (by return month)\"",[35,664,232],{"class":75},[35,666,98],{"class":71},[35,668,669],{"class":75}," naive\n",[35,671,672],{"class":37,"line":156},[35,673,89],{"emptyLinePlaceholder":88},[35,675,676,679,681,683,685,688,690],{"class":37,"line":209},[35,677,678],{"class":75},"lag_90 ",[35,680,98],{"class":71},[35,682,267],{"class":75},[35,684,250],{"class":45},[35,686,687],{"class":75},"].quantile(",[35,689,300],{"class":202},[35,691,206],{"class":75},[35,693,694,697,699,702,705],{"class":37,"line":244},[35,695,696],{"class":75},"period_end ",[35,698,98],{"class":71},[35,700,701],{"class":75}," pd.Timestamp(",[35,703,704],{"class":45},"\"2026-09-30\"",[35,706,206],{"class":75},[35,708,709,711,714,716,718,721,723,726,728,730,733,736,739],{"class":37,"line":275},[35,710,588],{"class":75},[35,712,713],{"class":45},"\"Mature\"",[35,715,232],{"class":75},[35,717,98],{"class":71},[35,719,720],{"class":75}," (period_end ",[35,722,264],{"class":71},[35,724,725],{"class":75}," by_month.index.to_timestamp(",[35,727,177],{"class":110},[35,729,98],{"class":71},[35,731,732],{"class":45},"\"end\"",[35,734,735],{"class":75},")).days ",[35,737,738],{"class":71},">=",[35,740,741],{"class":75}," lag_90\n",[35,743,744,746],{"class":37,"line":333},[35,745,212],{"class":202},[35,747,748],{"class":75},"(by_month.to_string())\n",[10,750,751,752,756],{},"Grouping by the month of ",[753,754,755],"em",{},"sale"," answers the right question: of the items sold in March, what share came back? The naive version, returns received in a month divided by sales in that month, is shown next to it for comparison, and the difference is clearest around the June promotion. By month of sale, June's rate is 11.1%, in line with the other months, because the extra sales brought proportionally extra returns. By month of return, June looks unusually good at 9.1% — its large sales figure is divided into returns that mostly came from smaller May sales — and July looks bad at 13.7%, as June's returns arrive against normal July sales. January's naive rate of 4.3% is the extreme case: the export has no December sales, so the returns that would have come from them are missing altogether.",[10,758,759,760,763],{},"The most recent months carry a different caveat. September's sales have had at most thirty days to come back, and many returns take longer. A month is marked ",[753,761,762],{},"mature"," only once the time since its end is longer than the 90th percentile of the return lag — 35 days here, so August is not yet mature and September, at 4.9%, is far from it; before that its rate will still rise, and the report should say so instead of celebrating an apparent improvement.",[434,765,443,771,443,774,443,777,443,782,443,789,443,793,443,799,443,803,443,807,443,811,443,815,443,819,443,823,443,827,443,831,443,835,443,839,443,844,443,848,443,850,443,853,443,855,443,858,443,860,443,863,443,865,443,868,443,871,443,875,443,877,443,880,443,882,443,885,443,887,443,890,443,892,443,895,443,897,443,900,443,903,443,906,443,908,443,911,443,913,443,916,443,918,443,921,443,925,443,929,443,931,443,933,443,936,443,939,443,941,443,944,443,946,443,948,443,950,443,953,443,955,443,959,443,961,443,963,443,966,443,970,443,972,443,975,443,977,443,979,443,981,443,984,443,986,443,989,443,991,443,994,443,997,443,1001,443,1003,443,1006,443,1008,443,1010,443,1012,443,1016,443,1018,443,1021,443,1023],{"viewBox":766,"role":437,"ariaLabelledBy":767,"xmlns":441,"style":770},"102 0 556 224",[768,769],"ret-months-t","ret-months-d","width:100%;max-width:556px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[445,772,773],{"id":768},"Return rate by month of sale and by month of return",[449,775,776],{"id":769},"By month of sale the rate stays between about 10 and 14 percent, with June at 11.1 percent. By month of return June looks better at 9.1 percent and July worse at 13.7 percent. August and September are not yet mature, and September's 4.9 percent will rise.",[453,778],{"x":779,"y":456,"width":780,"height":781,"fill":459},"102","556","224",[453,783],{"x":784,"y":463,"width":785,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"118.2","32.0","24.0","#e7ebef","var(--line,#cdd5e6)",[453,790],{"x":791,"y":463,"width":792,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"150.2","130.7",[471,794,798],{"x":795,"y":796,"style":797},"215.6","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[453,800],{"x":801,"y":463,"width":802,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"280.9","58.5",[471,804,806],{"x":805,"y":796,"style":797},"310.1","B",[453,808],{"x":809,"y":463,"width":810,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"339.4","110.7",[471,812,814],{"x":813,"y":796,"style":797},"394.7","C",[453,816],{"x":817,"y":463,"width":818,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"450.1","123.5",[471,820,822],{"x":821,"y":796,"style":797},"511.9","D",[453,824],{"x":825,"y":463,"width":826,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"573.6","68.2",[471,828,830],{"x":829,"y":796,"style":797},"607.7","E",[453,832],{"x":784,"y":833,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},"40.0","28.0",[471,836,306],{"x":837,"y":838,"style":797},"134.2","59.0",[453,840],{"x":791,"y":833,"width":792,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},"#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[471,845,847],{"x":795,"y":838,"style":846},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Month",[453,849],{"x":801,"y":833,"width":802,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},[471,851,852],{"x":805,"y":838,"style":846},"Sold",[453,854],{"x":809,"y":833,"width":810,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},[471,856,857],{"x":813,"y":838,"style":846},"By sale month",[453,859],{"x":817,"y":833,"width":818,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},[471,861,862],{"x":821,"y":838,"style":846},"By return month",[453,864],{"x":825,"y":833,"width":826,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},[471,866,867],{"x":829,"y":838,"style":846},"Mature",[453,869],{"x":784,"y":870,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},"68.0",[471,872,874],{"x":837,"y":873,"style":797},"87.0","2",[453,876],{"x":791,"y":870,"width":792,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,878,879],{"x":795,"y":873,"style":486},"May",[453,881],{"x":801,"y":870,"width":802,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,883,884],{"x":805,"y":873,"style":486},"900",[453,886],{"x":809,"y":870,"width":810,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,888,889],{"x":813,"y":873,"style":486},"12.9%",[453,891],{"x":817,"y":870,"width":818,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,893,894],{"x":821,"y":873,"style":486},"13.6%",[453,896],{"x":825,"y":870,"width":826,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,898,899],{"x":829,"y":873,"style":486},"yes",[453,901],{"x":784,"y":902,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},"96.0",[471,904,617],{"x":837,"y":905,"style":797},"115.0",[453,907],{"x":791,"y":902,"width":792,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,909,910],{"x":795,"y":905,"style":486},"June (promotion)",[453,912],{"x":801,"y":902,"width":802,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,914,915],{"x":805,"y":905,"style":486},"1,500",[453,917],{"x":809,"y":902,"width":810,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,919,920],{"x":813,"y":905,"style":486},"11.1%",[453,922],{"x":817,"y":902,"width":818,"height":834,"rx":456,"fill":923,"stroke":924,"style":843},"#fdefd8","var(--gold,#b4740a)",[471,926,928],{"x":821,"y":905,"style":927},"font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","9.1%",[453,930],{"x":825,"y":902,"width":826,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,932,899],{"x":829,"y":905,"style":486},[453,934],{"x":784,"y":935,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},"124.0",[471,937,455],{"x":837,"y":938,"style":797},"143.0",[453,940],{"x":791,"y":935,"width":792,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,942,943],{"x":795,"y":938,"style":486},"July",[453,945],{"x":801,"y":935,"width":802,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,947,884],{"x":805,"y":938,"style":486},[453,949],{"x":809,"y":935,"width":810,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,951,952],{"x":813,"y":938,"style":486},"11.7%",[453,954],{"x":817,"y":935,"width":818,"height":834,"rx":456,"fill":467,"stroke":468,"style":843},[471,956,958],{"x":821,"y":938,"style":957},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","13.7%",[453,960],{"x":825,"y":935,"width":826,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,962,899],{"x":829,"y":938,"style":486},[453,964],{"x":784,"y":965,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},"152.0",[471,967,969],{"x":837,"y":968,"style":797},"171.0","5",[453,971],{"x":791,"y":965,"width":792,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,973,974],{"x":795,"y":968,"style":486},"August",[453,976],{"x":801,"y":965,"width":802,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,978,884],{"x":805,"y":968,"style":486},[453,980],{"x":809,"y":965,"width":810,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,982,983],{"x":813,"y":968,"style":486},"11.4%",[453,985],{"x":817,"y":965,"width":818,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,987,988],{"x":821,"y":968,"style":486},"14.1%",[453,990],{"x":825,"y":965,"width":826,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,992,993],{"x":829,"y":968,"style":486},"no",[453,995],{"x":784,"y":996,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},"180.0",[471,998,1000],{"x":837,"y":999,"style":797},"199.0","6",[453,1002],{"x":791,"y":996,"width":792,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1004,1005],{"x":795,"y":999,"style":486},"September",[453,1007],{"x":801,"y":996,"width":802,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1009,884],{"x":805,"y":999,"style":486},[453,1011],{"x":809,"y":996,"width":810,"height":834,"rx":456,"fill":787,"stroke":788,"style":843},[471,1013,1015],{"x":813,"y":999,"style":1014},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","4.9%",[453,1017],{"x":817,"y":996,"width":818,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1019,1020],{"x":821,"y":999,"style":486},"11.2%",[453,1022],{"x":825,"y":996,"width":826,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1024,993],{"x":829,"y":999,"style":486},[20,1026,1028],{"id":1027},"step-3-products-channels-and-reasons","Step 3 — Products, channels and reasons",[25,1030,1032],{"className":62,"code":1031,"language":64,"meta":30,"style":30},"mature_sales = sales[sales[\"Sale month\"].isin(by_month.index[by_month[\"Mature\"]])]\nby_product = mature_sales.groupby(\"Product\").agg(sold=(\"Order\", \"size\"), returned=(\"Returned\", \"sum\"), refunds=(\"Refund\", \"sum\"))\nby_product[\"Return rate\"] = (by_product[\"returned\"] \u002F by_product[\"sold\"]).round(3)\nby_product = by_product.sort_values(\"refunds\", ascending=False)\nby_product[\"Share of refunds\"] = (by_product[\"refunds\"] \u002F by_product[\"refunds\"].sum()).round(3)\nby_product[\"Cumulative share\"] = by_product[\"Share of refunds\"].cumsum().round(3)\nprint(by_product.to_string())\n\nrates = mature_sales.pivot_table(index=\"Product\", columns=\"Channel\", values=\"Returned\", aggfunc=\"mean\").round(3)\nprint(rates.to_string())\n\nreasons = mature_sales.dropna(subset=[\"Reason\"]).pivot_table(index=\"Product\", columns=\"Reason\", values=\"Order\", aggfunc=\"count\", fill_value=0)\nprint(reasons.div(reasons.sum(axis=1), axis=0).round(2).to_string())\n",[32,1033,1034,1054,1112,1143,1167,1197,1219,1226,1230,1282,1289,1293,1357],{"__ignoreMap":30},[35,1035,1036,1039,1041,1044,1046,1049,1051],{"class":37,"line":38},[35,1037,1038],{"class":75},"mature_sales ",[35,1040,98],{"class":71},[35,1042,1043],{"class":75}," sales[sales[",[35,1045,344],{"class":45},[35,1047,1048],{"class":75},"].isin(by_month.index[by_month[",[35,1050,713],{"class":45},[35,1052,1053],{"class":75},"]])]\n",[35,1055,1056,1059,1061,1064,1067,1069,1071,1073,1075,1077,1079,1081,1083,1085,1087,1089,1091,1093,1095,1097,1100,1102,1104,1106,1108,1110],{"class":37,"line":85},[35,1057,1058],{"class":75},"by_product ",[35,1060,98],{"class":71},[35,1062,1063],{"class":75}," mature_sales.groupby(",[35,1065,1066],{"class":45},"\"Product\"",[35,1068,549],{"class":75},[35,1070,552],{"class":110},[35,1072,98],{"class":71},[35,1074,215],{"class":75},[35,1076,172],{"class":45},[35,1078,107],{"class":75},[35,1080,563],{"class":45},[35,1082,566],{"class":75},[35,1084,569],{"class":110},[35,1086,98],{"class":71},[35,1088,215],{"class":75},[35,1090,369],{"class":45},[35,1092,107],{"class":75},[35,1094,580],{"class":45},[35,1096,566],{"class":75},[35,1098,1099],{"class":110},"refunds",[35,1101,98],{"class":71},[35,1103,215],{"class":75},[35,1105,406],{"class":45},[35,1107,107],{"class":75},[35,1109,580],{"class":45},[35,1111,583],{"class":75},[35,1113,1114,1117,1119,1121,1123,1126,1128,1130,1132,1135,1137,1139,1141],{"class":37,"line":92},[35,1115,1116],{"class":75},"by_product[",[35,1118,591],{"class":45},[35,1120,232],{"class":75},[35,1122,98],{"class":71},[35,1124,1125],{"class":75}," (by_product[",[35,1127,601],{"class":45},[35,1129,232],{"class":75},[35,1131,606],{"class":71},[35,1133,1134],{"class":75}," by_product[",[35,1136,612],{"class":45},[35,1138,303],{"class":75},[35,1140,617],{"class":202},[35,1142,206],{"class":75},[35,1144,1145,1147,1149,1152,1155,1157,1160,1162,1165],{"class":37,"line":125},[35,1146,1058],{"class":75},[35,1148,98],{"class":71},[35,1150,1151],{"class":75}," by_product.sort_values(",[35,1153,1154],{"class":45},"\"refunds\"",[35,1156,107],{"class":75},[35,1158,1159],{"class":110},"ascending",[35,1161,98],{"class":71},[35,1163,1164],{"class":202},"False",[35,1166,206],{"class":75},[35,1168,1169,1171,1174,1176,1178,1180,1182,1184,1186,1188,1190,1193,1195],{"class":37,"line":151},[35,1170,1116],{"class":75},[35,1172,1173],{"class":45},"\"Share of refunds\"",[35,1175,232],{"class":75},[35,1177,98],{"class":71},[35,1179,1125],{"class":75},[35,1181,1154],{"class":45},[35,1183,232],{"class":75},[35,1185,606],{"class":71},[35,1187,1134],{"class":75},[35,1189,1154],{"class":45},[35,1191,1192],{"class":75},"].sum()).round(",[35,1194,617],{"class":202},[35,1196,206],{"class":75},[35,1198,1199,1201,1204,1206,1208,1210,1212,1215,1217],{"class":37,"line":156},[35,1200,1116],{"class":75},[35,1202,1203],{"class":45},"\"Cumulative share\"",[35,1205,232],{"class":75},[35,1207,98],{"class":71},[35,1209,1134],{"class":75},[35,1211,1173],{"class":45},[35,1213,1214],{"class":75},"].cumsum().round(",[35,1216,617],{"class":202},[35,1218,206],{"class":75},[35,1220,1221,1223],{"class":37,"line":209},[35,1222,212],{"class":202},[35,1224,1225],{"class":75},"(by_product.to_string())\n",[35,1227,1228],{"class":37,"line":244},[35,1229,89],{"emptyLinePlaceholder":88},[35,1231,1232,1235,1237,1240,1243,1245,1247,1249,1252,1254,1257,1259,1262,1264,1266,1268,1271,1273,1275,1278,1280],{"class":37,"line":275},[35,1233,1234],{"class":75},"rates ",[35,1236,98],{"class":71},[35,1238,1239],{"class":75}," mature_sales.pivot_table(",[35,1241,1242],{"class":110},"index",[35,1244,98],{"class":71},[35,1246,1066],{"class":45},[35,1248,107],{"class":75},[35,1250,1251],{"class":110},"columns",[35,1253,98],{"class":71},[35,1255,1256],{"class":45},"\"Channel\"",[35,1258,107],{"class":75},[35,1260,1261],{"class":110},"values",[35,1263,98],{"class":71},[35,1265,369],{"class":45},[35,1267,107],{"class":75},[35,1269,1270],{"class":110},"aggfunc",[35,1272,98],{"class":71},[35,1274,312],{"class":45},[35,1276,1277],{"class":75},").round(",[35,1279,617],{"class":202},[35,1281,206],{"class":75},[35,1283,1284,1286],{"class":37,"line":333},[35,1285,212],{"class":202},[35,1287,1288],{"class":75},"(rates.to_string())\n",[35,1290,1291],{"class":37,"line":338},[35,1292,89],{"emptyLinePlaceholder":88},[35,1294,1295,1298,1300,1303,1306,1308,1310,1312,1315,1317,1319,1321,1323,1325,1327,1329,1331,1333,1335,1337,1339,1341,1343,1346,1348,1351,1353,1355],{"class":37,"line":364},[35,1296,1297],{"class":75},"reasons ",[35,1299,98],{"class":71},[35,1301,1302],{"class":75}," mature_sales.dropna(",[35,1304,1305],{"class":110},"subset",[35,1307,98],{"class":71},[35,1309,116],{"class":75},[35,1311,401],{"class":45},[35,1313,1314],{"class":75},"]).pivot_table(",[35,1316,1242],{"class":110},[35,1318,98],{"class":71},[35,1320,1066],{"class":45},[35,1322,107],{"class":75},[35,1324,1251],{"class":110},[35,1326,98],{"class":71},[35,1328,401],{"class":45},[35,1330,107],{"class":75},[35,1332,1261],{"class":110},[35,1334,98],{"class":71},[35,1336,172],{"class":45},[35,1338,107],{"class":75},[35,1340,1270],{"class":110},[35,1342,98],{"class":71},[35,1344,1345],{"class":45},"\"count\"",[35,1347,107],{"class":75},[35,1349,1350],{"class":110},"fill_value",[35,1352,98],{"class":71},[35,1354,456],{"class":202},[35,1356,206],{"class":75},[35,1358,1359,1361,1364,1367,1369,1371,1373,1375,1377,1379,1381,1383],{"class":37,"line":387},[35,1360,212],{"class":202},[35,1362,1363],{"class":75},"(reasons.div(reasons.sum(",[35,1365,1366],{"class":110},"axis",[35,1368,98],{"class":71},[35,1370,306],{"class":202},[35,1372,566],{"class":75},[35,1374,1366],{"class":110},[35,1376,98],{"class":71},[35,1378,456],{"class":202},[35,1380,1277],{"class":75},[35,1382,874],{"class":202},[35,1384,1385],{"class":75},").to_string())\n",[10,1387,1388,1389,1392],{},"Restricting the product, channel and reason views to mature months keeps the comparisons fair. Sorting products by refund value and adding a cumulative share shows the concentration that is typical of returns: three products — the dress, the jacket and the boots — account for 81.7% of the money refunded, the boots despite a below-average return rate because they are the most expensive item, so they are where effort pays off. The channel view shows that the same product is returned more from the marketplace than from the web shop, and much less when bought in a store, where customers can try it on: the dress comes back 27.4% of the time from the marketplace, 17.9% from the web and 9.1% from stores. The reason mix, as shares per product, points at the fix: the dress, jeans and boots are returned mostly for ",[753,1390,1391],{},"wrong size",", which calls for better size guidance on the product page, while the cheaper items are returned for a spread of reasons with no single cause.",[434,1394,443,1400,443,1403,443,1406,443,1411,443,1414,443,1418,443,1421,443,1425,443,1428,443,1432,443,1435,443,1439,443,1442,443,1444,443,1447,443,1449,443,1452,443,1454,443,1457,443,1459,443,1462,443,1464,443,1467,443,1469,443,1471,443,1473,443,1476,443,1478,443,1481,443,1483,443,1486,443,1488,443,1491,443,1493,443,1495,443,1497,443,1500,443,1502,443,1505,443,1507,443,1510,443,1512,443,1515,443,1517,443,1519,443,1521,443,1524,443,1526,443,1529,443,1531,443,1534,443,1536,443,1538,443,1540,443,1542,443,1544,443,1547,443,1549,443,1552,443,1554,443,1557,443,1559,443,1561,443,1563,443,1565,443,1567,443,1570,443,1572,443,1575,443,1577,443,1580,443,1582,443,1584,443,1587,443,1591,443,1593,443,1596,443,1598,443,1601,443,1603,443,1606,443,1608],{"viewBox":1395,"role":437,"ariaLabelledBy":1396,"xmlns":441,"style":1399},"151 0 457 252",[1397,1398],"ret-products-t","ret-products-d","width:100%;max-width:457px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[445,1401,1402],{"id":1397},"Products by refund value (mature months)",[449,1404,1405],{"id":1398},"The dress has the highest return rate, 19.5 percent, and the largest share of refunds, 29.2 percent, followed by the jacket and the boots. Together the top three account for 81.7 percent of refunded value, while T-shirts and scarves are rarely returned.",[453,1407],{"x":1408,"y":456,"width":1409,"height":1410,"fill":459},"151","457","252",[453,1412],{"x":1413,"y":463,"width":785,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"167.7",[453,1415],{"x":1416,"y":463,"width":1417,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"199.7","72.8",[471,1419,798],{"x":1420,"y":796,"style":797},"236.1",[453,1422],{"x":1423,"y":463,"width":1424,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"272.5","92.8",[471,1426,806],{"x":1427,"y":796,"style":797},"318.9",[453,1429],{"x":1430,"y":463,"width":1431,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"365.3","127.1",[471,1433,814],{"x":1434,"y":796,"style":797},"428.9",[453,1436],{"x":1437,"y":463,"width":1438,"height":786,"rx":456,"fill":787,"stroke":788,"style":482},"492.4","99.9",[471,1440,822],{"x":1441,"y":796,"style":797},"542.4",[453,1443],{"x":1413,"y":833,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},[471,1445,306],{"x":1446,"y":838,"style":797},"183.7",[453,1448],{"x":1416,"y":833,"width":1417,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},[471,1450,1451],{"x":1420,"y":838,"style":846},"Product",[453,1453],{"x":1423,"y":833,"width":1424,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},[471,1455,1456],{"x":1427,"y":838,"style":846},"Return rate",[453,1458],{"x":1430,"y":833,"width":1431,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},[471,1460,1461],{"x":1434,"y":838,"style":846},"Share of refunds",[453,1463],{"x":1437,"y":833,"width":1438,"height":834,"rx":456,"fill":841,"stroke":842,"style":843},[471,1465,1466],{"x":1441,"y":838,"style":846},"Main reason",[453,1468],{"x":1413,"y":870,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},[471,1470,874],{"x":1446,"y":873,"style":797},[453,1472],{"x":1416,"y":870,"width":1417,"height":834,"rx":456,"fill":467,"stroke":468,"style":843},[471,1474,1475],{"x":1420,"y":873,"style":957},"Dress",[453,1477],{"x":1423,"y":870,"width":1424,"height":834,"rx":456,"fill":467,"stroke":468,"style":843},[471,1479,1480],{"x":1427,"y":873,"style":957},"19.5%",[453,1482],{"x":1430,"y":870,"width":1431,"height":834,"rx":456,"fill":467,"stroke":468,"style":843},[471,1484,1485],{"x":1434,"y":873,"style":957},"29.2%",[453,1487],{"x":1437,"y":870,"width":1438,"height":834,"rx":456,"fill":467,"stroke":468,"style":843},[471,1489,1490],{"x":1441,"y":873,"style":957},"Wrong size",[453,1492],{"x":1413,"y":902,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},[471,1494,617],{"x":1446,"y":905,"style":797},[453,1496],{"x":1416,"y":902,"width":1417,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1498,1499],{"x":1420,"y":905,"style":486},"Jacket",[453,1501],{"x":1423,"y":902,"width":1424,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1503,1504],{"x":1427,"y":905,"style":486},"16.1%",[453,1506],{"x":1430,"y":902,"width":1431,"height":834,"rx":456,"fill":923,"stroke":924,"style":843},[471,1508,1509],{"x":1434,"y":905,"style":927},"28.3%",[453,1511],{"x":1437,"y":902,"width":1438,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1513,1514],{"x":1441,"y":905,"style":486},"mixed",[453,1516],{"x":1413,"y":935,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},[471,1518,455],{"x":1446,"y":938,"style":797},[453,1520],{"x":1416,"y":935,"width":1417,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1522,1523],{"x":1420,"y":938,"style":486},"Boots",[453,1525],{"x":1423,"y":935,"width":1424,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1527,1528],{"x":1427,"y":938,"style":486},"9.9%",[453,1530],{"x":1430,"y":935,"width":1431,"height":834,"rx":456,"fill":923,"stroke":924,"style":843},[471,1532,1533],{"x":1434,"y":938,"style":927},"24.2%",[453,1535],{"x":1437,"y":935,"width":1438,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1537,1490],{"x":1441,"y":938,"style":486},[453,1539],{"x":1413,"y":965,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},[471,1541,969],{"x":1446,"y":968,"style":797},[453,1543],{"x":1416,"y":965,"width":1417,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1545,1546],{"x":1420,"y":968,"style":486},"Jeans",[453,1548],{"x":1423,"y":965,"width":1424,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1550,1551],{"x":1427,"y":968,"style":486},"14.2%",[453,1553],{"x":1430,"y":965,"width":1431,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1555,1556],{"x":1434,"y":968,"style":486},"15.0%",[453,1558],{"x":1437,"y":965,"width":1438,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1560,1490],{"x":1441,"y":968,"style":486},[453,1562],{"x":1413,"y":996,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},[471,1564,1000],{"x":1446,"y":999,"style":797},[453,1566],{"x":1416,"y":996,"width":1417,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1568,1569],{"x":1420,"y":999,"style":486},"Scarf",[453,1571],{"x":1423,"y":996,"width":1424,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1573,1574],{"x":1427,"y":999,"style":486},"3.9%",[453,1576],{"x":1430,"y":996,"width":1431,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1578,1579],{"x":1434,"y":999,"style":486},"1.7%",[453,1581],{"x":1437,"y":996,"width":1438,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1583,1514],{"x":1441,"y":999,"style":486},[453,1585],{"x":1413,"y":1586,"width":785,"height":834,"rx":456,"fill":787,"stroke":788,"style":482},"208.0",[471,1588,1590],{"x":1446,"y":1589,"style":797},"227.0","7",[453,1592],{"x":1416,"y":1586,"width":1417,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1594,1595],{"x":1420,"y":1589,"style":486},"T-shirt",[453,1597],{"x":1423,"y":1586,"width":1424,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1599,1600],{"x":1427,"y":1589,"style":486},"5.0%",[453,1602],{"x":1430,"y":1586,"width":1431,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1604,1605],{"x":1434,"y":1589,"style":486},"1.6%",[453,1607],{"x":1437,"y":1586,"width":1438,"height":834,"rx":456,"fill":459,"stroke":788,"style":482},[471,1609,1514],{"x":1441,"y":1589,"style":486},[20,1611,1613],{"id":1612},"step-4-the-report","Step 4 — The report",[25,1615,1617],{"className":62,"code":1616,"language":64,"meta":30,"style":30},"with pd.ExcelWriter(\"returns_analysis_2026-09.xlsx\") as xw:\n    by_month.rename(index=str).to_excel(xw, sheet_name=\"By sale month\")\n    by_product.to_excel(xw, sheet_name=\"By product\")\n    rates.to_excel(xw, sheet_name=\"Product x channel\")\n    reasons.to_excel(xw, sheet_name=\"Reasons\")\n    linked.drop(columns=\"_merge\").to_excel(xw, sheet_name=\"Returns detail\", index=False)\nprint(\"written\")\n",[32,1618,1619,1638,1663,1677,1691,1705,1735],{"__ignoreMap":30},[35,1620,1621,1624,1627,1630,1633,1635],{"class":37,"line":38},[35,1622,1623],{"class":71},"with",[35,1625,1626],{"class":75}," pd.ExcelWriter(",[35,1628,1629],{"class":45},"\"returns_analysis_2026-09.xlsx\"",[35,1631,1632],{"class":75},") ",[35,1634,79],{"class":71},[35,1636,1637],{"class":75}," xw:\n",[35,1639,1640,1643,1645,1647,1650,1653,1656,1658,1661],{"class":37,"line":85},[35,1641,1642],{"class":75},"    by_month.rename(",[35,1644,1242],{"class":110},[35,1646,98],{"class":71},[35,1648,1649],{"class":202},"str",[35,1651,1652],{"class":75},").to_excel(xw, ",[35,1654,1655],{"class":110},"sheet_name",[35,1657,98],{"class":71},[35,1659,1660],{"class":45},"\"By sale month\"",[35,1662,206],{"class":75},[35,1664,1665,1668,1670,1672,1675],{"class":37,"line":92},[35,1666,1667],{"class":75},"    by_product.to_excel(xw, ",[35,1669,1655],{"class":110},[35,1671,98],{"class":71},[35,1673,1674],{"class":45},"\"By product\"",[35,1676,206],{"class":75},[35,1678,1679,1682,1684,1686,1689],{"class":37,"line":125},[35,1680,1681],{"class":75},"    rates.to_excel(xw, ",[35,1683,1655],{"class":110},[35,1685,98],{"class":71},[35,1687,1688],{"class":45},"\"Product x channel\"",[35,1690,206],{"class":75},[35,1692,1693,1696,1698,1700,1703],{"class":37,"line":151},[35,1694,1695],{"class":75},"    reasons.to_excel(xw, ",[35,1697,1655],{"class":110},[35,1699,98],{"class":71},[35,1701,1702],{"class":45},"\"Reasons\"",[35,1704,206],{"class":75},[35,1706,1707,1710,1712,1714,1716,1718,1720,1722,1725,1727,1729,1731,1733],{"class":37,"line":156},[35,1708,1709],{"class":75},"    linked.drop(",[35,1711,1251],{"class":110},[35,1713,98],{"class":71},[35,1715,229],{"class":45},[35,1717,1652],{"class":75},[35,1719,1655],{"class":110},[35,1721,98],{"class":71},[35,1723,1724],{"class":45},"\"Returns detail\"",[35,1726,107],{"class":75},[35,1728,1242],{"class":110},[35,1730,98],{"class":71},[35,1732,1164],{"class":202},[35,1734,206],{"class":75},[35,1736,1737,1739,1741,1744],{"class":37,"line":209},[35,1738,212],{"class":202},[35,1740,215],{"class":75},[35,1742,1743],{"class":45},"\"written\"",[35,1745,206],{"class":75},[10,1747,1748,1749,18],{},"The workbook starts with the monthly trend by sale month, with the immature months marked, then the product ranking with cumulative refund share, the product-by-channel rates, the reason mix and the linked detail. Refunds are only part of the cost of a return; if the business knows its average handling and shipping cost per return, adding it per product makes the ranking reflect the real cost and often moves cheap, frequently returned items up the list. A chart of the monthly rate with the immature months drawn differently — a lighter colour or a dashed line — prevents the most common misreading of a returns trend. To show both views of the trend side by side on a dashboard, see ",[14,1750,1752],{"href":1751},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcompare-two-periods-side-by-side-in-a-pivot\u002F","Compare Two Periods Side by Side in a Pivot",[20,1754,1756],{"id":1755},"common-pitfalls","Common pitfalls",[1758,1759,1760,1768,1774,1780,1786],"ul",{},[1761,1762,1763,1767],"li",{},[1764,1765,1766],"strong",{},"Dividing by sales in the return month."," Link returns to sales and rate by month of sale.",[1761,1769,1770,1773],{},[1764,1771,1772],{},"Reading recent months as final."," Flag months younger than the usual return lag.",[1761,1775,1776,1779],{},[1764,1777,1778],{},"Dropping unmatched returns."," Report returns whose sale is outside the data.",[1761,1781,1782,1785],{},[1764,1783,1784],{},"Ranking by rate alone."," Weigh by refund value; a high rate on a cheap item may not matter.",[1761,1787,1788,1791],{},[1764,1789,1790],{},"Ignoring channel."," The same product can have very different rates by channel.",[20,1793,1795],{"id":1794},"conclusion","Conclusion",[10,1797,1798],{},"A returns analysis that people can act on links every return to the sale it came from and measures return rates by the month of sale, flagging recent months whose returns are still arriving. From the linked table come the product ranking by refund value with its cumulative share, return rates by product and channel, and the reason mix per product — enough to show which few products cost the most and what would reduce their returns.",[20,1800,1802],{"id":1801},"frequently-asked-questions","Frequently asked questions",[10,1804,1805,1808],{},[1764,1806,1807],{},"How do I calculate a return rate correctly?","\nLink each return to its original sale and divide the number of returned items from each month's sales by that month's sales.",[10,1810,1811,1814],{},[1764,1812,1813],{},"Why does my return rate jump after a promotion?","\nReturns from the promotion arrive in later months; dividing them by those months' normal sales inflates the rate.",[10,1816,1817,1820],{},[1764,1818,1819],{},"How long until a month's return rate is final?","\nUntil more time has passed than nearly all returns take — for example the 90th percentile of days from sale to return.",[10,1822,1823,1826],{},[1764,1824,1825],{},"How do I find the products that cause most returns cost?","\nSum refund value by product, sort descending and add a cumulative share; the top few rows usually cover most of the cost.",[20,1828,1830],{"id":1829},"related","Related",[1758,1832,1833,1839,1846,1853],{},[1761,1834,1835,1836,1838],{},"Up one level: ",[14,1837,17],{"href":16}," — finance and operations reports.",[1761,1840,1841,1845],{},[14,1842,1844],{"href":1843},"\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"," — the few products that matter.",[1761,1847,1848,1852],{},[14,1849,1851],{"href":1850},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-cohort-retention-table-from-excel-data\u002F","Build a Cohort Retention Table from Excel Data"," — another analysis by starting month.",[1761,1854,1855,1859],{},[14,1856,1858],{"href":1857},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warranty-claims-report\u002F","Build a Warranty Claims Report"," — returns after the return window.",[1861,1862,1863],"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}",{"title":30,"searchDepth":85,"depth":85,"links":1865},[1866,1867,1868,1869,1870,1871,1872,1873,1874],{"id":22,"depth":85,"text":23},{"id":58,"depth":85,"text":59},{"id":528,"depth":85,"text":529},{"id":1027,"depth":85,"text":1028},{"id":1612,"depth":85,"text":1613},{"id":1755,"depth":85,"text":1756},{"id":1794,"depth":85,"text":1795},{"id":1801,"depth":85,"text":1802},{"id":1829,"depth":85,"text":1830},"2026-10-02","Analyse product returns properly with pandas: link each return to the sale it came from, calculate return rates by the month of sale rather than the month of return, compare products and channels, rank the reasons customers give, find the few products that cause most refund value, allow for returns still to come in recent months, and write the analysis to Excel.","md",[1879,1881,1883,1885],{"q":1807,"a":1880},"Link each return to its original sale and divide the number of returned items from each month's sales by that month's sales.",{"q":1813,"a":1882},"Returns from the promotion arrive in later months; dividing them by those months' normal sales inflates the rate.",{"q":1819,"a":1884},"Until more time has passed than nearly all returns take — for example the 90th percentile of days from sale to return.",{"q":1825,"a":1886},"Sum refund value by product, sort descending and add a cumulative share; the top few rows usually cover most of the cost.","returns analysis report python",null,{"breadcrumb":1890},[1891,1893,1896],{"name":1892,"item":606},"Home",{"name":1894,"item":1895},"Automating Reporting Workflows with Python and Excel","\u002Fautomating-reporting-workflows\u002F",{"name":1897,"item":16},"Building Finance and Operations Reports in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-returns-analysis-report",{"title":1900,"description":1901},"Build a Returns Analysis Report with Python and Excel","Returns analysis with pandas: return rate by sale month, by product and channel, top return reasons, the products behind most refunds, immature recent months and an Excel report.","build-a-returns-analysis-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-returns-analysis-report\u002Findex",[1905,1906],"report-layouts","pivots-and-summaries","how-to","7qP7eYNtuh4r6UIFbDB2VYbIjTbPlsCxDD1KkPaNfYE",[1910,1914],{"title":1911,"path":1912,"stem":1913,"children":-1},"Build a Purchase Order Tracking Report","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-purchase-order-tracking-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-purchase-order-tracking-report\u002Findex",{"title":1915,"path":1916,"stem":1917,"children":-1},"Build a Sales Commission Report with Python and Excel","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-sales-commission-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-sales-commission-report\u002Findex",[1919,1921],{"path":1920,"title":1897},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports",{"path":1922,"title":1894},"\u002Fautomating-reporting-workflows",[],[1925,1929,1932,1935,1938,1941],{"path":1926,"title":1927,"kind":1928},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards","Building Multi-Sheet Excel Dashboards","guide",{"path":1930,"title":1931,"kind":1907},"\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":1933,"title":1934,"kind":1907},"\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":1936,"title":1937,"kind":1907},"\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":1939,"title":1940,"kind":1907},"\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":1942,"title":1943,"kind":1907},"\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",1790972127186]