[{"data":1,"prerenderedAt":2637},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data":2604,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data":2613,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data":2618,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data":2619},{"id":4,"title":5,"body":6,"dateModified":2570,"datePublished":2570,"description":2571,"extension":2572,"faq":2573,"keyword":2582,"kind":2583,"meta":2584,"navigation":230,"path":2593,"seo":2594,"slug":2597,"stem":2598,"topics":2599,"type":2602,"__hash__":2603},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data\u002Findex.md","Build an RFM Customer Segmentation from Excel Data",{"type":7,"value":8,"toc":2557},"minimark",[9,19,24,56,62,195,199,202,489,496,500,507,591,594,832,835,958,961,965,968,1272,1275,1479,1483,1486,1696,1699,1818,1821,1825,1828,1912,1916,1919,2418,2425,2429,2477,2481,2487,2491,2497,2503,2509,2515,2519,2553],[10,11,12,13,18],"p",{},"RFM segmentation groups customers by three questions: how recently did they buy (recency), how often (frequency), and how much have they spent (monetary value). It needs nothing but an order history, it is easy to explain to a marketing team, and it produces lists people can act on: thank the best customers, win back the ones drifting away, stop discounting to people who would buy anyway. This page builds it from an Excel export with pandas and writes the segments back to Excel. It is part of ",[14,15,17],"a",{"href":16},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002F","Creating Pivot Tables from Excel Data",".",[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 xlsxwriter\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47,50,53],"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",[35,54,55],{"class":45}," xlsxwriter\n",[10,57,58,61],{},[32,59,60],{},"orders_24m.xlsx"," holds two years of orders, one row per order: order ID, customer ID, order date and amount. The analysis date is Monday 28 September 2026, the day after the last full week of data. Returns and cancelled orders should be removed before this point; they distort both frequency and value.",[63,64,72,73,72,77,72,81,72,89,72,99,72,110,72,117,72,123,72,128,72,132,72,136,72,141,72,148,72,153,72,157,72,160,72,163,72,166,72,171,72,178,72,183,72,187,72,190,72,192],"svg",{"viewBox":65,"role":66,"ariaLabelledBy":67,"xmlns":70,"style":71},"4 0 752 207","img",[68,69],"rfm-measures-t","rfm-measures-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  ",[74,75,76],"title",{"id":68},"Three numbers per customer",[78,79,80],"desc",{"id":69},"Three panels. Recency is the days since the customer's last order; fewer days is better. Frequency is the number of orders in the period; more is better. Monetary is the total spent in the period; more is better.",[82,83],"rect",{"x":84,"y":85,"width":86,"height":87,"fill":88},"4","0","752","207","#ffffff",[82,90],{"x":91,"y":92,"width":93,"height":94,"rx":95,"fill":96,"stroke":97,"style":98},"20.0","16.0","228.0","175.0","14","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[100,101,103],"g",{"transform":102},"translate(121.0,29.0) scale(1.083)",[104,105],"path",{"d":106,"fill":107,"stroke":108,"style":109},"M12 3a9 9 0 1 0 .01 0z M12 7v5l3.5 2","none","var(--brand-strong,#4338ca)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[111,112,116],"text",{"x":113,"y":114,"style":115},"134.0","78.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Recency",[37,118],{"x1":119,"y1":120,"x2":121,"y2":120,"stroke":97,"style":122},"36.0","91.0","232.0","stroke-width:1px",[111,124,127],{"x":113,"y":125,"style":126},"111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","days since last order",[111,129,131],{"x":113,"y":130,"style":126},"137.0","lower is better",[111,133,135],{"x":113,"y":134,"style":126},"163.0","the strongest predictor",[82,137],{"x":138,"y":92,"width":93,"height":94,"rx":95,"fill":139,"stroke":140,"style":98},"266.0","#d9f4f1","var(--teal,#0f9488)",[100,142,144],{"transform":143},"translate(367.0,29.0) scale(1.083)",[104,145],{"d":146,"fill":107,"stroke":147,"style":109},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7","var(--teal-ink,#0b6157)",[111,149,152],{"x":150,"y":114,"style":151},"380.0","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Frequency",[37,154],{"x1":155,"y1":120,"x2":156,"y2":120,"stroke":140,"style":122},"282.0","478.0",[111,158,159],{"x":150,"y":125,"style":126},"orders in the period",[111,161,162],{"x":150,"y":130,"style":126},"higher is better",[111,164,165],{"x":150,"y":134,"style":126},"habit",[82,167],{"x":168,"y":92,"width":93,"height":94,"rx":95,"fill":169,"stroke":170,"style":98},"512.0","#fdefd8","var(--gold,#b4740a)",[100,172,174],{"transform":173},"translate(613.0,29.0) scale(1.083)",[104,175],{"d":176,"fill":107,"stroke":177,"style":109},"M4 20h16 M7 17v-5 M12 17V7 M17 17v-8","var(--gold-ink,#7a4e06)",[111,179,182],{"x":180,"y":114,"style":181},"626.0","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Monetary",[37,184],{"x1":185,"y1":120,"x2":186,"y2":120,"stroke":170,"style":122},"528.0","724.0",[111,188,189],{"x":180,"y":125,"style":126},"total spent",[111,191,162],{"x":180,"y":130,"style":126},[111,193,194],{"x":180,"y":134,"style":126},"value",[20,196,198],{"id":197},"step-1-recency-frequency-and-monetary-per-customer","Step 1 — Recency, frequency and monetary per customer",[10,200,201],{},"One groupby produces all three. Recency is measured from the analysis date, not from today, so the analysis can be rerun as of any date:",[25,203,207],{"className":204,"code":205,"language":206,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\norders = pd.read_excel(\"orders_24m.xlsx\", parse_dates=[\"OrderDate\"])\nAS_OF = pd.Timestamp(\"2026-09-28\")\n\nrfm = orders.groupby(\"CustomerID\").agg(\n    LastOrder=(\"OrderDate\", \"max\"),\n    Frequency=(\"OrderID\", \"nunique\"),\n    Monetary=(\"Amount\", \"sum\"),\n)\nrfm[\"Recency\"] = (AS_OF - rfm[\"LastOrder\"]).dt.days\nprint(f\"{len(rfm)} customers\")\nprint(rfm[[\"Recency\", \"Frequency\", \"Monetary\"]].describe().round(1).loc[[\"min\", \"25%\", \"50%\", \"75%\", \"max\"]].to_string())\n","python",[32,208,209,225,232,265,284,289,306,327,347,367,372,403,435],{"__ignoreMap":30},[35,210,211,215,219,222],{"class":37,"line":38},[35,212,214],{"class":213},"s-kum","import",[35,216,218],{"class":217},"skGVy"," pandas ",[35,220,221],{"class":213},"as",[35,223,224],{"class":217}," pd\n",[35,226,228],{"class":37,"line":227},2,[35,229,231],{"emptyLinePlaceholder":230},true,"\n",[35,233,235,238,241,244,247,250,254,256,259,262],{"class":37,"line":234},3,[35,236,237],{"class":217},"orders ",[35,239,240],{"class":213},"=",[35,242,243],{"class":217}," pd.read_excel(",[35,245,246],{"class":45},"\"orders_24m.xlsx\"",[35,248,249],{"class":217},", ",[35,251,253],{"class":252},"sa561","parse_dates",[35,255,240],{"class":213},[35,257,258],{"class":217},"[",[35,260,261],{"class":45},"\"OrderDate\"",[35,263,264],{"class":217},"])\n",[35,266,268,272,275,278,281],{"class":37,"line":267},4,[35,269,271],{"class":270},"sP0c6","AS_OF",[35,273,274],{"class":213}," =",[35,276,277],{"class":217}," pd.Timestamp(",[35,279,280],{"class":45},"\"2026-09-28\"",[35,282,283],{"class":217},")\n",[35,285,287],{"class":37,"line":286},5,[35,288,231],{"emptyLinePlaceholder":230},[35,290,292,295,297,300,303],{"class":37,"line":291},6,[35,293,294],{"class":217},"rfm ",[35,296,240],{"class":213},[35,298,299],{"class":217}," orders.groupby(",[35,301,302],{"class":45},"\"CustomerID\"",[35,304,305],{"class":217},").agg(\n",[35,307,309,312,314,317,319,321,324],{"class":37,"line":308},7,[35,310,311],{"class":252},"    LastOrder",[35,313,240],{"class":213},[35,315,316],{"class":217},"(",[35,318,261],{"class":45},[35,320,249],{"class":217},[35,322,323],{"class":45},"\"max\"",[35,325,326],{"class":217},"),\n",[35,328,330,333,335,337,340,342,345],{"class":37,"line":329},8,[35,331,332],{"class":252},"    Frequency",[35,334,240],{"class":213},[35,336,316],{"class":217},[35,338,339],{"class":45},"\"OrderID\"",[35,341,249],{"class":217},[35,343,344],{"class":45},"\"nunique\"",[35,346,326],{"class":217},[35,348,350,353,355,357,360,362,365],{"class":37,"line":349},9,[35,351,352],{"class":252},"    Monetary",[35,354,240],{"class":213},[35,356,316],{"class":217},[35,358,359],{"class":45},"\"Amount\"",[35,361,249],{"class":217},[35,363,364],{"class":45},"\"sum\"",[35,366,326],{"class":217},[35,368,370],{"class":37,"line":369},10,[35,371,283],{"class":217},[35,373,375,378,381,384,386,389,391,394,397,400],{"class":37,"line":374},11,[35,376,377],{"class":217},"rfm[",[35,379,380],{"class":45},"\"Recency\"",[35,382,383],{"class":217},"] ",[35,385,240],{"class":213},[35,387,388],{"class":217}," (",[35,390,271],{"class":270},[35,392,393],{"class":213}," -",[35,395,396],{"class":217}," rfm[",[35,398,399],{"class":45},"\"LastOrder\"",[35,401,402],{"class":217},"]).dt.days\n",[35,404,406,409,411,414,417,421,424,427,430,433],{"class":37,"line":405},12,[35,407,408],{"class":270},"print",[35,410,316],{"class":217},[35,412,413],{"class":213},"f",[35,415,416],{"class":45},"\"",[35,418,420],{"class":419},"sSjpA","{",[35,422,423],{"class":270},"len",[35,425,426],{"class":217},"(rfm)",[35,428,429],{"class":419},"}",[35,431,432],{"class":45}," customers\"",[35,434,283],{"class":217},[35,436,438,440,443,445,447,450,452,455,458,461,464,467,469,472,474,477,479,482,484,486],{"class":37,"line":437},13,[35,439,408],{"class":270},[35,441,442],{"class":217},"(rfm[[",[35,444,380],{"class":45},[35,446,249],{"class":217},[35,448,449],{"class":45},"\"Frequency\"",[35,451,249],{"class":217},[35,453,454],{"class":45},"\"Monetary\"",[35,456,457],{"class":217},"]].describe().round(",[35,459,460],{"class":270},"1",[35,462,463],{"class":217},").loc[[",[35,465,466],{"class":45},"\"min\"",[35,468,249],{"class":217},[35,470,471],{"class":45},"\"25%\"",[35,473,249],{"class":217},[35,475,476],{"class":45},"\"50%\"",[35,478,249],{"class":217},[35,480,481],{"class":45},"\"75%\"",[35,483,249],{"class":217},[35,485,323],{"class":45},[35,487,488],{"class":217},"]].to_string())\n",[10,490,491,492,495],{},"Frequency counts distinct orders, not rows: if the export has one row per order line, ",[32,493,494],{},"nunique"," on the order ID stops a five-line order counting as five purchases.",[20,497,499],{"id":498},"step-2-score-each-measure-from-1-to-5","Step 2 — Score each measure from 1 to 5",[10,501,502,503,506],{},"Scores put the three measures on the same scale: each customer gets 1 to 5 by quintile, with 5 the best. Recency is reversed, since fewer days is better. The trap is frequency: with many customers on one or two orders, the quintile boundaries coincide and ",[32,504,505],{},"pd.qcut"," raises an error about duplicate bin edges:",[25,508,510],{"className":204,"code":509,"language":206,"meta":30,"style":30},"try:\n    pd.qcut(rfm[\"Frequency\"], 5, labels=[1, 2, 3, 4, 5])\nexcept ValueError as e:\n    print(\"qcut failed:\", e)\n",[32,511,512,520,564,578],{"__ignoreMap":30},[35,513,514,517],{"class":37,"line":38},[35,515,516],{"class":213},"try",[35,518,519],{"class":217},":\n",[35,521,522,525,527,530,533,535,538,540,542,544,546,549,551,554,556,558,560,562],{"class":37,"line":227},[35,523,524],{"class":217},"    pd.qcut(rfm[",[35,526,449],{"class":45},[35,528,529],{"class":217},"], ",[35,531,532],{"class":270},"5",[35,534,249],{"class":217},[35,536,537],{"class":252},"labels",[35,539,240],{"class":213},[35,541,258],{"class":217},[35,543,460],{"class":270},[35,545,249],{"class":217},[35,547,548],{"class":270},"2",[35,550,249],{"class":217},[35,552,553],{"class":270},"3",[35,555,249],{"class":217},[35,557,84],{"class":270},[35,559,249],{"class":217},[35,561,532],{"class":270},[35,563,264],{"class":217},[35,565,566,569,572,575],{"class":37,"line":234},[35,567,568],{"class":213},"except",[35,570,571],{"class":270}," ValueError",[35,573,574],{"class":213}," as",[35,576,577],{"class":217}," e:\n",[35,579,580,583,585,588],{"class":37,"line":267},[35,581,582],{"class":270},"    print",[35,584,316],{"class":217},[35,586,587],{"class":45},"\"qcut failed:\"",[35,589,590],{"class":217},", e)\n",[10,592,593],{},"Ranking first gives every customer a distinct position, so the bins are always equal-sized. Customers with the same frequency can land in adjacent scores; that is the price of equal groups, and the usual choice:",[25,595,597],{"className":204,"code":596,"language":206,"meta":30,"style":30},"def score(series, higher_is_better=True):\n    ranked = series.rank(method=\"first\", ascending=higher_is_better)\n    return pd.qcut(ranked, 5, labels=[1, 2, 3, 4, 5]).astype(int)\n\nrfm[\"R\"] = score(rfm[\"Recency\"], higher_is_better=False)\nrfm[\"F\"] = score(rfm[\"Frequency\"])\nrfm[\"M\"] = score(rfm[\"Monetary\"])\nrfm[\"RFM\"] = rfm[\"R\"].astype(str) + rfm[\"F\"].astype(str) + rfm[\"M\"].astype(str)\nprint(rfm.groupby(\"R\")[\"Recency\"].agg([\"min\", \"max\"]).to_string())\n",[32,598,599,619,647,691,695,723,740,757,806],{"__ignoreMap":30},[35,600,601,604,608,611,613,616],{"class":37,"line":38},[35,602,603],{"class":213},"def",[35,605,607],{"class":606},"s_Opv"," score",[35,609,610],{"class":217},"(series, higher_is_better",[35,612,240],{"class":213},[35,614,615],{"class":270},"True",[35,617,618],{"class":217},"):\n",[35,620,621,624,626,629,632,634,637,639,642,644],{"class":37,"line":227},[35,622,623],{"class":217},"    ranked ",[35,625,240],{"class":213},[35,627,628],{"class":217}," series.rank(",[35,630,631],{"class":252},"method",[35,633,240],{"class":213},[35,635,636],{"class":45},"\"first\"",[35,638,249],{"class":217},[35,640,641],{"class":252},"ascending",[35,643,240],{"class":213},[35,645,646],{"class":217},"higher_is_better)\n",[35,648,649,652,655,657,659,661,663,665,667,669,671,673,675,677,679,681,683,686,689],{"class":37,"line":234},[35,650,651],{"class":213},"    return",[35,653,654],{"class":217}," pd.qcut(ranked, ",[35,656,532],{"class":270},[35,658,249],{"class":217},[35,660,537],{"class":252},[35,662,240],{"class":213},[35,664,258],{"class":217},[35,666,460],{"class":270},[35,668,249],{"class":217},[35,670,548],{"class":270},[35,672,249],{"class":217},[35,674,553],{"class":270},[35,676,249],{"class":217},[35,678,84],{"class":270},[35,680,249],{"class":217},[35,682,532],{"class":270},[35,684,685],{"class":217},"]).astype(",[35,687,688],{"class":270},"int",[35,690,283],{"class":217},[35,692,693],{"class":37,"line":267},[35,694,231],{"emptyLinePlaceholder":230},[35,696,697,699,702,704,706,709,711,713,716,718,721],{"class":37,"line":286},[35,698,377],{"class":217},[35,700,701],{"class":45},"\"R\"",[35,703,383],{"class":217},[35,705,240],{"class":213},[35,707,708],{"class":217}," score(rfm[",[35,710,380],{"class":45},[35,712,529],{"class":217},[35,714,715],{"class":252},"higher_is_better",[35,717,240],{"class":213},[35,719,720],{"class":270},"False",[35,722,283],{"class":217},[35,724,725,727,730,732,734,736,738],{"class":37,"line":291},[35,726,377],{"class":217},[35,728,729],{"class":45},"\"F\"",[35,731,383],{"class":217},[35,733,240],{"class":213},[35,735,708],{"class":217},[35,737,449],{"class":45},[35,739,264],{"class":217},[35,741,742,744,747,749,751,753,755],{"class":37,"line":308},[35,743,377],{"class":217},[35,745,746],{"class":45},"\"M\"",[35,748,383],{"class":217},[35,750,240],{"class":213},[35,752,708],{"class":217},[35,754,454],{"class":45},[35,756,264],{"class":217},[35,758,759,761,764,766,768,770,772,775,778,781,784,786,788,790,792,794,796,798,800,802,804],{"class":37,"line":329},[35,760,377],{"class":217},[35,762,763],{"class":45},"\"RFM\"",[35,765,383],{"class":217},[35,767,240],{"class":213},[35,769,396],{"class":217},[35,771,701],{"class":45},[35,773,774],{"class":217},"].astype(",[35,776,777],{"class":270},"str",[35,779,780],{"class":217},") ",[35,782,783],{"class":213},"+",[35,785,396],{"class":217},[35,787,729],{"class":45},[35,789,774],{"class":217},[35,791,777],{"class":270},[35,793,780],{"class":217},[35,795,783],{"class":213},[35,797,396],{"class":217},[35,799,746],{"class":45},[35,801,774],{"class":217},[35,803,777],{"class":270},[35,805,283],{"class":217},[35,807,808,810,813,815,818,820,823,825,827,829],{"class":37,"line":349},[35,809,408],{"class":270},[35,811,812],{"class":217},"(rfm.groupby(",[35,814,701],{"class":45},[35,816,817],{"class":217},")[",[35,819,380],{"class":45},[35,821,822],{"class":217},"].agg([",[35,824,466],{"class":45},[35,826,249],{"class":217},[35,828,323],{"class":45},[35,830,831],{"class":217},"]).to_string())\n",[10,833,834],{},"Look at what ranking does to frequency, though. 188 customers placed exactly one order, more than the 120 that fit in the bottom fifth, so 68 of them receive a frequency score of 2 alongside customers with two orders, purely because of the order they happened to be ranked in. For monetary value, which is continuous, that never matters. For a count with a few very common values it can, and some teams prefer fixed thresholds for frequency instead of quantiles:",[25,836,838],{"className":204,"code":837,"language":206,"meta":30,"style":30},"bins = [0, 1, 2, 4, 9, float(\"inf\")]           # 1, 2, 3–4, 5–9, 10+ orders\nrfm[\"F_fixed\"] = pd.cut(rfm[\"Frequency\"], bins=bins, labels=[1, 2, 3, 4, 5]).astype(int)\nprint(pd.crosstab(rfm[\"F_fixed\"], rfm[\"F\"]).to_string())\n",[32,839,840,886,942],{"__ignoreMap":30},[35,841,842,845,847,850,852,854,856,858,860,862,864,866,869,871,874,876,879,882],{"class":37,"line":38},[35,843,844],{"class":217},"bins ",[35,846,240],{"class":213},[35,848,849],{"class":217}," [",[35,851,85],{"class":270},[35,853,249],{"class":217},[35,855,460],{"class":270},[35,857,249],{"class":217},[35,859,548],{"class":270},[35,861,249],{"class":217},[35,863,84],{"class":270},[35,865,249],{"class":217},[35,867,868],{"class":270},"9",[35,870,249],{"class":217},[35,872,873],{"class":270},"float",[35,875,316],{"class":217},[35,877,878],{"class":45},"\"inf\"",[35,880,881],{"class":217},")]           ",[35,883,885],{"class":884},"s-wDw","# 1, 2, 3–4, 5–9, 10+ orders\n",[35,887,888,890,893,895,897,900,902,904,907,909,912,914,916,918,920,922,924,926,928,930,932,934,936,938,940],{"class":37,"line":227},[35,889,377],{"class":217},[35,891,892],{"class":45},"\"F_fixed\"",[35,894,383],{"class":217},[35,896,240],{"class":213},[35,898,899],{"class":217}," pd.cut(rfm[",[35,901,449],{"class":45},[35,903,529],{"class":217},[35,905,906],{"class":252},"bins",[35,908,240],{"class":213},[35,910,911],{"class":217},"bins, ",[35,913,537],{"class":252},[35,915,240],{"class":213},[35,917,258],{"class":217},[35,919,460],{"class":270},[35,921,249],{"class":217},[35,923,548],{"class":270},[35,925,249],{"class":217},[35,927,553],{"class":270},[35,929,249],{"class":217},[35,931,84],{"class":270},[35,933,249],{"class":217},[35,935,532],{"class":270},[35,937,685],{"class":217},[35,939,688],{"class":270},[35,941,283],{"class":217},[35,943,944,946,949,951,954,956],{"class":37,"line":234},[35,945,408],{"class":270},[35,947,948],{"class":217},"(pd.crosstab(rfm[",[35,950,892],{"class":45},[35,952,953],{"class":217},"], rfm[",[35,955,729],{"class":45},[35,957,831],{"class":217},[10,959,960],{},"Fixed thresholds have a second advantage: a score means the same thing next month. The quintile version is relative, so as the customer base grows a customer can drop a score without changing their behaviour. The rest of this page uses the quintile scores, since that is the classic method; switching is a one-line change.",[20,962,964],{"id":963},"step-3-name-the-segments","Step 3 — Name the segments",[10,966,967],{},"125 score combinations are too many to act on. Map them to a handful of named segments with rules based mostly on recency and frequency, which are the strongest signals of future buying. Rules are checked in order, and the first match wins:",[25,969,971],{"className":204,"code":970,"language":206,"meta":30,"style":30},"import numpy as np\n\nR, F = rfm[\"R\"], rfm[\"F\"]\nrules = [\n    (\"Champions\",       (R >= 4) & (F >= 4)),\n    (\"Loyal\",           (R >= 3) & (F >= 4)),\n    (\"New\",             (R >= 4) & (F \u003C= 1)),\n    (\"Promising\",       (R >= 4) & (F \u003C= 3)),\n    (\"Needs attention\", (R == 3) & (F \u003C= 3)),\n    (\"At risk\",         (R \u003C= 2) & (F >= 3)),\n    (\"Hibernating\",     (R \u003C= 2) & (F \u003C= 2)),\n]\nrfm[\"Segment\"] = np.select([cond for _, cond in rules], [name for name, _ in rules], default=\"Other\")\nprint(rfm[\"Segment\"].value_counts().to_string())\n",[32,972,973,985,989,1007,1017,1049,1076,1104,1129,1156,1183,1209,1213,1259],{"__ignoreMap":30},[35,974,975,977,980,982],{"class":37,"line":38},[35,976,214],{"class":213},[35,978,979],{"class":217}," numpy ",[35,981,221],{"class":213},[35,983,984],{"class":217}," np\n",[35,986,987],{"class":37,"line":227},[35,988,231],{"emptyLinePlaceholder":230},[35,990,991,994,996,998,1000,1002,1004],{"class":37,"line":234},[35,992,993],{"class":217},"R, F ",[35,995,240],{"class":213},[35,997,396],{"class":217},[35,999,701],{"class":45},[35,1001,953],{"class":217},[35,1003,729],{"class":45},[35,1005,1006],{"class":217},"]\n",[35,1008,1009,1012,1014],{"class":37,"line":267},[35,1010,1011],{"class":217},"rules ",[35,1013,240],{"class":213},[35,1015,1016],{"class":217}," [\n",[35,1018,1019,1022,1025,1028,1031,1034,1036,1039,1042,1044,1046],{"class":37,"line":286},[35,1020,1021],{"class":217},"    (",[35,1023,1024],{"class":45},"\"Champions\"",[35,1026,1027],{"class":217},",       (R ",[35,1029,1030],{"class":213},">=",[35,1032,1033],{"class":270}," 4",[35,1035,780],{"class":217},[35,1037,1038],{"class":213},"&",[35,1040,1041],{"class":217}," (F ",[35,1043,1030],{"class":213},[35,1045,1033],{"class":270},[35,1047,1048],{"class":217},")),\n",[35,1050,1051,1053,1056,1059,1061,1064,1066,1068,1070,1072,1074],{"class":37,"line":291},[35,1052,1021],{"class":217},[35,1054,1055],{"class":45},"\"Loyal\"",[35,1057,1058],{"class":217},",           (R ",[35,1060,1030],{"class":213},[35,1062,1063],{"class":270}," 3",[35,1065,780],{"class":217},[35,1067,1038],{"class":213},[35,1069,1041],{"class":217},[35,1071,1030],{"class":213},[35,1073,1033],{"class":270},[35,1075,1048],{"class":217},[35,1077,1078,1080,1083,1086,1088,1090,1092,1094,1096,1099,1102],{"class":37,"line":308},[35,1079,1021],{"class":217},[35,1081,1082],{"class":45},"\"New\"",[35,1084,1085],{"class":217},",             (R ",[35,1087,1030],{"class":213},[35,1089,1033],{"class":270},[35,1091,780],{"class":217},[35,1093,1038],{"class":213},[35,1095,1041],{"class":217},[35,1097,1098],{"class":213},"\u003C=",[35,1100,1101],{"class":270}," 1",[35,1103,1048],{"class":217},[35,1105,1106,1108,1111,1113,1115,1117,1119,1121,1123,1125,1127],{"class":37,"line":329},[35,1107,1021],{"class":217},[35,1109,1110],{"class":45},"\"Promising\"",[35,1112,1027],{"class":217},[35,1114,1030],{"class":213},[35,1116,1033],{"class":270},[35,1118,780],{"class":217},[35,1120,1038],{"class":213},[35,1122,1041],{"class":217},[35,1124,1098],{"class":213},[35,1126,1063],{"class":270},[35,1128,1048],{"class":217},[35,1130,1131,1133,1136,1139,1142,1144,1146,1148,1150,1152,1154],{"class":37,"line":349},[35,1132,1021],{"class":217},[35,1134,1135],{"class":45},"\"Needs attention\"",[35,1137,1138],{"class":217},", (R ",[35,1140,1141],{"class":213},"==",[35,1143,1063],{"class":270},[35,1145,780],{"class":217},[35,1147,1038],{"class":213},[35,1149,1041],{"class":217},[35,1151,1098],{"class":213},[35,1153,1063],{"class":270},[35,1155,1048],{"class":217},[35,1157,1158,1160,1163,1166,1168,1171,1173,1175,1177,1179,1181],{"class":37,"line":369},[35,1159,1021],{"class":217},[35,1161,1162],{"class":45},"\"At risk\"",[35,1164,1165],{"class":217},",         (R ",[35,1167,1098],{"class":213},[35,1169,1170],{"class":270}," 2",[35,1172,780],{"class":217},[35,1174,1038],{"class":213},[35,1176,1041],{"class":217},[35,1178,1030],{"class":213},[35,1180,1063],{"class":270},[35,1182,1048],{"class":217},[35,1184,1185,1187,1190,1193,1195,1197,1199,1201,1203,1205,1207],{"class":37,"line":374},[35,1186,1021],{"class":217},[35,1188,1189],{"class":45},"\"Hibernating\"",[35,1191,1192],{"class":217},",     (R ",[35,1194,1098],{"class":213},[35,1196,1170],{"class":270},[35,1198,780],{"class":217},[35,1200,1038],{"class":213},[35,1202,1041],{"class":217},[35,1204,1098],{"class":213},[35,1206,1170],{"class":270},[35,1208,1048],{"class":217},[35,1210,1211],{"class":37,"line":405},[35,1212,1006],{"class":217},[35,1214,1215,1217,1220,1222,1224,1227,1230,1233,1236,1239,1241,1244,1246,1249,1252,1254,1257],{"class":37,"line":437},[35,1216,377],{"class":217},[35,1218,1219],{"class":45},"\"Segment\"",[35,1221,383],{"class":217},[35,1223,240],{"class":213},[35,1225,1226],{"class":217}," np.select([cond ",[35,1228,1229],{"class":213},"for",[35,1231,1232],{"class":217}," _, cond ",[35,1234,1235],{"class":213},"in",[35,1237,1238],{"class":217}," rules], [name ",[35,1240,1229],{"class":213},[35,1242,1243],{"class":217}," name, _ ",[35,1245,1235],{"class":213},[35,1247,1248],{"class":217}," rules], ",[35,1250,1251],{"class":252},"default",[35,1253,240],{"class":213},[35,1255,1256],{"class":45},"\"Other\"",[35,1258,283],{"class":217},[35,1260,1262,1264,1267,1269],{"class":37,"line":1261},14,[35,1263,408],{"class":270},[35,1265,1266],{"class":217},"(rfm[",[35,1268,1219],{"class":45},[35,1270,1271],{"class":217},"].value_counts().to_string())\n",[10,1273,1274],{},"Rules are a business decision; write them where marketing can read them and adjust. The segments here follow a widely used scheme, but \"At risk\" for a subscription business and for a furniture shop mean different things.",[63,1276,72,1282,72,1285,72,1288,72,1293,72,1299,72,1305,72,1309,72,1312,72,1315,72,1318,72,1322,72,1325,72,1329,72,1332,72,1335,72,1338,72,1341,72,1344,72,1347,72,1351,72,1353,72,1356,72,1358,72,1360,72,1362,72,1366,72,1368,72,1370,72,1373,72,1375,72,1377,72,1379,72,1381,72,1383,72,1385,72,1387,72,1389,72,1391,72,1393,72,1395,72,1398,72,1401,72,1403,72,1406,72,1408,72,1410,72,1412,72,1414,72,1416,72,1419,72,1421,72,1423,72,1426,72,1429,72,1431,72,1434,72,1436,72,1438,72,1442,72,1446,72,1448,72,1450,72,1452,72,1454,72,1457,72,1459,72,1461,72,1463,72,1465,72,1467,72,1469,72,1471,72,1473,72,1475,72,1477],{"viewBox":1277,"role":66,"ariaLabelledBy":1278,"xmlns":70,"style":1281},"135 0 489 200",[1279,1280],"rfm-grid-t","rfm-grid-d","width:100%;max-width:489px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[74,1283,1284],{"id":1279},"Segments on the recency and frequency grid",[78,1286,1287],{"id":1280},"A five by five grid with recency score down the side and frequency score across. The top right, high recency and high frequency, is Champions; high frequency with medium recency is Loyal; high recency with low frequency is New or Promising; low recency with high frequency is At risk; low recency with low frequency is Hibernating.",[82,1289],{"x":1290,"y":85,"width":1291,"height":1292,"fill":88},"135","489","200",[82,1294],{"x":1295,"y":92,"width":1296,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"151.9","46.1","28.0","stroke-width:1.5px",[111,1300,1304],{"x":1301,"y":1302,"style":1303},"174.9","35.0","font-size:10px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","R \\ F",[82,1306],{"x":1307,"y":92,"width":1308,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"198.0","84.3",[111,1310,460],{"x":1311,"y":1302,"style":1303},"240.2",[82,1313],{"x":1314,"y":92,"width":1308,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"282.3",[111,1316,548],{"x":1317,"y":1302,"style":1303},"324.5",[82,1319],{"x":1320,"y":92,"width":1321,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"366.7","76.8",[111,1323,553],{"x":1324,"y":1302,"style":1303},"405.1",[82,1326],{"x":1327,"y":92,"width":1328,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"443.5","82.3",[111,1330,84],{"x":1331,"y":1302,"style":1303},"484.6",[82,1333],{"x":1334,"y":92,"width":1328,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"525.8",[111,1336,532],{"x":1337,"y":1302,"style":1303},"567.0",[82,1339],{"x":1295,"y":1340,"width":1296,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"44.0",[111,1342,532],{"x":1301,"y":1343,"style":1303},"63.0",[82,1345],{"x":1307,"y":1340,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},"var(--line,#cdd5e6)",[111,1348,1350],{"x":1311,"y":1343,"style":1349},"font-size:10px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","New",[82,1352],{"x":1314,"y":1340,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1354,1355],{"x":1317,"y":1343,"style":1349},"Promising",[82,1357],{"x":1320,"y":1340,"width":1321,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1359,1355],{"x":1324,"y":1343,"style":1349},[82,1361],{"x":1327,"y":1340,"width":1328,"height":1297,"rx":85,"fill":139,"stroke":140,"style":1298},[111,1363,1365],{"x":1331,"y":1343,"style":1364},"font-size:10px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Champions",[82,1367],{"x":1334,"y":1340,"width":1328,"height":1297,"rx":85,"fill":139,"stroke":140,"style":1298},[111,1369,1365],{"x":1337,"y":1343,"style":1364},[82,1371],{"x":1295,"y":1372,"width":1296,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"72.0",[111,1374,84],{"x":1301,"y":120,"style":1303},[82,1376],{"x":1307,"y":1372,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1378,1350],{"x":1311,"y":120,"style":1349},[82,1380],{"x":1314,"y":1372,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1382,1355],{"x":1317,"y":120,"style":1349},[82,1384],{"x":1320,"y":1372,"width":1321,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1386,1355],{"x":1324,"y":120,"style":1349},[82,1388],{"x":1327,"y":1372,"width":1328,"height":1297,"rx":85,"fill":139,"stroke":140,"style":1298},[111,1390,1365],{"x":1331,"y":120,"style":1364},[82,1392],{"x":1334,"y":1372,"width":1328,"height":1297,"rx":85,"fill":139,"stroke":140,"style":1298},[111,1394,1365],{"x":1337,"y":120,"style":1364},[82,1396],{"x":1295,"y":1397,"width":1296,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"100.0",[111,1399,553],{"x":1301,"y":1400,"style":1303},"119.0",[82,1402],{"x":1307,"y":1397,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1404,1405],{"x":1311,"y":1400,"style":1349},"Needs att.",[82,1407],{"x":1314,"y":1397,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1409,1405],{"x":1317,"y":1400,"style":1349},[82,1411],{"x":1320,"y":1397,"width":1321,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1413,1405],{"x":1324,"y":1400,"style":1349},[82,1415],{"x":1327,"y":1397,"width":1328,"height":1297,"rx":85,"fill":139,"stroke":140,"style":1298},[111,1417,1418],{"x":1331,"y":1400,"style":1364},"Loyal",[82,1420],{"x":1334,"y":1397,"width":1328,"height":1297,"rx":85,"fill":139,"stroke":140,"style":1298},[111,1422,1418],{"x":1337,"y":1400,"style":1364},[82,1424],{"x":1295,"y":1425,"width":1296,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"128.0",[111,1427,548],{"x":1301,"y":1428,"style":1303},"147.0",[82,1430],{"x":1307,"y":1425,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1432,1433],{"x":1311,"y":1428,"style":1349},"Hibernating",[82,1435],{"x":1314,"y":1425,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1437,1433],{"x":1317,"y":1428,"style":1349},[82,1439],{"x":1320,"y":1425,"width":1321,"height":1297,"rx":85,"fill":1440,"stroke":1441,"style":1298},"#fce9e9","var(--danger,#dc2626)",[111,1443,1445],{"x":1324,"y":1428,"style":1444},"font-size:10px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","At risk",[82,1447],{"x":1327,"y":1425,"width":1328,"height":1297,"rx":85,"fill":1440,"stroke":1441,"style":1298},[111,1449,1445],{"x":1331,"y":1428,"style":1444},[82,1451],{"x":1334,"y":1425,"width":1328,"height":1297,"rx":85,"fill":1440,"stroke":1441,"style":1298},[111,1453,1445],{"x":1337,"y":1428,"style":1444},[82,1455],{"x":1295,"y":1456,"width":1296,"height":1297,"rx":85,"fill":96,"stroke":97,"style":1298},"156.0",[111,1458,460],{"x":1301,"y":94,"style":1303},[82,1460],{"x":1307,"y":1456,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1462,1433],{"x":1311,"y":94,"style":1349},[82,1464],{"x":1314,"y":1456,"width":1308,"height":1297,"rx":85,"fill":88,"stroke":1346,"style":122},[111,1466,1433],{"x":1317,"y":94,"style":1349},[82,1468],{"x":1320,"y":1456,"width":1321,"height":1297,"rx":85,"fill":1440,"stroke":1441,"style":1298},[111,1470,1445],{"x":1324,"y":94,"style":1444},[82,1472],{"x":1327,"y":1456,"width":1328,"height":1297,"rx":85,"fill":1440,"stroke":1441,"style":1298},[111,1474,1445],{"x":1331,"y":94,"style":1444},[82,1476],{"x":1334,"y":1456,"width":1328,"height":1297,"rx":85,"fill":1440,"stroke":1441,"style":1298},[111,1478,1445],{"x":1337,"y":94,"style":1444},[20,1480,1482],{"id":1481},"step-4-summarise-the-segments","Step 4 — Summarise the segments",[10,1484,1485],{},"The summary is what gets presented: how many customers in each segment, what share of revenue they bring, and their typical recency and order count:",[25,1487,1489],{"className":204,"code":1488,"language":206,"meta":30,"style":30},"summary = rfm.groupby(\"Segment\").agg(\n    Customers=(\"R\", \"size\"),\n    Revenue=(\"Monetary\", \"sum\"),\n    MedianRecency=(\"Recency\", \"median\"),\n    MedianOrders=(\"Frequency\", \"median\"),\n    AvgSpend=(\"Monetary\", \"mean\"),\n)\nsummary[\"Customer %\"] = summary[\"Customers\"] \u002F summary[\"Customers\"].sum() * 100\nsummary[\"Revenue %\"] = summary[\"Revenue\"] \u002F summary[\"Revenue\"].sum() * 100\nsummary = summary.sort_values(\"Revenue\", ascending=False)\nprint(summary.round(1).to_string())\n",[32,1490,1491,1505,1523,1540,1558,1575,1593,1597,1633,1663,1684],{"__ignoreMap":30},[35,1492,1493,1496,1498,1501,1503],{"class":37,"line":38},[35,1494,1495],{"class":217},"summary ",[35,1497,240],{"class":213},[35,1499,1500],{"class":217}," rfm.groupby(",[35,1502,1219],{"class":45},[35,1504,305],{"class":217},[35,1506,1507,1510,1512,1514,1516,1518,1521],{"class":37,"line":227},[35,1508,1509],{"class":252},"    Customers",[35,1511,240],{"class":213},[35,1513,316],{"class":217},[35,1515,701],{"class":45},[35,1517,249],{"class":217},[35,1519,1520],{"class":45},"\"size\"",[35,1522,326],{"class":217},[35,1524,1525,1528,1530,1532,1534,1536,1538],{"class":37,"line":234},[35,1526,1527],{"class":252},"    Revenue",[35,1529,240],{"class":213},[35,1531,316],{"class":217},[35,1533,454],{"class":45},[35,1535,249],{"class":217},[35,1537,364],{"class":45},[35,1539,326],{"class":217},[35,1541,1542,1545,1547,1549,1551,1553,1556],{"class":37,"line":267},[35,1543,1544],{"class":252},"    MedianRecency",[35,1546,240],{"class":213},[35,1548,316],{"class":217},[35,1550,380],{"class":45},[35,1552,249],{"class":217},[35,1554,1555],{"class":45},"\"median\"",[35,1557,326],{"class":217},[35,1559,1560,1563,1565,1567,1569,1571,1573],{"class":37,"line":286},[35,1561,1562],{"class":252},"    MedianOrders",[35,1564,240],{"class":213},[35,1566,316],{"class":217},[35,1568,449],{"class":45},[35,1570,249],{"class":217},[35,1572,1555],{"class":45},[35,1574,326],{"class":217},[35,1576,1577,1580,1582,1584,1586,1588,1591],{"class":37,"line":291},[35,1578,1579],{"class":252},"    AvgSpend",[35,1581,240],{"class":213},[35,1583,316],{"class":217},[35,1585,454],{"class":45},[35,1587,249],{"class":217},[35,1589,1590],{"class":45},"\"mean\"",[35,1592,326],{"class":217},[35,1594,1595],{"class":37,"line":308},[35,1596,283],{"class":217},[35,1598,1599,1602,1605,1607,1609,1612,1615,1617,1620,1622,1624,1627,1630],{"class":37,"line":329},[35,1600,1601],{"class":217},"summary[",[35,1603,1604],{"class":45},"\"Customer %\"",[35,1606,383],{"class":217},[35,1608,240],{"class":213},[35,1610,1611],{"class":217}," summary[",[35,1613,1614],{"class":45},"\"Customers\"",[35,1616,383],{"class":217},[35,1618,1619],{"class":213},"\u002F",[35,1621,1611],{"class":217},[35,1623,1614],{"class":45},[35,1625,1626],{"class":217},"].sum() ",[35,1628,1629],{"class":213},"*",[35,1631,1632],{"class":270}," 100\n",[35,1634,1635,1637,1640,1642,1644,1646,1649,1651,1653,1655,1657,1659,1661],{"class":37,"line":349},[35,1636,1601],{"class":217},[35,1638,1639],{"class":45},"\"Revenue %\"",[35,1641,383],{"class":217},[35,1643,240],{"class":213},[35,1645,1611],{"class":217},[35,1647,1648],{"class":45},"\"Revenue\"",[35,1650,383],{"class":217},[35,1652,1619],{"class":213},[35,1654,1611],{"class":217},[35,1656,1648],{"class":45},[35,1658,1626],{"class":217},[35,1660,1629],{"class":213},[35,1662,1632],{"class":270},[35,1664,1665,1667,1669,1672,1674,1676,1678,1680,1682],{"class":37,"line":369},[35,1666,1495],{"class":217},[35,1668,240],{"class":213},[35,1670,1671],{"class":217}," summary.sort_values(",[35,1673,1648],{"class":45},[35,1675,249],{"class":217},[35,1677,641],{"class":252},[35,1679,240],{"class":213},[35,1681,720],{"class":270},[35,1683,283],{"class":217},[35,1685,1686,1688,1691,1693],{"class":37,"line":374},[35,1687,408],{"class":270},[35,1689,1690],{"class":217},"(summary.round(",[35,1692,460],{"class":270},[35,1694,1695],{"class":217},").to_string())\n",[10,1697,1698],{},"Here the Champions are 19.5% of customers and bring 55.3% of revenue, with a median of nine orders and a last order 25 days ago. The At risk segment is the largest, 146 customers: a median of five orders, but the last one about ten months ago. Together with Loyal they account for another 35% of revenue.",[63,1700,72,1706,72,1709,72,1712,72,1716,72,1721,72,1726,72,1730,72,1735,72,1738,72,1741,72,1744,72,1748,72,1751,72,1754,72,1757,72,1762,72,1765,72,1768,72,1771,72,1776,72,1779,72,1783,72,1786,72,1791,72,1794,72,1797,72,1800,72,1805,72,1808,72,1811,72,1814],{"viewBox":1701,"role":66,"ariaLabelledBy":1702,"xmlns":70,"style":1705},"4 0 744 300",[1703,1704],"rfm-share-t","rfm-share-d","width:100%;max-width:744px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[74,1707,1708],{"id":1703},"Share of revenue by segment",[78,1710,1711],{"id":1704},"A horizontal bar chart of each segment's share of total revenue over the two years. Champions 55.3 percent, Loyal 19.1, At risk 16.0, Promising 4.4, Needs attention 2.6, Hibernating 2.1 and New 0.5.",[82,1713],{"x":84,"y":85,"width":1714,"height":1715,"fill":88},"744","300",[82,1717],{"x":91,"y":92,"width":1718,"height":1297,"rx":1719,"fill":1720,"stroke":1346,"style":122},"130.2","7","#e7ebef",[111,1722,1365],{"x":1723,"y":1724,"style":1725},"85.1","34.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[82,1727],{"x":1728,"y":92,"width":1729,"height":1297,"rx":1719,"fill":139,"stroke":140,"style":1298},"160.2","523.0",[111,1731,1734],{"x":1732,"y":1724,"style":1733},"691.2","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","55.3%",[82,1736],{"x":91,"y":1737,"width":1718,"height":1297,"rx":1719,"fill":1720,"stroke":1346,"style":122},"56.0",[111,1739,1418],{"x":1723,"y":1740,"style":1725},"74.5",[82,1742],{"x":1728,"y":1737,"width":1743,"height":1297,"rx":1719,"fill":139,"stroke":140,"style":1298},"180.6",[111,1745,1747],{"x":1746,"y":1740,"style":1733},"348.8","19.1%",[82,1749],{"x":91,"y":1750,"width":1718,"height":1297,"rx":1719,"fill":1720,"stroke":1346,"style":122},"96.0",[111,1752,1445],{"x":1723,"y":1753,"style":1725},"114.5",[82,1755],{"x":1728,"y":1750,"width":1756,"height":1297,"rx":1719,"fill":1440,"stroke":1441,"style":1298},"151.3",[111,1758,1761],{"x":1759,"y":1753,"style":1760},"319.5","font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:start","16.0%",[82,1763],{"x":91,"y":1764,"width":1718,"height":1297,"rx":1719,"fill":1720,"stroke":1346,"style":122},"136.0",[111,1766,1355],{"x":1723,"y":1767,"style":1725},"154.5",[82,1769],{"x":1728,"y":1764,"width":1770,"height":1297,"rx":1719,"fill":96,"stroke":97,"style":1298},"41.6",[111,1772,1775],{"x":1773,"y":1767,"style":1774},"209.8","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","4.4%",[82,1777],{"x":91,"y":1778,"width":1718,"height":1297,"rx":1719,"fill":1720,"stroke":1346,"style":122},"176.0",[111,1780,1782],{"x":1723,"y":1781,"style":1725},"194.5","Needs attention",[82,1784],{"x":1728,"y":1778,"width":1785,"height":1297,"rx":1719,"fill":169,"stroke":170,"style":1298},"24.6",[111,1787,1790],{"x":1788,"y":1781,"style":1789},"192.8","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","2.6%",[82,1792],{"x":91,"y":1793,"width":1718,"height":1297,"rx":1719,"fill":1720,"stroke":1346,"style":122},"216.0",[111,1795,1433],{"x":1723,"y":1796,"style":1725},"234.5",[82,1798],{"x":1728,"y":1793,"width":1799,"height":1297,"rx":1719,"fill":1720,"stroke":1346,"style":1298},"19.9",[111,1801,1804],{"x":1802,"y":1796,"style":1803},"188.1","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:start","2.1%",[82,1806],{"x":91,"y":1807,"width":1718,"height":1297,"rx":1719,"fill":1720,"stroke":1346,"style":122},"256.0",[111,1809,1350],{"x":1723,"y":1810,"style":1725},"274.5",[82,1812],{"x":1728,"y":1807,"width":1813,"height":1297,"rx":1719,"fill":96,"stroke":97,"style":1298},"6.0",[111,1815,1817],{"x":1816,"y":1810,"style":1774},"174.2","0.5%",[10,1819,1820],{},"The typical result, and the one here, is that a small share of customers brings a large share of revenue, and that \"At risk\" holds customers who used to be valuable and have stopped buying — the best target for a win-back campaign, because they have already shown what they are worth.",[20,1822,1824],{"id":1823},"step-5-the-recency-by-frequency-grid","Step 5 — The recency-by-frequency grid",[10,1826,1827],{},"A pivot of customer counts by R and F score is the picture marketing teams recognise; with a colour scale it shows where the customer base sits at a glance:",[25,1829,1831],{"className":204,"code":1830,"language":206,"meta":30,"style":30},"grid = rfm.pivot_table(index=\"R\", columns=\"F\", values=\"Monetary\", aggfunc=\"size\", fill_value=0)\ngrid = grid.sort_index(ascending=False)\nprint(grid.to_string())\n",[32,1832,1833,1888,1905],{"__ignoreMap":30},[35,1834,1835,1838,1840,1843,1846,1848,1850,1852,1855,1857,1859,1861,1864,1866,1868,1870,1873,1875,1877,1879,1882,1884,1886],{"class":37,"line":38},[35,1836,1837],{"class":217},"grid ",[35,1839,240],{"class":213},[35,1841,1842],{"class":217}," rfm.pivot_table(",[35,1844,1845],{"class":252},"index",[35,1847,240],{"class":213},[35,1849,701],{"class":45},[35,1851,249],{"class":217},[35,1853,1854],{"class":252},"columns",[35,1856,240],{"class":213},[35,1858,729],{"class":45},[35,1860,249],{"class":217},[35,1862,1863],{"class":252},"values",[35,1865,240],{"class":213},[35,1867,454],{"class":45},[35,1869,249],{"class":217},[35,1871,1872],{"class":252},"aggfunc",[35,1874,240],{"class":213},[35,1876,1520],{"class":45},[35,1878,249],{"class":217},[35,1880,1881],{"class":252},"fill_value",[35,1883,240],{"class":213},[35,1885,85],{"class":270},[35,1887,283],{"class":217},[35,1889,1890,1892,1894,1897,1899,1901,1903],{"class":37,"line":227},[35,1891,1837],{"class":217},[35,1893,240],{"class":213},[35,1895,1896],{"class":217}," grid.sort_index(",[35,1898,641],{"class":252},[35,1900,240],{"class":213},[35,1902,720],{"class":270},[35,1904,283],{"class":217},[35,1906,1907,1909],{"class":37,"line":234},[35,1908,408],{"class":270},[35,1910,1911],{"class":217},"(grid.to_string())\n",[20,1913,1915],{"id":1914},"step-6-write-the-workbook","Step 6 — Write the workbook",[10,1917,1918],{},"A summary sheet with the grid and segment table, and one sheet listing every customer with scores and segment, ready to filter into campaign lists:",[25,1920,1922],{"className":204,"code":1921,"language":206,"meta":30,"style":30},"with pd.ExcelWriter(\"rfm_segments_2026-09-28.xlsx\", engine=\"xlsxwriter\") as xw:\n    book = xw.book\n    summary.round(1).to_excel(xw, sheet_name=\"Summary\")\n    ws = xw.sheets[\"Summary\"]\n    ws.set_column(0, 0, 16)\n    ws.set_column(1, 7, 13, book.add_format({\"num_format\": \"#,##0.0\"}))\n    top = len(summary) + 3\n    ws.write(top, 0, \"Customers by recency (rows) and frequency (columns) score\", book.add_format({\"bold\": True}))\n    grid.to_excel(xw, sheet_name=\"Summary\", startrow=top + 1)\n    ws.conditional_format(top + 2, 1, top + 6, 5, {\"type\": \"3_color_scale\",\n                          \"min_color\": \"#F8FAFC\", \"mid_color\": \"#A5B4FC\", \"max_color\": \"#4338CA\"})\n\n    out = rfm.reset_index()[[\"CustomerID\", \"Segment\", \"R\", \"F\", \"M\", \"RFM\", \"Recency\", \"Frequency\", \"Monetary\", \"LastOrder\"]]\n    out.sort_values([\"Segment\", \"Monetary\"], ascending=[True, False]).to_excel(xw, sheet_name=\"Customers\", index=False)\n    cs = xw.sheets[\"Customers\"]\n    cs.set_column(0, 1, 16)\n    cs.set_column(8, 8, 12, book.add_format({\"num_format\": \"#,##0.00\"}))\n    cs.set_column(9, 9, 12, book.add_format({\"num_format\": \"yyyy-mm-dd\"}))\n    cs.autofilter(0, 0, len(out), 9)\n    cs.freeze_panes(1, 1)\nprint(\"written\")\n",[32,1923,1924,1952,1962,1982,1996,2014,2044,2062,2085,2112,2151,2184,2188,2239,2283,2297,2315,2343,2369,2392,2406],{"__ignoreMap":30},[35,1925,1926,1929,1932,1935,1937,1940,1942,1945,1947,1949],{"class":37,"line":38},[35,1927,1928],{"class":213},"with",[35,1930,1931],{"class":217}," pd.ExcelWriter(",[35,1933,1934],{"class":45},"\"rfm_segments_2026-09-28.xlsx\"",[35,1936,249],{"class":217},[35,1938,1939],{"class":252},"engine",[35,1941,240],{"class":213},[35,1943,1944],{"class":45},"\"xlsxwriter\"",[35,1946,780],{"class":217},[35,1948,221],{"class":213},[35,1950,1951],{"class":217}," xw:\n",[35,1953,1954,1957,1959],{"class":37,"line":227},[35,1955,1956],{"class":217},"    book ",[35,1958,240],{"class":213},[35,1960,1961],{"class":217}," xw.book\n",[35,1963,1964,1967,1969,1972,1975,1977,1980],{"class":37,"line":234},[35,1965,1966],{"class":217},"    summary.round(",[35,1968,460],{"class":270},[35,1970,1971],{"class":217},").to_excel(xw, ",[35,1973,1974],{"class":252},"sheet_name",[35,1976,240],{"class":213},[35,1978,1979],{"class":45},"\"Summary\"",[35,1981,283],{"class":217},[35,1983,1984,1987,1989,1992,1994],{"class":37,"line":267},[35,1985,1986],{"class":217},"    ws ",[35,1988,240],{"class":213},[35,1990,1991],{"class":217}," xw.sheets[",[35,1993,1979],{"class":45},[35,1995,1006],{"class":217},[35,1997,1998,2001,2003,2005,2007,2009,2012],{"class":37,"line":286},[35,1999,2000],{"class":217},"    ws.set_column(",[35,2002,85],{"class":270},[35,2004,249],{"class":217},[35,2006,85],{"class":270},[35,2008,249],{"class":217},[35,2010,2011],{"class":270},"16",[35,2013,283],{"class":217},[35,2015,2016,2018,2020,2022,2024,2026,2029,2032,2035,2038,2041],{"class":37,"line":291},[35,2017,2000],{"class":217},[35,2019,460],{"class":270},[35,2021,249],{"class":217},[35,2023,1719],{"class":270},[35,2025,249],{"class":217},[35,2027,2028],{"class":270},"13",[35,2030,2031],{"class":217},", book.add_format({",[35,2033,2034],{"class":45},"\"num_format\"",[35,2036,2037],{"class":217},": ",[35,2039,2040],{"class":45},"\"#,##0.0\"",[35,2042,2043],{"class":217},"}))\n",[35,2045,2046,2049,2051,2054,2057,2059],{"class":37,"line":308},[35,2047,2048],{"class":217},"    top ",[35,2050,240],{"class":213},[35,2052,2053],{"class":270}," len",[35,2055,2056],{"class":217},"(summary) ",[35,2058,783],{"class":213},[35,2060,2061],{"class":270}," 3\n",[35,2063,2064,2067,2069,2071,2074,2076,2079,2081,2083],{"class":37,"line":329},[35,2065,2066],{"class":217},"    ws.write(top, ",[35,2068,85],{"class":270},[35,2070,249],{"class":217},[35,2072,2073],{"class":45},"\"Customers by recency (rows) and frequency (columns) score\"",[35,2075,2031],{"class":217},[35,2077,2078],{"class":45},"\"bold\"",[35,2080,2037],{"class":217},[35,2082,615],{"class":270},[35,2084,2043],{"class":217},[35,2086,2087,2090,2092,2094,2096,2098,2101,2103,2106,2108,2110],{"class":37,"line":349},[35,2088,2089],{"class":217},"    grid.to_excel(xw, ",[35,2091,1974],{"class":252},[35,2093,240],{"class":213},[35,2095,1979],{"class":45},[35,2097,249],{"class":217},[35,2099,2100],{"class":252},"startrow",[35,2102,240],{"class":213},[35,2104,2105],{"class":217},"top ",[35,2107,783],{"class":213},[35,2109,1101],{"class":270},[35,2111,283],{"class":217},[35,2113,2114,2117,2119,2121,2123,2125,2128,2130,2133,2135,2137,2140,2143,2145,2148],{"class":37,"line":369},[35,2115,2116],{"class":217},"    ws.conditional_format(top ",[35,2118,783],{"class":213},[35,2120,1170],{"class":270},[35,2122,249],{"class":217},[35,2124,460],{"class":270},[35,2126,2127],{"class":217},", top ",[35,2129,783],{"class":213},[35,2131,2132],{"class":270}," 6",[35,2134,249],{"class":217},[35,2136,532],{"class":270},[35,2138,2139],{"class":217},", {",[35,2141,2142],{"class":45},"\"type\"",[35,2144,2037],{"class":217},[35,2146,2147],{"class":45},"\"3_color_scale\"",[35,2149,2150],{"class":217},",\n",[35,2152,2153,2156,2158,2161,2163,2166,2168,2171,2173,2176,2178,2181],{"class":37,"line":374},[35,2154,2155],{"class":45},"                          \"min_color\"",[35,2157,2037],{"class":217},[35,2159,2160],{"class":45},"\"#F8FAFC\"",[35,2162,249],{"class":217},[35,2164,2165],{"class":45},"\"mid_color\"",[35,2167,2037],{"class":217},[35,2169,2170],{"class":45},"\"#A5B4FC\"",[35,2172,249],{"class":217},[35,2174,2175],{"class":45},"\"max_color\"",[35,2177,2037],{"class":217},[35,2179,2180],{"class":45},"\"#4338CA\"",[35,2182,2183],{"class":217},"})\n",[35,2185,2186],{"class":37,"line":405},[35,2187,231],{"emptyLinePlaceholder":230},[35,2189,2190,2193,2195,2198,2200,2202,2204,2206,2208,2210,2212,2214,2216,2218,2220,2222,2224,2226,2228,2230,2232,2234,2236],{"class":37,"line":437},[35,2191,2192],{"class":217},"    out ",[35,2194,240],{"class":213},[35,2196,2197],{"class":217}," rfm.reset_index()[[",[35,2199,302],{"class":45},[35,2201,249],{"class":217},[35,2203,1219],{"class":45},[35,2205,249],{"class":217},[35,2207,701],{"class":45},[35,2209,249],{"class":217},[35,2211,729],{"class":45},[35,2213,249],{"class":217},[35,2215,746],{"class":45},[35,2217,249],{"class":217},[35,2219,763],{"class":45},[35,2221,249],{"class":217},[35,2223,380],{"class":45},[35,2225,249],{"class":217},[35,2227,449],{"class":45},[35,2229,249],{"class":217},[35,2231,454],{"class":45},[35,2233,249],{"class":217},[35,2235,399],{"class":45},[35,2237,2238],{"class":217},"]]\n",[35,2240,2241,2244,2246,2248,2250,2252,2254,2256,2258,2260,2262,2264,2267,2269,2271,2273,2275,2277,2279,2281],{"class":37,"line":1261},[35,2242,2243],{"class":217},"    out.sort_values([",[35,2245,1219],{"class":45},[35,2247,249],{"class":217},[35,2249,454],{"class":45},[35,2251,529],{"class":217},[35,2253,641],{"class":252},[35,2255,240],{"class":213},[35,2257,258],{"class":217},[35,2259,615],{"class":270},[35,2261,249],{"class":217},[35,2263,720],{"class":270},[35,2265,2266],{"class":217},"]).to_excel(xw, ",[35,2268,1974],{"class":252},[35,2270,240],{"class":213},[35,2272,1614],{"class":45},[35,2274,249],{"class":217},[35,2276,1845],{"class":252},[35,2278,240],{"class":213},[35,2280,720],{"class":270},[35,2282,283],{"class":217},[35,2284,2286,2289,2291,2293,2295],{"class":37,"line":2285},15,[35,2287,2288],{"class":217},"    cs ",[35,2290,240],{"class":213},[35,2292,1991],{"class":217},[35,2294,1614],{"class":45},[35,2296,1006],{"class":217},[35,2298,2300,2303,2305,2307,2309,2311,2313],{"class":37,"line":2299},16,[35,2301,2302],{"class":217},"    cs.set_column(",[35,2304,85],{"class":270},[35,2306,249],{"class":217},[35,2308,460],{"class":270},[35,2310,249],{"class":217},[35,2312,2011],{"class":270},[35,2314,283],{"class":217},[35,2316,2318,2320,2323,2325,2327,2329,2332,2334,2336,2338,2341],{"class":37,"line":2317},17,[35,2319,2302],{"class":217},[35,2321,2322],{"class":270},"8",[35,2324,249],{"class":217},[35,2326,2322],{"class":270},[35,2328,249],{"class":217},[35,2330,2331],{"class":270},"12",[35,2333,2031],{"class":217},[35,2335,2034],{"class":45},[35,2337,2037],{"class":217},[35,2339,2340],{"class":45},"\"#,##0.00\"",[35,2342,2043],{"class":217},[35,2344,2346,2348,2350,2352,2354,2356,2358,2360,2362,2364,2367],{"class":37,"line":2345},18,[35,2347,2302],{"class":217},[35,2349,868],{"class":270},[35,2351,249],{"class":217},[35,2353,868],{"class":270},[35,2355,249],{"class":217},[35,2357,2331],{"class":270},[35,2359,2031],{"class":217},[35,2361,2034],{"class":45},[35,2363,2037],{"class":217},[35,2365,2366],{"class":45},"\"yyyy-mm-dd\"",[35,2368,2043],{"class":217},[35,2370,2372,2375,2377,2379,2381,2383,2385,2388,2390],{"class":37,"line":2371},19,[35,2373,2374],{"class":217},"    cs.autofilter(",[35,2376,85],{"class":270},[35,2378,249],{"class":217},[35,2380,85],{"class":270},[35,2382,249],{"class":217},[35,2384,423],{"class":270},[35,2386,2387],{"class":217},"(out), ",[35,2389,868],{"class":270},[35,2391,283],{"class":217},[35,2393,2395,2398,2400,2402,2404],{"class":37,"line":2394},20,[35,2396,2397],{"class":217},"    cs.freeze_panes(",[35,2399,460],{"class":270},[35,2401,249],{"class":217},[35,2403,460],{"class":270},[35,2405,283],{"class":217},[35,2407,2409,2411,2413,2416],{"class":37,"line":2408},21,[35,2410,408],{"class":270},[35,2412,316],{"class":217},[35,2414,2415],{"class":45},"\"written\"",[35,2417,283],{"class":217},[10,2419,2420,2424],{},[14,2421,2423],{"href":2422},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fturn-a-pivot-table-into-a-heatmap-in-excel\u002F","Turn a Pivot Table into a Heatmap in Excel"," covers colour scales on pivots in more detail.",[20,2426,2428],{"id":2427},"common-pitfalls","Common pitfalls",[2430,2431,2432,2440,2453,2459,2465,2471],"ul",{},[2433,2434,2435,2439],"li",{},[2436,2437,2438],"strong",{},"Counting rows as orders."," Use the number of distinct order IDs for frequency.",[2433,2441,2442,2448,2449,2452],{},[2436,2443,2444,2447],{},[32,2445,2446],{},"qcut"," on skewed counts."," Duplicate bin edges raise an error; rank with ",[32,2450,2451],{},"method=\"first\""," before cutting.",[2433,2454,2455,2458],{},[2436,2456,2457],{},"Forgetting to reverse recency."," Fewer days since the last order is better, so it scores 5.",[2433,2460,2461,2464],{},[2436,2462,2463],{},"Using today as the analysis date."," Fix the date so results can be reproduced and compared month to month.",[2433,2466,2467,2470],{},[2436,2468,2469],{},"Scores across different runs."," Quintiles are relative to the current customer base; a score of 5 this month is not the same threshold as last month. Compare segments, not raw scores, over time.",[2433,2472,2473,2476],{},[2436,2474,2475],{},"Returns and test orders."," Remove them first, or refund-heavy customers look valuable.",[20,2478,2480],{"id":2479},"conclusion","Conclusion",[10,2482,2483,2484,2486],{},"Group orders by customer to get days since the last order, the number of distinct orders and the total spent, then score each measure 1 to 5 by quintile, ranking first so ties do not break ",[32,2485,2446],{}," and reversing recency. Map score combinations to a few named segments with ordered rules, summarise customers and revenue per segment, and write the summary, a recency-by-frequency grid with a colour scale and the scored customer list to Excel.",[20,2488,2490],{"id":2489},"frequently-asked-questions","Frequently asked questions",[10,2492,2493,2496],{},[2436,2494,2495],{},"What is RFM analysis?","\nA way of segmenting customers by recency (days since the last purchase), frequency (number of purchases) and monetary value (total spent). Each measure is scored, usually 1 to 5, and combinations of scores are grouped into segments.",[10,2498,2499,2502],{},[2436,2500,2501],{},"Why does pd.qcut fail with duplicate bin edges?","\nBecause many customers share the same value, such as one order, so several quantile boundaries are equal. Rank the values with method=\"first\" and cut the ranks instead.",[10,2504,2505,2508],{},[2436,2506,2507],{},"How many RFM segments should I use?","\nFew enough to act on: five to eight named segments is typical. The 125 raw score combinations are useful for analysis but not for campaigns.",[10,2510,2511,2514],{},[2436,2512,2513],{},"How often should RFM segments be recalculated?","\nMonthly is common for retail. Keep the analysis date fixed per run and track how many customers move between segments from one run to the next.",[20,2516,2518],{"id":2517},"related","Related",[2430,2520,2521,2527,2534,2539,2546],{},[2433,2522,2523,2524,2526],{},"Up one level: ",[14,2525,17],{"href":16}," — summarising Excel data by group.",[2433,2528,2529,2533],{},[14,2530,2532],{"href":2531},"\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"," — retention by first-purchase month.",[2433,2535,2536,2538],{},[14,2537,2423],{"href":2422}," — colouring the grid.",[2433,2540,2541,2545],{},[14,2542,2544],{"href":2543},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcalculate-percent-of-total-per-group-in-pandas\u002F","Calculate Percent of Total per Group in pandas"," — revenue shares by segment.",[2433,2547,2548,2552],{},[14,2549,2551],{"href":2550},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-weekly-sales-report\u002F","Build a Weekly Sales Report"," — the same orders, by week.",[2554,2555,2556],"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":30,"searchDepth":227,"depth":227,"links":2558},[2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569],{"id":22,"depth":227,"text":23},{"id":197,"depth":227,"text":198},{"id":498,"depth":227,"text":499},{"id":963,"depth":227,"text":964},{"id":1481,"depth":227,"text":1482},{"id":1823,"depth":227,"text":1824},{"id":1914,"depth":227,"text":1915},{"id":2427,"depth":227,"text":2428},{"id":2479,"depth":227,"text":2480},{"id":2489,"depth":227,"text":2490},{"id":2517,"depth":227,"text":2518},"2026-09-29","Segment customers by recency, frequency and monetary value from an Excel order history: compute the three measures per customer, score them 1 to 5 with quantiles that survive ties, map score combinations to named segments such as Champions and At risk, summarise each segment, and write a workbook with a recency-by-frequency grid.","md",[2574,2576,2578,2580],{"q":2495,"a":2575},"A way of segmenting customers by recency (days since the last purchase), frequency (number of purchases) and monetary value (total spent). Each measure is scored, usually 1 to 5, and combinations of scores are grouped into segments.",{"q":2501,"a":2577},"Because many customers share the same value, such as one order, so several quantile boundaries are equal. Rank the values with method=\"first\" and cut the ranks instead.",{"q":2507,"a":2579},"Few enough to act on: five to eight named segments is typical. The 125 raw score combinations are useful for analysis but not for campaigns.",{"q":2513,"a":2581},"Monthly is common for retail. Keep the analysis date fixed per run and track how many customers move between segments from one run to the next.","build an rfm customer segmentation",null,{"breadcrumb":2585},[2586,2588,2591],{"name":2587,"item":1619},"Home",{"name":2589,"item":2590},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2592,"item":16},"Creating Pivot Tables from Excel Data with Pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data",{"title":2595,"description":2596},"RFM Analysis and Customer Segmentation in Python (pandas)","Build an RFM segmentation from Excel orders with pandas: recency, frequency and monetary per customer, qcut scores with rank to handle ties, segment rules, segment summary and an R×F heatmap written to Excel.","build-an-rfm-customer-segmentation-from-excel-data","advanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data\u002Findex",[2600,2601],"pivots-and-summaries","pandas","how-to","LR3Gq4sCcLu415-AUdmYGTF09Yfpce7UOlndQcHvd34",[2605,2609],{"title":2606,"path":2607,"stem":2608,"children":-1},"Build a Product Co-occurrence Matrix from Order Lines","\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines","advanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines\u002Findex",{"title":2610,"path":2611,"stem":2612,"children":-1},"Calculate Customer Lifetime Value from Order History","\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcalculate-customer-lifetime-value-from-order-history","advanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcalculate-customer-lifetime-value-from-order-history\u002Findex",[2614,2616],{"path":2615,"title":2592},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data",{"path":2617,"title":2589},"\u002Fadvanced-data-transformation-and-cleaning",[],[2620,2623,2626,2629,2632,2635],{"path":2621,"title":2622,"kind":2602},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-customer-churn-report-from-subscription-data","Build a Customer Churn Report from Subscription Data",{"path":2624,"title":2625,"kind":2602},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frefresh-pivot-tables-and-queries-in-excel-with-python","Refresh Excel Pivot Tables and Queries with Python",{"path":2627,"title":2628,"kind":2602},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fadd-a-native-excel-pivot-table-with-python","Add a Native Excel Pivot Table with Python",{"path":2630,"title":2631,"kind":2602},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fadd-subtotals-and-grand-totals-to-a-pandas-pivot-table","Add Subtotals and Grand Totals to a pandas Pivot Table",{"path":2633,"title":2634,"kind":2602},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbin-values-into-ranges-with-pandas-cut","Bin Values into Ranges Like Excel FREQUENCY with pd.cut",{"path":2636,"title":2532,"kind":2602},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-cohort-retention-table-from-excel-data",1790972086286]