[{"data":1,"prerenderedAt":2188},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines":2155,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines":2163,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines":2168,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines":2169},{"id":4,"title":5,"body":6,"dateModified":2121,"datePublished":2121,"description":2122,"extension":2123,"faq":2124,"keyword":2133,"kind":2134,"meta":2135,"navigation":97,"path":2144,"seo":2145,"slug":2148,"stem":2149,"topics":2150,"type":2153,"__hash__":2154},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines\u002Findex.md","Build a Product Co-occurrence Matrix from Order Lines",{"type":7,"value":8,"toc":2107},"minimark",[9,19,24,59,65,69,190,205,599,603,625,628,632,635,948,971,1007,1095,1099,1102,1215,1218,1222,1439,1446,1742,1746,1749,1964,1971,1975,1986,1990,2025,2029,2036,2040,2052,2058,2064,2070,2074,2103],[10,11,12,13,18],"p",{},"\"Customers who bought a drill also bought…\" is one of the most useful questions a sales dataset can answer: it drives cross-sell suggestions, shelf placement, bundle pricing and stock planning. The data usually already exists as order lines — one row per product per order — in an Excel export. Turning that into a product × product table of how often each pair appears in the same order is a short piece of pandas: build an order × product table of 0s and 1s, and multiply it by its own transpose. From the counts, three standard measures — support, confidence and lift — separate genuinely related products from ones that just happen to be popular. This page belongs to ",[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 numpy openpyxl xlsxwriter\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47,50,53,56],"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}," numpy",[35,54,55],{"class":45}," openpyxl",[35,57,58],{"class":45}," xlsxwriter\n",[10,60,61,64],{},[32,62,63],{},"order_lines.xlsx"," holds 400 orders as order lines: order ID, product and quantity. Eight hardware and garden products; some are often bought together, some are just popular, and one order line is duplicated — the kind of glitch an export can contain.",[20,66,68],{"id":67},"step-1-an-order-product-incidence-table","Step 1 — An order × product incidence table",[25,70,74],{"className":71,"code":72,"language":73,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nlines = pd.read_excel(\"order_lines.xlsx\")\nbasket = pd.crosstab(lines[\"OrderID\"], lines[\"Product\"]).clip(upper=1)\nprint(basket.head())\nprint(basket.shape[0], \"orders,\", basket.shape[1], \"products\")\n","python",[32,75,76,92,99,117,152,161],{"__ignoreMap":30},[35,77,78,82,86,89],{"class":37,"line":38},[35,79,81],{"class":80},"s-kum","import",[35,83,85],{"class":84},"skGVy"," pandas ",[35,87,88],{"class":80},"as",[35,90,91],{"class":84}," pd\n",[35,93,95],{"class":37,"line":94},2,[35,96,98],{"emptyLinePlaceholder":97},true,"\n",[35,100,102,105,108,111,114],{"class":37,"line":101},3,[35,103,104],{"class":84},"lines ",[35,106,107],{"class":80},"=",[35,109,110],{"class":84}," pd.read_excel(",[35,112,113],{"class":45},"\"order_lines.xlsx\"",[35,115,116],{"class":84},")\n",[35,118,120,123,125,128,131,134,137,140,144,146,150],{"class":37,"line":119},4,[35,121,122],{"class":84},"basket ",[35,124,107],{"class":80},[35,126,127],{"class":84}," pd.crosstab(lines[",[35,129,130],{"class":45},"\"OrderID\"",[35,132,133],{"class":84},"], lines[",[35,135,136],{"class":45},"\"Product\"",[35,138,139],{"class":84},"]).clip(",[35,141,143],{"class":142},"sa561","upper",[35,145,107],{"class":80},[35,147,149],{"class":148},"sP0c6","1",[35,151,116],{"class":84},[35,153,155,158],{"class":37,"line":154},5,[35,156,157],{"class":148},"print",[35,159,160],{"class":84},"(basket.head())\n",[35,162,164,166,169,172,175,178,181,183,185,188],{"class":37,"line":163},6,[35,165,157],{"class":148},[35,167,168],{"class":84},"(basket.shape[",[35,170,171],{"class":148},"0",[35,173,174],{"class":84},"], ",[35,176,177],{"class":45},"\"orders,\"",[35,179,180],{"class":84},", basket.shape[",[35,182,149],{"class":148},[35,184,174],{"class":84},[35,186,187],{"class":45},"\"products\"",[35,189,116],{"class":84},[10,191,192,195,196,199,200,204],{},[32,193,194],{},"crosstab"," counts lines per order and product; ",[32,197,198],{},"clip(upper=1)"," turns any count above one into 1, so the table records only ",[201,202,203],"em",{},"whether"," an order contains a product. Clipping handles the duplicated line, and it also means quantities do not matter: an order with three pairs of gloves counts once for gloves, which is what \"bought together\" means. If you want quantity-weighted analysis, it is a different question and needs a different table.",[206,207,215,216,215,220,215,224,215,231,215,240,215,244,215,251,215,255,215,259,215,263,215,267,215,271,215,275,215,280,215,284,215,286,215,289,215,291,215,294,215,297,215,301,215,303,215,307,215,309,215,312,215,314,215,316,215,319,215,323,215,325,215,327,215,329,215,332,215,334,215,336,215,339,215,342,215,344,215,347,215,349,215,352,215,354,215,356,215,359,215,363,215,365,215,368,215,370,215,373,215,375,215,377,215,380,215,384,215,386,215,388,215,390,215,393,215,395,215,397,215,400,215,404,215,407,215,411,215,414,215,418,215,421,215,425,215,429,215,433,215,437,215,441,215,445,215,447,215,450,215,452,215,455,215,457,215,459,215,461,215,464,215,466,215,468,215,470,215,472,215,474,215,477,215,479,215,481,215,483,215,485,215,489,215,492,215,494,215,496,215,498,215,500,215,502,215,504,215,506,215,508,215,510,215,512,215,514,215,516,215,518,215,520,215,522,215,524,215,526,215,528,215,530,215,532,215,534,215,536,215,538,215,540,215,542,215,544,215,546,215,548,215,550,215,552,215,554,215,556,215,558,215,560,215,562,215,564,215,570,215,574,215,580,215,585,215,593],"svg",{"viewBox":208,"role":209,"ariaLabelledBy":210,"xmlns":213,"style":214},"4 0 752 248","img",[211,212],"co-incidence-t","co-incidence-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  ",[217,218,219],"title",{"id":211},"Order lines become a 0\u002F1 table of orders by products",[221,222,223],"desc",{"id":212},"On the left order lines — order 1001 with Drill and Drill bits, order 1002 with Gloves, order 1003 with Hose and Hose reel. On the right one row per order with a 1 under each product it contains.",[225,226],"rect",{"x":227,"y":171,"width":228,"height":229,"fill":230},"4","752","248","#ffffff",[225,232],{"x":233,"y":234,"width":235,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"20.0","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[225,241],{"x":242,"y":234,"width":243,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"52.0","49.6",[245,246,250],"text",{"x":247,"y":248,"style":249},"76.8","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[225,252],{"x":253,"y":234,"width":254,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"101.6","56.3",[245,256,258],{"x":257,"y":248,"style":249},"129.8","B",[225,260],{"x":261,"y":234,"width":262,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"158.0","33.1",[245,264,266],{"x":265,"y":248,"style":249},"174.5","C",[225,268],{"x":233,"y":269,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"64.0","28.0",[245,272,149],{"x":273,"y":274,"style":249},"36.0","83.0",[225,276],{"x":242,"y":269,"width":243,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},"#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[245,281,283],{"x":247,"y":274,"style":282},"font-size:10.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","OrderID",[225,285],{"x":253,"y":269,"width":254,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,287,288],{"x":257,"y":274,"style":282},"Product",[225,290],{"x":261,"y":269,"width":262,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,292,293],{"x":265,"y":274,"style":282},"Qty",[225,295],{"x":233,"y":296,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"92.0",[245,298,300],{"x":273,"y":299,"style":249},"111.0","2",[225,302],{"x":242,"y":296,"width":243,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,304,306],{"x":247,"y":299,"style":305},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","1001",[225,308],{"x":253,"y":296,"width":254,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,310,311],{"x":257,"y":299,"style":305},"Drill",[225,313],{"x":261,"y":296,"width":262,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,315,149],{"x":265,"y":299,"style":305},[225,317],{"x":233,"y":318,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"120.0",[245,320,322],{"x":273,"y":321,"style":249},"139.0","3",[225,324],{"x":242,"y":318,"width":243,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,326,306],{"x":247,"y":321,"style":305},[225,328],{"x":253,"y":318,"width":254,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,330,331],{"x":257,"y":321,"style":305},"Drill bits",[225,333],{"x":261,"y":318,"width":262,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,335,300],{"x":265,"y":321,"style":305},[225,337],{"x":233,"y":338,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"148.0",[245,340,227],{"x":273,"y":341,"style":249},"167.0",[225,343],{"x":242,"y":338,"width":243,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,345,346],{"x":247,"y":341,"style":305},"1002",[225,348],{"x":253,"y":338,"width":254,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,350,351],{"x":257,"y":341,"style":305},"Gloves",[225,353],{"x":261,"y":338,"width":262,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,355,322],{"x":265,"y":341,"style":305},[225,357],{"x":233,"y":358,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"176.0",[245,360,362],{"x":273,"y":361,"style":249},"195.0","5",[225,364],{"x":242,"y":358,"width":243,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,366,367],{"x":247,"y":361,"style":305},"1003",[225,369],{"x":253,"y":358,"width":254,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,371,372],{"x":257,"y":361,"style":305},"Hose",[225,374],{"x":261,"y":358,"width":262,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,376,149],{"x":265,"y":361,"style":305},[225,378],{"x":233,"y":379,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"204.0",[245,381,383],{"x":273,"y":382,"style":249},"223.0","6",[225,385],{"x":242,"y":379,"width":243,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,387,367],{"x":247,"y":382,"style":305},[225,389],{"x":253,"y":379,"width":254,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,391,392],{"x":257,"y":382,"style":305},"Hose reel",[225,394],{"x":261,"y":379,"width":262,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,396,149],{"x":265,"y":382,"style":305},[225,398],{"x":399,"y":234,"width":235,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"474.1",[225,401],{"x":402,"y":234,"width":403,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"506.1","42.1",[245,405,250],{"x":406,"y":248,"style":249},"527.2",[225,408],{"x":409,"y":234,"width":410,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"548.2","34.8",[245,412,258],{"x":413,"y":248,"style":249},"565.6",[225,415],{"x":416,"y":234,"width":417,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"583.0","34.1",[245,419,266],{"x":420,"y":248,"style":249},"600.0",[225,422],{"x":423,"y":234,"width":424,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"617.1","47.0",[245,426,428],{"x":427,"y":248,"style":249},"640.6","D",[225,430],{"x":431,"y":234,"width":432,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"664.1","39.6",[245,434,436],{"x":435,"y":248,"style":249},"683.9","E",[225,438],{"x":439,"y":234,"width":440,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"703.7","36.3",[245,442,444],{"x":443,"y":248,"style":249},"721.9","F",[225,446],{"x":399,"y":269,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},[245,448,149],{"x":449,"y":274,"style":249},"490.1",[225,451],{"x":402,"y":269,"width":403,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,453,454],{"x":406,"y":274,"style":282},"Order",[225,456],{"x":409,"y":269,"width":410,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,458,311],{"x":413,"y":274,"style":282},[225,460],{"x":416,"y":269,"width":417,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,462,463],{"x":420,"y":274,"style":282},"Bits",[225,465],{"x":423,"y":269,"width":424,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,467,351],{"x":427,"y":274,"style":282},[225,469],{"x":431,"y":269,"width":432,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,471,372],{"x":435,"y":274,"style":282},[225,473],{"x":439,"y":269,"width":440,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,475,476],{"x":443,"y":274,"style":282},"Reel",[225,478],{"x":399,"y":296,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},[245,480,300],{"x":449,"y":299,"style":249},[225,482],{"x":402,"y":296,"width":403,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,484,306],{"x":406,"y":299,"style":305},[225,486],{"x":409,"y":296,"width":410,"height":270,"rx":171,"fill":487,"stroke":488,"style":279},"#d9f4f1","var(--teal,#0f9488)",[245,490,149],{"x":413,"y":299,"style":491},"font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[225,493],{"x":416,"y":296,"width":417,"height":270,"rx":171,"fill":487,"stroke":488,"style":279},[245,495,149],{"x":420,"y":299,"style":491},[225,497],{"x":423,"y":296,"width":424,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,499,171],{"x":427,"y":299,"style":305},[225,501],{"x":431,"y":296,"width":432,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,503,171],{"x":435,"y":299,"style":305},[225,505],{"x":439,"y":296,"width":440,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,507,171],{"x":443,"y":299,"style":305},[225,509],{"x":399,"y":318,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},[245,511,322],{"x":449,"y":321,"style":249},[225,513],{"x":402,"y":318,"width":403,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,515,346],{"x":406,"y":321,"style":305},[225,517],{"x":409,"y":318,"width":410,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,519,171],{"x":413,"y":321,"style":305},[225,521],{"x":416,"y":318,"width":417,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,523,171],{"x":420,"y":321,"style":305},[225,525],{"x":423,"y":318,"width":424,"height":270,"rx":171,"fill":487,"stroke":488,"style":279},[245,527,149],{"x":427,"y":321,"style":491},[225,529],{"x":431,"y":318,"width":432,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,531,171],{"x":435,"y":321,"style":305},[225,533],{"x":439,"y":318,"width":440,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,535,171],{"x":443,"y":321,"style":305},[225,537],{"x":399,"y":338,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},[245,539,227],{"x":449,"y":341,"style":249},[225,541],{"x":402,"y":338,"width":403,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,543,367],{"x":406,"y":341,"style":305},[225,545],{"x":409,"y":338,"width":410,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,547,171],{"x":413,"y":341,"style":305},[225,549],{"x":416,"y":338,"width":417,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,551,171],{"x":420,"y":341,"style":305},[225,553],{"x":423,"y":338,"width":424,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,555,171],{"x":427,"y":341,"style":305},[225,557],{"x":431,"y":338,"width":432,"height":270,"rx":171,"fill":487,"stroke":488,"style":279},[245,559,149],{"x":435,"y":341,"style":491},[225,561],{"x":439,"y":338,"width":440,"height":270,"rx":171,"fill":487,"stroke":488,"style":279},[245,563,149],{"x":443,"y":341,"style":491},[245,565,569],{"x":566,"y":567,"style":568},"105.5","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","order lines",[245,571,573],{"x":572,"y":567,"style":568},"607.1","incidence table",[37,575],{"x1":576,"y1":577,"x2":578,"y2":577,"stroke":278,"style":579},"201.0","108.0","460.1","stroke-width:2px",[581,582],"polygon",{"points":583,"fill":584},"464.1,108.0 455.1,113.0 455.1,103.0","#5b5cf0",[225,586],{"x":587,"y":588,"width":589,"height":590,"rx":591,"fill":230,"stroke":238,"style":592},"235.3","75.0","194.5","22.0","11","stroke-width:1.2px",[245,594,598],{"x":595,"y":596,"style":597},"332.6","90.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","crosstab + clip(upper=1)",[20,600,602],{"id":601},"step-2-co-occurrence-counts-with-one-matrix-product","Step 2 — Co-occurrence counts with one matrix product",[25,604,606],{"className":71,"code":605,"language":73,"meta":30,"style":30},"co = basket.T.dot(basket)\nprint(co)\n",[32,607,608,618],{"__ignoreMap":30},[35,609,610,613,615],{"class":37,"line":38},[35,611,612],{"class":84},"co ",[35,614,107],{"class":80},[35,616,617],{"class":84}," basket.T.dot(basket)\n",[35,619,620,622],{"class":37,"line":94},[35,621,157],{"class":148},[35,623,624],{"class":84},"(co)\n",[10,626,627],{},"Multiplying the transposed table by itself counts, for every pair of products, the orders that contain both: each order contributes 1 × 1 to the cells of the products it holds together. The diagonal is each product's own order count (a product always co-occurs with itself), and the matrix is symmetric — drill with bits equals bits with drill. With eight products the result is an 8 × 8 table; with a few thousand products it is still one fast operation, though the table becomes too large to read and Step 4's pair list becomes the useful output.",[20,629,631],{"id":630},"step-3-support-confidence-and-lift","Step 3 — Support, confidence and lift",[10,633,634],{},"Raw counts favour popular products: gloves appear with everything because gloves are in a third of all orders. Three ratios correct for that:",[25,636,638],{"className":71,"code":637,"language":73,"meta":30,"style":30},"import numpy as np\n\nn_orders = len(basket)\ncounts = pd.Series(np.diag(co), index=co.index)\nupper = co.where(np.triu(np.ones(co.shape, dtype=bool), k=1)).rename_axis(index=\"A\", columns=\"B\")\npairs = upper.stack().dropna().rename(\"Together\").reset_index()\npairs[\"Together\"] = pairs[\"Together\"].astype(int)\npairs[\"Support\"] = pairs[\"Together\"] \u002F n_orders\npairs[\"Conf A→B\"] = pairs[\"Together\"] \u002F pairs[\"A\"].map(counts)\npairs[\"Conf B→A\"] = pairs[\"Together\"] \u002F pairs[\"B\"].map(counts)\npairs[\"Lift\"] = pairs[\"Support\"] \u002F ((pairs[\"A\"].map(counts) \u002F n_orders) * (pairs[\"B\"].map(counts) \u002F n_orders))\nprint(pairs.sort_values(\"Lift\", ascending=False).round(3).head(8).to_string(index=False))\n",[32,639,640,652,656,669,687,738,754,780,804,831,857,905],{"__ignoreMap":30},[35,641,642,644,647,649],{"class":37,"line":38},[35,643,81],{"class":80},[35,645,646],{"class":84}," numpy ",[35,648,88],{"class":80},[35,650,651],{"class":84}," np\n",[35,653,654],{"class":37,"line":94},[35,655,98],{"emptyLinePlaceholder":97},[35,657,658,661,663,666],{"class":37,"line":101},[35,659,660],{"class":84},"n_orders ",[35,662,107],{"class":80},[35,664,665],{"class":148}," len",[35,667,668],{"class":84},"(basket)\n",[35,670,671,674,676,679,682,684],{"class":37,"line":119},[35,672,673],{"class":84},"counts ",[35,675,107],{"class":80},[35,677,678],{"class":84}," pd.Series(np.diag(co), ",[35,680,681],{"class":142},"index",[35,683,107],{"class":80},[35,685,686],{"class":84},"co.index)\n",[35,688,689,692,694,697,700,702,705,708,711,713,715,718,720,722,725,728,731,733,736],{"class":37,"line":154},[35,690,691],{"class":84},"upper ",[35,693,107],{"class":80},[35,695,696],{"class":84}," co.where(np.triu(np.ones(co.shape, ",[35,698,699],{"class":142},"dtype",[35,701,107],{"class":80},[35,703,704],{"class":148},"bool",[35,706,707],{"class":84},"), ",[35,709,710],{"class":142},"k",[35,712,107],{"class":80},[35,714,149],{"class":148},[35,716,717],{"class":84},")).rename_axis(",[35,719,681],{"class":142},[35,721,107],{"class":80},[35,723,724],{"class":45},"\"A\"",[35,726,727],{"class":84},", ",[35,729,730],{"class":142},"columns",[35,732,107],{"class":80},[35,734,735],{"class":45},"\"B\"",[35,737,116],{"class":84},[35,739,740,743,745,748,751],{"class":37,"line":163},[35,741,742],{"class":84},"pairs ",[35,744,107],{"class":80},[35,746,747],{"class":84}," upper.stack().dropna().rename(",[35,749,750],{"class":45},"\"Together\"",[35,752,753],{"class":84},").reset_index()\n",[35,755,757,760,762,765,767,770,772,775,778],{"class":37,"line":756},7,[35,758,759],{"class":84},"pairs[",[35,761,750],{"class":45},[35,763,764],{"class":84},"] ",[35,766,107],{"class":80},[35,768,769],{"class":84}," pairs[",[35,771,750],{"class":45},[35,773,774],{"class":84},"].astype(",[35,776,777],{"class":148},"int",[35,779,116],{"class":84},[35,781,783,785,788,790,792,794,796,798,801],{"class":37,"line":782},8,[35,784,759],{"class":84},[35,786,787],{"class":45},"\"Support\"",[35,789,764],{"class":84},[35,791,107],{"class":80},[35,793,769],{"class":84},[35,795,750],{"class":45},[35,797,764],{"class":84},[35,799,800],{"class":80},"\u002F",[35,802,803],{"class":84}," n_orders\n",[35,805,807,809,812,814,816,818,820,822,824,826,828],{"class":37,"line":806},9,[35,808,759],{"class":84},[35,810,811],{"class":45},"\"Conf A→B\"",[35,813,764],{"class":84},[35,815,107],{"class":80},[35,817,769],{"class":84},[35,819,750],{"class":45},[35,821,764],{"class":84},[35,823,800],{"class":80},[35,825,769],{"class":84},[35,827,724],{"class":45},[35,829,830],{"class":84},"].map(counts)\n",[35,832,834,836,839,841,843,845,847,849,851,853,855],{"class":37,"line":833},10,[35,835,759],{"class":84},[35,837,838],{"class":45},"\"Conf B→A\"",[35,840,764],{"class":84},[35,842,107],{"class":80},[35,844,769],{"class":84},[35,846,750],{"class":45},[35,848,764],{"class":84},[35,850,800],{"class":80},[35,852,769],{"class":84},[35,854,735],{"class":45},[35,856,830],{"class":84},[35,858,860,862,865,867,869,871,873,875,877,880,882,885,887,890,893,896,898,900,902],{"class":37,"line":859},11,[35,861,759],{"class":84},[35,863,864],{"class":45},"\"Lift\"",[35,866,764],{"class":84},[35,868,107],{"class":80},[35,870,769],{"class":84},[35,872,787],{"class":45},[35,874,764],{"class":84},[35,876,800],{"class":80},[35,878,879],{"class":84}," ((pairs[",[35,881,724],{"class":45},[35,883,884],{"class":84},"].map(counts) ",[35,886,800],{"class":80},[35,888,889],{"class":84}," n_orders) ",[35,891,892],{"class":80},"*",[35,894,895],{"class":84}," (pairs[",[35,897,735],{"class":45},[35,899,884],{"class":84},[35,901,800],{"class":80},[35,903,904],{"class":84}," n_orders))\n",[35,906,908,910,913,915,917,920,922,925,928,930,933,936,939,941,943,945],{"class":37,"line":907},12,[35,909,157],{"class":148},[35,911,912],{"class":84},"(pairs.sort_values(",[35,914,864],{"class":45},[35,916,727],{"class":84},[35,918,919],{"class":142},"ascending",[35,921,107],{"class":80},[35,923,924],{"class":148},"False",[35,926,927],{"class":84},").round(",[35,929,322],{"class":148},[35,931,932],{"class":84},").head(",[35,934,935],{"class":148},"8",[35,937,938],{"class":84},").to_string(",[35,940,681],{"class":142},[35,942,107],{"class":80},[35,944,924],{"class":148},[35,946,947],{"class":84},"))\n",[949,950,951,959,965],"ul",{},[952,953,954,958],"li",{},[955,956,957],"strong",{},"Support"," is the share of all orders that contain both products.",[952,960,961,964],{},[955,962,963],{},"Confidence A→B"," is the share of orders with A that also contain B — \"of drill buyers, how many bought bits?\" It is directional: B→A usually differs.",[952,966,967,970],{},[955,968,969],{},"Lift"," compares how often the pair occurs with how often it would if the products were bought independently. Above 1 means they go together more than chance; around 1 means no relationship; below 1 means they rarely meet.",[10,972,973,974,977,978,981,982,985,986,989,990,993,994,996,997,999,1000,1002,1003,1006],{},"Taking the upper triangle (",[32,975,976],{},"np.triu"," with ",[32,979,980],{},"k=1",") keeps each pair once and drops the diagonal; ",[32,983,984],{},"dropna()"," removes the masked lower half, which pandas 3's ",[32,987,988],{},"stack"," keeps as ",[32,991,992],{},"NaN"," rows; and renaming the axes to ",[32,995,250],{}," and ",[32,998,258],{}," first matters, because both axes are called ",[32,1001,288],{}," after the crosstab and ",[32,1004,1005],{},"reset_index"," refuses to create two columns with the same name. Sorted by lift, the true companions — drill with bits and wall plugs, hose with hose reel — come first, while gloves, despite large raw counts with everything, have lift at or below 1 — gloves and drills share 64 orders, yet that is fewer than independence would predict.",[206,1008,215,1014,215,1017,215,1020,215,1024,215,1029,215,1035,215,1039,215,1044,215,1047,215,1051,215,1054,215,1058,215,1061,215,1065,215,1068,215,1072,215,1075,215,1079,215,1084,215,1089],{"viewBox":1009,"role":209,"ariaLabelledBy":1010,"xmlns":213,"style":1013},"4 0 684 206",[1011,1012],"co-lift-t","co-lift-d","width:100%;max-width:684px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[217,1015,1016],{"id":1011},"Lift separates real companions from popular products",[221,1018,1019],{"id":1012},"Lift for selected pairs. Hose with Hose reel has lift 3.27, Drill bits with Wall plugs 2.5 and Drill with Drill bits 2.34, so they are bought together far more than chance. Gloves with Drill has lift 0.81 despite 64 shared orders, because gloves are in many orders anyway.",[225,1021],{"x":227,"y":171,"width":1022,"height":1023,"fill":230},"684","206",[225,1025],{"x":233,"y":1026,"width":1027,"height":270,"rx":1028,"fill":237,"stroke":238,"style":239},"16.0","162.8","7",[245,1030,1034],{"x":1031,"y":1032,"style":1033},"101.4","34.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Hose ~ Hose reel",[225,1036],{"x":1037,"y":1026,"width":1038,"height":270,"rx":1028,"fill":487,"stroke":488,"style":279},"192.8","421.4",[245,1040,1043],{"x":1041,"y":1032,"style":1042},"622.3","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","3.27",[225,1045],{"x":233,"y":1046,"width":1027,"height":270,"rx":1028,"fill":237,"stroke":238,"style":239},"56.0",[245,1048,1050],{"x":1031,"y":1049,"style":1033},"74.5","Drill bits ~ Wall plugs",[225,1052],{"x":1037,"y":1046,"width":1053,"height":270,"rx":1028,"fill":487,"stroke":488,"style":279},"322.2",[245,1055,1057],{"x":1056,"y":1049,"style":1042},"523.0","2.5",[225,1059],{"x":233,"y":1060,"width":1027,"height":270,"rx":1028,"fill":237,"stroke":238,"style":239},"96.0",[245,1062,1064],{"x":1031,"y":1063,"style":1033},"114.5","Drill ~ Drill bits",[225,1066],{"x":1037,"y":1060,"width":1067,"height":270,"rx":1028,"fill":487,"stroke":488,"style":279},"301.6",[245,1069,1071],{"x":1070,"y":1063,"style":1042},"502.4","2.34",[225,1073],{"x":233,"y":1074,"width":1027,"height":270,"rx":1028,"fill":237,"stroke":238,"style":239},"136.0",[245,1076,1078],{"x":1031,"y":1077,"style":1033},"154.5","Gloves ~ Drill",[225,1080],{"x":1037,"y":1074,"width":1081,"height":270,"rx":1028,"fill":1082,"stroke":1083,"style":279},"104.4","#fdefd8","var(--gold,#b4740a)",[245,1085,1088],{"x":1086,"y":1077,"style":1087},"305.2","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","0.81 · just popular",[245,1090,1094],{"x":1091,"y":1092,"style":1093},"380.0","186.0","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","Gloves and drills share 64 orders, more than most pairs — yet less than chance would predict.",[20,1096,1098],{"id":1097},"step-4-filter-out-pairs-that-are-too-rare-to-trust","Step 4 — Filter out pairs that are too rare to trust",[10,1100,1101],{},"Lift is unstable for rare products: two orders that both contain a slow seller can produce an enormous lift from pure chance. Set a minimum number of orders before ranking:",[25,1103,1105],{"className":71,"code":1104,"language":73,"meta":30,"style":30},"MIN_TOGETHER = 15\ntop = (pairs[pairs[\"Together\"] >= MIN_TOGETHER]\n       .sort_values([\"Lift\", \"Together\"], ascending=False)\n       .head(5))\nprint(top[[\"A\", \"B\", \"Together\", \"Conf A→B\", \"Conf B→A\", \"Lift\"]].round(2).to_string(index=False))\n",[32,1106,1107,1118,1141,1162,1171],{"__ignoreMap":30},[35,1108,1109,1112,1115],{"class":37,"line":38},[35,1110,1111],{"class":148},"MIN_TOGETHER",[35,1113,1114],{"class":80}," =",[35,1116,1117],{"class":148}," 15\n",[35,1119,1120,1123,1125,1128,1130,1132,1135,1138],{"class":37,"line":94},[35,1121,1122],{"class":84},"top ",[35,1124,107],{"class":80},[35,1126,1127],{"class":84}," (pairs[pairs[",[35,1129,750],{"class":45},[35,1131,764],{"class":84},[35,1133,1134],{"class":80},">=",[35,1136,1137],{"class":148}," MIN_TOGETHER",[35,1139,1140],{"class":84},"]\n",[35,1142,1143,1146,1148,1150,1152,1154,1156,1158,1160],{"class":37,"line":101},[35,1144,1145],{"class":84},"       .sort_values([",[35,1147,864],{"class":45},[35,1149,727],{"class":84},[35,1151,750],{"class":45},[35,1153,174],{"class":84},[35,1155,919],{"class":142},[35,1157,107],{"class":80},[35,1159,924],{"class":148},[35,1161,116],{"class":84},[35,1163,1164,1167,1169],{"class":37,"line":119},[35,1165,1166],{"class":84},"       .head(",[35,1168,362],{"class":148},[35,1170,947],{"class":84},[35,1172,1173,1175,1178,1180,1182,1184,1186,1188,1190,1192,1194,1196,1198,1200,1203,1205,1207,1209,1211,1213],{"class":37,"line":154},[35,1174,157],{"class":148},[35,1176,1177],{"class":84},"(top[[",[35,1179,724],{"class":45},[35,1181,727],{"class":84},[35,1183,735],{"class":45},[35,1185,727],{"class":84},[35,1187,750],{"class":45},[35,1189,727],{"class":84},[35,1191,811],{"class":45},[35,1193,727],{"class":84},[35,1195,838],{"class":45},[35,1197,727],{"class":84},[35,1199,864],{"class":45},[35,1201,1202],{"class":84},"]].round(",[35,1204,300],{"class":148},[35,1206,938],{"class":84},[35,1208,681],{"class":142},[35,1210,107],{"class":80},[35,1212,924],{"class":148},[35,1214,947],{"class":84},[10,1216,1217],{},"A threshold of 15 orders is a judgement call that depends on volume; the point is to have one. The resulting short list is what merchandisers act on, with both confidences shown so they can see the direction: most hose-reel buyers bought a hose, but many hose buyers did not buy a reel — the cross-sell opportunity.",[20,1219,1221],{"id":1220},"step-5-write-a-heatmap-and-the-top-pairs-to-excel","Step 5 — Write a heatmap and the top pairs to Excel",[25,1223,1225],{"className":71,"code":1224,"language":73,"meta":30,"style":30},"with pd.ExcelWriter(\"co_occurrence.xlsx\", engine=\"xlsxwriter\") as xw:\n    co.to_excel(xw, sheet_name=\"Matrix\")\n    ws = xw.sheets[\"Matrix\"]\n    ws.conditional_format(1, 1, len(co), len(co.columns), {\"type\": \"2_color_scale\",\n                          \"min_color\": \"#FFFFFF\", \"max_color\": \"#5B5CF0\"})\n    ws.set_column(0, len(co.columns), 11)\n    pairs.sort_values(\"Lift\", ascending=False).round(3).to_excel(xw, sheet_name=\"Pairs\", index=False)\n    top.round(3).to_excel(xw, sheet_name=\"Top pairs\", index=False)\nprint(\"sheets written: Matrix, Pairs, Top pairs\")\n",[32,1226,1227,1256,1271,1285,1321,1344,1362,1401,1427],{"__ignoreMap":30},[35,1228,1229,1232,1235,1238,1240,1243,1245,1248,1251,1253],{"class":37,"line":38},[35,1230,1231],{"class":80},"with",[35,1233,1234],{"class":84}," pd.ExcelWriter(",[35,1236,1237],{"class":45},"\"co_occurrence.xlsx\"",[35,1239,727],{"class":84},[35,1241,1242],{"class":142},"engine",[35,1244,107],{"class":80},[35,1246,1247],{"class":45},"\"xlsxwriter\"",[35,1249,1250],{"class":84},") ",[35,1252,88],{"class":80},[35,1254,1255],{"class":84}," xw:\n",[35,1257,1258,1261,1264,1266,1269],{"class":37,"line":94},[35,1259,1260],{"class":84},"    co.to_excel(xw, ",[35,1262,1263],{"class":142},"sheet_name",[35,1265,107],{"class":80},[35,1267,1268],{"class":45},"\"Matrix\"",[35,1270,116],{"class":84},[35,1272,1273,1276,1278,1281,1283],{"class":37,"line":101},[35,1274,1275],{"class":84},"    ws ",[35,1277,107],{"class":80},[35,1279,1280],{"class":84}," xw.sheets[",[35,1282,1268],{"class":45},[35,1284,1140],{"class":84},[35,1286,1287,1290,1292,1294,1296,1298,1301,1304,1306,1309,1312,1315,1318],{"class":37,"line":119},[35,1288,1289],{"class":84},"    ws.conditional_format(",[35,1291,149],{"class":148},[35,1293,727],{"class":84},[35,1295,149],{"class":148},[35,1297,727],{"class":84},[35,1299,1300],{"class":148},"len",[35,1302,1303],{"class":84},"(co), ",[35,1305,1300],{"class":148},[35,1307,1308],{"class":84},"(co.columns), {",[35,1310,1311],{"class":45},"\"type\"",[35,1313,1314],{"class":84},": ",[35,1316,1317],{"class":45},"\"2_color_scale\"",[35,1319,1320],{"class":84},",\n",[35,1322,1323,1326,1328,1331,1333,1336,1338,1341],{"class":37,"line":154},[35,1324,1325],{"class":45},"                          \"min_color\"",[35,1327,1314],{"class":84},[35,1329,1330],{"class":45},"\"#FFFFFF\"",[35,1332,727],{"class":84},[35,1334,1335],{"class":45},"\"max_color\"",[35,1337,1314],{"class":84},[35,1339,1340],{"class":45},"\"#5B5CF0\"",[35,1342,1343],{"class":84},"})\n",[35,1345,1346,1349,1351,1353,1355,1358,1360],{"class":37,"line":163},[35,1347,1348],{"class":84},"    ws.set_column(",[35,1350,171],{"class":148},[35,1352,727],{"class":84},[35,1354,1300],{"class":148},[35,1356,1357],{"class":84},"(co.columns), ",[35,1359,591],{"class":148},[35,1361,116],{"class":84},[35,1363,1364,1367,1369,1371,1373,1375,1377,1379,1381,1384,1386,1388,1391,1393,1395,1397,1399],{"class":37,"line":756},[35,1365,1366],{"class":84},"    pairs.sort_values(",[35,1368,864],{"class":45},[35,1370,727],{"class":84},[35,1372,919],{"class":142},[35,1374,107],{"class":80},[35,1376,924],{"class":148},[35,1378,927],{"class":84},[35,1380,322],{"class":148},[35,1382,1383],{"class":84},").to_excel(xw, ",[35,1385,1263],{"class":142},[35,1387,107],{"class":80},[35,1389,1390],{"class":45},"\"Pairs\"",[35,1392,727],{"class":84},[35,1394,681],{"class":142},[35,1396,107],{"class":80},[35,1398,924],{"class":148},[35,1400,116],{"class":84},[35,1402,1403,1406,1408,1410,1412,1414,1417,1419,1421,1423,1425],{"class":37,"line":782},[35,1404,1405],{"class":84},"    top.round(",[35,1407,322],{"class":148},[35,1409,1383],{"class":84},[35,1411,1263],{"class":142},[35,1413,107],{"class":80},[35,1415,1416],{"class":45},"\"Top pairs\"",[35,1418,727],{"class":84},[35,1420,681],{"class":142},[35,1422,107],{"class":80},[35,1424,924],{"class":148},[35,1426,116],{"class":84},[35,1428,1429,1431,1434,1437],{"class":37,"line":806},[35,1430,157],{"class":148},[35,1432,1433],{"class":84},"(",[35,1435,1436],{"class":45},"\"sheets written: Matrix, Pairs, Top pairs\"",[35,1438,116],{"class":84},[10,1440,1441,1442,18],{},"The matrix sheet with a two-colour scale makes clusters visible at a glance — the drill group and the hose group light up as blocks. The pairs sheet is the full sortable list. Colour scales from Python are covered in ",[14,1443,1445],{"href":1444},"\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",[206,1447,215,1453,215,1456,215,1459,215,1464,215,1467,215,1471,215,1475,215,1479,215,1482,215,1486,215,1489,215,1492,215,1495,215,1499,215,1502,215,1506,215,1509,215,1513,215,1517,215,1519,215,1523,215,1525,215,1527,215,1529,215,1531,215,1533,215,1535,215,1538,215,1540,215,1542,215,1544,215,1546,215,1548,215,1550,215,1553,215,1556,215,1558,215,1560,215,1562,215,1565,215,1567,215,1570,215,1572,215,1575,215,1577,215,1580,215,1582,215,1585,215,1587,215,1590,215,1592,215,1595,215,1597,215,1599,215,1601,215,1603,215,1605,215,1608,215,1610,215,1613,215,1615,215,1618,215,1620,215,1623,215,1625,215,1628,215,1631,215,1634,215,1636,215,1638,215,1640,215,1642,215,1644,215,1646,215,1648,215,1651,215,1653,215,1656,215,1658,215,1661,215,1663,215,1666,215,1669,215,1672,215,1674,215,1676,215,1678,215,1680,215,1682,215,1684,215,1686,215,1688,215,1690,215,1693,215,1695,215,1698,215,1700,215,1702,215,1705,215,1708,215,1710,215,1712,215,1714,215,1716,215,1718,215,1720,215,1722,215,1724,215,1726,215,1728,215,1730,215,1733,215,1735,215,1738],{"viewBox":1448,"role":209,"ariaLabelledBy":1449,"xmlns":213,"style":1452},"108 0 544 250",[1450,1451],"co-matrix-t","co-matrix-d","width:100%;max-width:544px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[217,1454,1455],{"id":1450},"The co-occurrence matrix as a heatmap",[221,1457,1458],{"id":1451},"A product by product matrix of shared orders. The diagonal holds each product's order count — 160 for Drill. Drill, Drill bits and Wall plugs form a block of high values (105, 75, 56), as do Hose and Hose reel (54); Gloves has moderate values with everything.",[225,1460],{"x":1461,"y":171,"width":1462,"height":1463,"fill":230},"108","544","250",[225,1465],{"x":1466,"y":1026,"width":235,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"184.7",[225,1468],{"x":1469,"y":1026,"width":1470,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"216.7","54.1",[245,1472,250],{"x":1473,"y":1474,"style":249},"243.7","33.0",[225,1476],{"x":1477,"y":1026,"width":1478,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"270.8","45.4",[245,1480,258],{"x":1481,"y":1474,"style":249},"293.5",[225,1483],{"x":1484,"y":1026,"width":1485,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"316.2","44.5",[245,1487,266],{"x":1488,"y":1474,"style":249},"338.5",[225,1490],{"x":1491,"y":1026,"width":1470,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"360.7",[245,1493,428],{"x":1494,"y":1474,"style":249},"387.8",[225,1496],{"x":1497,"y":1026,"width":1498,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"414.9","51.7",[245,1500,436],{"x":1501,"y":1474,"style":249},"440.7",[225,1503],{"x":1504,"y":1026,"width":1505,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"466.6","47.4",[245,1507,444],{"x":1508,"y":1474,"style":249},"490.3",[225,1510],{"x":1511,"y":1026,"width":1512,"height":236,"rx":171,"fill":237,"stroke":238,"style":239},"514.0","61.4",[245,1514,1516],{"x":1515,"y":1474,"style":249},"544.7","G",[225,1518],{"x":1466,"y":234,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},[245,1520,149],{"x":1521,"y":1522,"style":249},"200.7","59.0",[225,1524],{"x":1469,"y":234,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[225,1526],{"x":1477,"y":234,"width":1478,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1528,311],{"x":1481,"y":1522,"style":282},[225,1530],{"x":1484,"y":234,"width":1485,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1532,463],{"x":1488,"y":1522,"style":282},[225,1534],{"x":1491,"y":234,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1536,1537],{"x":1494,"y":1522,"style":282},"Plugs",[225,1539],{"x":1497,"y":234,"width":1498,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1541,372],{"x":1501,"y":1522,"style":282},[225,1543],{"x":1504,"y":234,"width":1505,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1545,476],{"x":1508,"y":1522,"style":282},[225,1547],{"x":1511,"y":234,"width":1512,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1549,351],{"x":1515,"y":1522,"style":282},[225,1551],{"x":1466,"y":1552,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"68.0",[245,1554,300],{"x":1521,"y":1555,"style":249},"87.0",[225,1557],{"x":1469,"y":1552,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1559,311],{"x":1473,"y":1555,"style":282},[225,1561],{"x":1477,"y":1552,"width":1478,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1563,1564],{"x":1481,"y":1555,"style":305},"160",[225,1566],{"x":1484,"y":1552,"width":1485,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1568,1569],{"x":1488,"y":1555,"style":282},"105",[225,1571],{"x":1491,"y":1552,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1573,1574],{"x":1494,"y":1555,"style":282},"75",[225,1576],{"x":1497,"y":1552,"width":1498,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1578,1579],{"x":1501,"y":1555,"style":305},"42",[225,1581],{"x":1504,"y":1552,"width":1505,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1583,1584],{"x":1508,"y":1555,"style":305},"23",[225,1586],{"x":1511,"y":1552,"width":1512,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1588,1589],{"x":1515,"y":1555,"style":305},"64",[225,1591],{"x":1466,"y":1060,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},[245,1593,322],{"x":1521,"y":1594,"style":249},"115.0",[225,1596],{"x":1469,"y":1060,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1598,463],{"x":1473,"y":1594,"style":282},[225,1600],{"x":1477,"y":1060,"width":1478,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1602,1569],{"x":1481,"y":1594,"style":282},[225,1604],{"x":1484,"y":1060,"width":1485,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1606,1607],{"x":1488,"y":1594,"style":305},"112",[225,1609],{"x":1491,"y":1060,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1611,1612],{"x":1494,"y":1594,"style":282},"56",[225,1614],{"x":1497,"y":1060,"width":1498,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1616,1617],{"x":1501,"y":1594,"style":305},"33",[225,1619],{"x":1504,"y":1060,"width":1505,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1621,1622],{"x":1508,"y":1594,"style":305},"20",[225,1624],{"x":1511,"y":1060,"width":1512,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1626,1627],{"x":1515,"y":1594,"style":305},"45",[225,1629],{"x":1466,"y":1630,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"124.0",[245,1632,227],{"x":1521,"y":1633,"style":249},"143.0",[225,1635],{"x":1469,"y":1630,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1637,1537],{"x":1473,"y":1633,"style":282},[225,1639],{"x":1477,"y":1630,"width":1478,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1641,1574],{"x":1481,"y":1633,"style":282},[225,1643],{"x":1484,"y":1630,"width":1485,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1645,1612],{"x":1488,"y":1633,"style":282},[225,1647],{"x":1491,"y":1630,"width":1470,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1649,1650],{"x":1494,"y":1633,"style":305},"80",[225,1652],{"x":1497,"y":1630,"width":1498,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1654,1655],{"x":1501,"y":1633,"style":305},"22",[225,1657],{"x":1504,"y":1630,"width":1505,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1659,1660],{"x":1508,"y":1633,"style":305},"15",[225,1662],{"x":1511,"y":1630,"width":1512,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1664,1665],{"x":1515,"y":1633,"style":305},"30",[225,1667],{"x":1466,"y":1668,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"152.0",[245,1670,362],{"x":1521,"y":1671,"style":249},"171.0",[225,1673],{"x":1469,"y":1668,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1675,372],{"x":1473,"y":1671,"style":282},[225,1677],{"x":1477,"y":1668,"width":1478,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1679,1579],{"x":1481,"y":1671,"style":305},[225,1681],{"x":1484,"y":1668,"width":1485,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1683,1617],{"x":1488,"y":1671,"style":305},[225,1685],{"x":1491,"y":1668,"width":1470,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1687,1655],{"x":1494,"y":1671,"style":305},[225,1689],{"x":1497,"y":1668,"width":1498,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1691,1692],{"x":1501,"y":1671,"style":305},"110",[225,1694],{"x":1504,"y":1668,"width":1505,"height":270,"rx":171,"fill":487,"stroke":488,"style":279},[245,1696,1697],{"x":1508,"y":1671,"style":491},"54",[225,1699],{"x":1511,"y":1668,"width":1512,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1701,1627],{"x":1515,"y":1671,"style":305},[225,1703],{"x":1466,"y":1704,"width":235,"height":270,"rx":171,"fill":237,"stroke":238,"style":239},"180.0",[245,1706,383],{"x":1521,"y":1707,"style":249},"199.0",[225,1709],{"x":1469,"y":1704,"width":1470,"height":270,"rx":171,"fill":277,"stroke":278,"style":279},[245,1711,476],{"x":1473,"y":1707,"style":282},[225,1713],{"x":1477,"y":1704,"width":1478,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1715,1584],{"x":1481,"y":1707,"style":305},[225,1717],{"x":1484,"y":1704,"width":1485,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1719,1622],{"x":1488,"y":1707,"style":305},[225,1721],{"x":1491,"y":1704,"width":1470,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1723,1660],{"x":1494,"y":1707,"style":305},[225,1725],{"x":1497,"y":1704,"width":1498,"height":270,"rx":171,"fill":487,"stroke":488,"style":279},[245,1727,1697],{"x":1501,"y":1707,"style":491},[225,1729],{"x":1504,"y":1704,"width":1505,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1731,1732],{"x":1508,"y":1707,"style":305},"60",[225,1734],{"x":1511,"y":1704,"width":1512,"height":270,"rx":171,"fill":230,"stroke":238,"style":239},[245,1736,1737],{"x":1515,"y":1707,"style":305},"25",[245,1739,1741],{"x":1091,"y":1740,"style":1093},"230.0","The diagonal holds each product's own order count, e.g. 160 orders contain a drill.",[20,1743,1745],{"id":1744},"step-6-recommendations-per-product","Step 6 — Recommendations per product",[10,1747,1748],{},"For a product page or a sales script, turn the pairs into \"top companions\" for each product, ranked by confidence in that direction, with the same minimum count:",[25,1750,1752],{"className":71,"code":1751,"language":73,"meta":30,"style":30},"both_ways = pd.concat([\n    pairs.rename(columns={\"A\": \"Product\", \"B\": \"Companion\", \"Conf A→B\": \"Confidence\"}),\n    pairs.rename(columns={\"B\": \"Product\", \"A\": \"Companion\", \"Conf B→A\": \"Confidence\"}),\n])[[\"Product\", \"Companion\", \"Together\", \"Confidence\", \"Lift\"]]\nrecs = (both_ways[(both_ways[\"Together\"] >= MIN_TOGETHER) & (both_ways[\"Lift\"] > 1.1)]\n        .sort_values([\"Product\", \"Confidence\"], ascending=[True, False])\n        .groupby(\"Product\").head(2))\nprint(recs.round(2).to_string(index=False))\n",[32,1753,1754,1764,1803,1837,1863,1902,1932,1945],{"__ignoreMap":30},[35,1755,1756,1759,1761],{"class":37,"line":38},[35,1757,1758],{"class":84},"both_ways ",[35,1760,107],{"class":80},[35,1762,1763],{"class":84}," pd.concat([\n",[35,1765,1766,1769,1771,1773,1776,1778,1780,1782,1784,1786,1788,1791,1793,1795,1797,1800],{"class":37,"line":94},[35,1767,1768],{"class":84},"    pairs.rename(",[35,1770,730],{"class":142},[35,1772,107],{"class":80},[35,1774,1775],{"class":84},"{",[35,1777,724],{"class":45},[35,1779,1314],{"class":84},[35,1781,136],{"class":45},[35,1783,727],{"class":84},[35,1785,735],{"class":45},[35,1787,1314],{"class":84},[35,1789,1790],{"class":45},"\"Companion\"",[35,1792,727],{"class":84},[35,1794,811],{"class":45},[35,1796,1314],{"class":84},[35,1798,1799],{"class":45},"\"Confidence\"",[35,1801,1802],{"class":84},"}),\n",[35,1804,1805,1807,1809,1811,1813,1815,1817,1819,1821,1823,1825,1827,1829,1831,1833,1835],{"class":37,"line":101},[35,1806,1768],{"class":84},[35,1808,730],{"class":142},[35,1810,107],{"class":80},[35,1812,1775],{"class":84},[35,1814,735],{"class":45},[35,1816,1314],{"class":84},[35,1818,136],{"class":45},[35,1820,727],{"class":84},[35,1822,724],{"class":45},[35,1824,1314],{"class":84},[35,1826,1790],{"class":45},[35,1828,727],{"class":84},[35,1830,838],{"class":45},[35,1832,1314],{"class":84},[35,1834,1799],{"class":45},[35,1836,1802],{"class":84},[35,1838,1839,1842,1844,1846,1848,1850,1852,1854,1856,1858,1860],{"class":37,"line":119},[35,1840,1841],{"class":84},"])[[",[35,1843,136],{"class":45},[35,1845,727],{"class":84},[35,1847,1790],{"class":45},[35,1849,727],{"class":84},[35,1851,750],{"class":45},[35,1853,727],{"class":84},[35,1855,1799],{"class":45},[35,1857,727],{"class":84},[35,1859,864],{"class":45},[35,1861,1862],{"class":84},"]]\n",[35,1864,1865,1868,1870,1873,1875,1877,1879,1881,1883,1886,1889,1891,1893,1896,1899],{"class":37,"line":154},[35,1866,1867],{"class":84},"recs ",[35,1869,107],{"class":80},[35,1871,1872],{"class":84}," (both_ways[(both_ways[",[35,1874,750],{"class":45},[35,1876,764],{"class":84},[35,1878,1134],{"class":80},[35,1880,1137],{"class":148},[35,1882,1250],{"class":84},[35,1884,1885],{"class":80},"&",[35,1887,1888],{"class":84}," (both_ways[",[35,1890,864],{"class":45},[35,1892,764],{"class":84},[35,1894,1895],{"class":80},">",[35,1897,1898],{"class":148}," 1.1",[35,1900,1901],{"class":84},")]\n",[35,1903,1904,1907,1909,1911,1913,1915,1917,1919,1922,1925,1927,1929],{"class":37,"line":163},[35,1905,1906],{"class":84},"        .sort_values([",[35,1908,136],{"class":45},[35,1910,727],{"class":84},[35,1912,1799],{"class":45},[35,1914,174],{"class":84},[35,1916,919],{"class":142},[35,1918,107],{"class":80},[35,1920,1921],{"class":84},"[",[35,1923,1924],{"class":148},"True",[35,1926,727],{"class":84},[35,1928,924],{"class":148},[35,1930,1931],{"class":84},"])\n",[35,1933,1934,1937,1939,1941,1943],{"class":37,"line":756},[35,1935,1936],{"class":84},"        .groupby(",[35,1938,136],{"class":45},[35,1940,932],{"class":84},[35,1942,300],{"class":148},[35,1944,947],{"class":84},[35,1946,1947,1949,1952,1954,1956,1958,1960,1962],{"class":37,"line":782},[35,1948,157],{"class":148},[35,1950,1951],{"class":84},"(recs.round(",[35,1953,300],{"class":148},[35,1955,938],{"class":84},[35,1957,681],{"class":142},[35,1959,107],{"class":80},[35,1961,924],{"class":148},[35,1963,947],{"class":84},[10,1965,1966,1967,18],{},"Each pair appears twice — once in each direction, with its own confidence — so that every product can look up its companions. Requiring lift above 1.1 removes companions that are merely popular, which is why gloves are not suggested with everything. The result reads naturally: a hose-reel buyer is shown the hose (90% of reel buyers bought one), a drill buyer drill bits and wall plugs. A few weaker suggestions survive the filters — hose reel with drill bits at lift 1.19, saw with wall plugs at 1.20 — and are worth checking against common sense before they go live; raising the lift threshold to 1.5 would remove them. The same long table can feed a lookup on a product sheet in the workbook, as in ",[14,1968,1970],{"href":1969},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-lookup-formulas-with-openpyxl\u002F","Write Lookup Formulas (XLOOKUP, VLOOKUP, INDEX\u002FMATCH) with openpyxl",[20,1972,1974],{"id":1973},"performance-notes","Performance notes",[10,1976,1977,1978,1981,1982,1985],{},"The incidence table has one column per product, so a catalogue of 20,000 products and a million orders makes a table that is huge and almost entirely zeros. For that scale, build it as a sparse matrix — ",[32,1979,1980],{},"scipy.sparse.csr_matrix"," from the order and product codes — and compute ",[32,1983,1984],{},"X.T @ X"," sparsely; only pairs that actually co-occur take memory. Keep the analysis to the top few hundred products by order count for anything written to Excel, where a 20,000 × 20,000 matrix would exceed the sheet's column limit anyway.",[20,1987,1989],{"id":1988},"common-pitfalls","Common pitfalls",[949,1991,1992,1998,2007,2013,2019],{},[952,1993,1994,1997],{},[955,1995,1996],{},"Counting quantities."," Use 0\u002F1 incidence; quantities inflate pairs with bulk items.",[952,1999,2000,2003,2004,2006],{},[955,2001,2002],{},"Duplicate order lines."," ",[32,2005,198],{}," neutralises them; summing raw lines would not.",[952,2008,2009,2012],{},[955,2010,2011],{},"Ranking by raw counts."," Popular products dominate; use lift (and confidence) instead.",[952,2014,2015,2018],{},[955,2016,2017],{},"Trusting rare pairs."," Require a minimum number of shared orders before ranking.",[952,2020,2021,2024],{},[955,2022,2023],{},"Reading direction into lift."," Lift is symmetric; confidence gives the direction.",[20,2026,2028],{"id":2027},"conclusion","Conclusion",[10,2030,2031,2032,2035],{},"Build an order × product table of 0s and 1s with ",[32,2033,2034],{},"crosstab(...).clip(upper=1)",", multiply its transpose by itself to count orders containing each pair, and read the diagonal as each product's order count. Convert counts into support, confidence and lift so that popular products do not crowd out real companions, filter pairs below a minimum count, and write the matrix as a heatmap plus a sortable pair list to Excel.",[20,2037,2039],{"id":2038},"frequently-asked-questions","Frequently asked questions",[10,2041,2042,2045,2046,2048,2049,2051],{},[955,2043,2044],{},"How do I find which products are bought together in pandas?","\nCreate an order-by-product table with pd.crosstab(lines",[35,2047,130],{},", lines",[35,2050,136],{},").clip(upper=1), then compute basket.T.dot(basket). Each cell counts the orders containing both products.",[10,2053,2054,2057],{},[955,2055,2056],{},"What is lift in market basket analysis?","\nLift is the share of orders containing both products divided by the share you would expect if they were bought independently. Values above 1 mean the products appear together more often than chance.",[10,2059,2060,2063],{},[955,2061,2062],{},"Why do some products appear with everything in my co-occurrence matrix?","\nPopular products are in many orders, so they share high raw counts with every other product. Use lift or confidence, which account for each product's own popularity.",[10,2065,2066,2069],{},[955,2067,2068],{},"What is on the diagonal of a co-occurrence matrix?","\nThe number of orders that contain each product, because every product always co-occurs with itself.",[20,2071,2073],{"id":2072},"related","Related",[949,2075,2076,2082,2089,2096],{},[952,2077,2078,2079,2081],{},"Up one level: ",[14,2080,17],{"href":16}," — summarising data with pandas.",[952,2083,2084,2088],{},[14,2085,2087],{"href":2086},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-crosstab-from-excel-data-with-pandas\u002F","Build a Crosstab from Excel Data with pandas"," — counting combinations.",[952,2090,2091,2095],{},[14,2092,2094],{"href":2093},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-delimited-cell-values-into-rows-with-pandas\u002F","Split Delimited Cell Values into Rows with pandas"," — when orders list products in one cell.",[952,2097,2098,2102],{},[14,2099,2101],{"href":2100},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-an-rfm-customer-segmentation-from-excel-data\u002F","Build an RFM Customer Segmentation from Excel Data"," — another customer analysis from order data.",[2104,2105,2106],"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":94,"depth":94,"links":2108},[2109,2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120],{"id":22,"depth":94,"text":23},{"id":67,"depth":94,"text":68},{"id":601,"depth":94,"text":602},{"id":630,"depth":94,"text":631},{"id":1097,"depth":94,"text":1098},{"id":1220,"depth":94,"text":1221},{"id":1744,"depth":94,"text":1745},{"id":1973,"depth":94,"text":1974},{"id":1988,"depth":94,"text":1989},{"id":2027,"depth":94,"text":2028},{"id":2038,"depth":94,"text":2039},{"id":2072,"depth":94,"text":2073},"2026-10-02","Find out which products are bought together from an order-lines sheet: build an order × product incidence table, multiply it by its transpose to count co-occurrences, read the diagonal as order counts, rank pairs by support, confidence and lift, avoid the pitfalls of quantities and duplicate lines, and write a heatmap matrix and a top-pairs list to Excel.","md",[2125,2127,2129,2131],{"q":2044,"a":2126},"Create an order-by-product table with pd.crosstab(lines[\"OrderID\"], lines[\"Product\"]).clip(upper=1), then compute basket.T.dot(basket). Each cell counts the orders containing both products.",{"q":2056,"a":2128},"Lift is the share of orders containing both products divided by the share you would expect if they were bought independently. Values above 1 mean the products appear together more often than chance.",{"q":2062,"a":2130},"Popular products are in many orders, so they share high raw counts with every other product. Use lift or confidence, which account for each product's own popularity.",{"q":2068,"a":2132},"The number of orders that contain each product, because every product always co-occurs with itself.","build a product co-occurrence matrix from order lines",null,{"breadcrumb":2136},[2137,2139,2142],{"name":2138,"item":800},"Home",{"name":2140,"item":2141},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2143,"item":16},"Creating Pivot Tables from Excel Data with Pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-product-co-occurrence-matrix-from-order-lines",{"title":2146,"description":2147},"Product Co-occurrence Matrix from Excel Order Lines (pandas)","Market-basket analysis in pandas: crosstab of orders × products clipped to 0\u002F1, X.T @ X for co-occurrence counts, support, confidence and lift for each pair, top pairs, minimum counts, and an Excel heatmap of the matrix.","build-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",[2151,2152],"pivots-and-summaries","pandas","how-to","Xa4t9Le0iTx_XVaRy886e7tV1rpJbblW_WLzZYGa66w",[2156,2160],{"title":2157,"path":2158,"stem":2159,"children":-1},"Build a Funnel Conversion Table from Event Data","\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-funnel-conversion-table-from-event-data","advanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-funnel-conversion-table-from-event-data\u002Findex",{"title":2101,"path":2161,"stem":2162,"children":-1},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-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",[2164,2166],{"path":2165,"title":2143},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data",{"path":2167,"title":2140},"\u002Fadvanced-data-transformation-and-cleaning",[],[2170,2173,2176,2179,2182,2185],{"path":2171,"title":2172,"kind":2153},"\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":2174,"title":2175,"kind":2153},"\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":2177,"title":2178,"kind":2153},"\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":2180,"title":2181,"kind":2153},"\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":2183,"title":2184,"kind":2153},"\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":2186,"title":2187,"kind":2153},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbuild-a-cohort-retention-table-from-excel-data","Build a Cohort Retention Table from Excel Data",1790972086262]