[{"data":1,"prerenderedAt":2164},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-values-in-an-excel-column-with-pandas":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-values-in-an-excel-column-with-pandas":2132,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-values-in-an-excel-column-with-pandas":2140,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-values-in-an-excel-column-with-pandas":2145,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-values-in-an-excel-column-with-pandas":2146},{"id":4,"title":5,"body":6,"dateModified":2097,"datePublished":2097,"description":2098,"extension":2099,"faq":2100,"keyword":2109,"kind":2110,"meta":2111,"navigation":254,"path":2121,"seo":2122,"slug":2125,"stem":2126,"topics":2127,"type":2130,"__hash__":2131},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-values-in-an-excel-column-with-pandas\u002Findex.md","Replace Values in an Excel Column with pandas",{"type":7,"value":8,"toc":2082},"minimark",[9,19,177,182,210,213,504,508,514,596,612,616,626,731,742,746,749,998,1011,1169,1173,1176,1237,1240,1244,1257,1382,1410,1414,1421,1516,1533,1595,1599,1605,1689,1692,1696,1703,1801,1808,1939,1943,1998,2002,2017,2021,2027,2033,2039,2045,2049,2078],[10,11,12,13,18],"p",{},"Excel exports carry codes and spellings that are not what the report should show: region \"N\" in one system and \"north\" in another, status 1, 2 and 3 instead of Open, Closed and Cancelled, \"n\u002Fa\" and \"-\" typed in place of blanks. Recoding these is one of the most common cleaning jobs, and pandas offers several tools that look alike but behave differently when a value is not in your list. This guide, part of ",[14,15,17],"a",{"href":16},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002F","Cleaning Excel Data with pandas",", shows which one to use, how to keep the mapping in a workbook where business users can maintain it, and how to catch the values nobody planned for.",[20,21,29,30,29,34,29,38,29,46,29,56,29,67,29,74,29,81,29,87,29,95,29,99,29,104,29,108,29,115,29,119,29,124,29,128,29,135,29,140,29,144,29,147,29,152,29,154,29,159,29,162,29,169,29,172],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"4 0 752 233","img",[25,26],"rv-compare-t","rv-compare-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  ",[31,32,33],"title",{"id":25},"replace and map treat unlisted values differently",[35,36,37],"desc",{"id":26},"With the mapping N, north, S and W, replace turns known codes into region names and leaves E with a trailing space and X unchanged. map turns the same known codes into names but returns missing values for E with a space and X, which makes the gaps visible.",[39,40],"rect",{"x":41,"y":42,"width":43,"height":44,"fill":45},"4","0","752","233","#ffffff",[39,47],{"x":48,"y":49,"width":50,"height":51,"rx":52,"fill":53,"stroke":54,"style":55},"20.0","16.0","351.0","201.0","14","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[57,58,60],"g",{"transform":59},"translate(182.5,29.0) scale(1.083)",[61,62],"path",{"d":63,"fill":64,"stroke":65,"style":66},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7","none","var(--brand-strong,#4338ca)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[68,69,73],"text",{"x":70,"y":71,"style":72},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Series.replace(mapping)",[75,76],"line",{"x1":77,"y1":78,"x2":79,"y2":78,"stroke":54,"style":80},"36.0","91.0","355.0","stroke-width:1px",[68,82,86],{"x":83,"y":84,"style":85},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","N and north become North",[57,88,90],{"transform":89},"translate(38.5,99.5) scale(0.625)",[61,91],{"d":92,"fill":64,"stroke":93,"style":94},"M5 12.5l4.5 4.5L19 7","var(--teal,#0f9488)","stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[68,96,98],{"x":83,"y":97,"style":85},"137.0","S becomes South, W becomes West",[57,100,102],{"transform":101},"translate(38.5,125.5) scale(0.625)",[61,103],{"d":92,"fill":64,"stroke":93,"style":94},[68,105,107],{"x":83,"y":106,"style":85},"163.0","\"E \" stays \"E \"",[57,109,111],{"transform":110},"translate(38.5,151.5) scale(0.625)",[61,112],{"d":113,"fill":64,"stroke":114,"style":94},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold,#b4740a)",[68,116,118],{"x":83,"y":117,"style":85},"189.0","X stays X, silently",[57,120,122],{"transform":121},"translate(38.5,177.5) scale(0.625)",[61,123],{"d":113,"fill":64,"stroke":114,"style":94},[39,125],{"x":126,"y":49,"width":50,"height":51,"rx":52,"fill":127,"stroke":114,"style":55},"389.0","#fdefd8",[57,129,131],{"transform":130},"translate(551.5,29.0) scale(1.083)",[61,132],{"d":133,"fill":64,"stroke":134,"style":66},"M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1 M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1","var(--gold-ink,#7a4e06)",[68,136,139],{"x":137,"y":71,"style":138},"564.5","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Series.map(mapping)",[75,141],{"x1":142,"y1":78,"x2":143,"y2":78,"stroke":114,"style":80},"405.0","724.0",[68,145,86],{"x":146,"y":84,"style":85},"429.0",[57,148,150],{"transform":149},"translate(407.5,99.5) scale(0.625)",[61,151],{"d":92,"fill":64,"stroke":93,"style":94},[68,153,98],{"x":146,"y":97,"style":85},[57,155,157],{"transform":156},"translate(407.5,125.5) scale(0.625)",[61,158],{"d":92,"fill":64,"stroke":93,"style":94},[68,160,161],{"x":146,"y":106,"style":85},"\"E \" becomes NaN",[57,163,165],{"transform":164},"translate(407.5,151.5) scale(0.625)",[61,166],{"d":167,"fill":64,"stroke":168,"style":94},"M6 6l12 12 M18 6L6 18","var(--accent,#f43f8f)",[68,170,171],{"x":146,"y":117,"style":85},"X becomes NaN, visibly",[57,173,175],{"transform":174},"translate(407.5,177.5) scale(0.625)",[61,176],{"d":167,"fill":64,"stroke":168,"style":94},[178,179,181],"h2",{"id":180},"prerequisites","Prerequisites",[183,184,189],"pre",{"className":185,"code":186,"language":187,"meta":188,"style":188},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[190,191,192],"code",{"__ignoreMap":188},[193,194,196,200,204,207],"span",{"class":75,"line":195},1,[193,197,199],{"class":198},"sMTad","pip",[193,201,203],{"class":202},"srMev"," install",[193,205,206],{"class":202}," pandas",[193,208,209],{"class":202}," openpyxl\n",[10,211,212],{},"The examples use a small orders sheet with the usual problems:",[183,214,218],{"className":215,"code":216,"language":217,"meta":188,"style":188},"language-python shiki shiki-themes github-light github-dark-high-contrast","import numpy as np\nimport pandas as pd\n\norders = pd.DataFrame({\n    \"order\": [101, 102, 103, 104, 105, 106],\n    \"region\": [\"N\", \"north\", \"S\", \"E \", \"W\", \"X\"],\n    \"status\": [1, 2, \"2\", 3, 1, 9],\n    \"notes\": [\"n\u002Fa\", \"ok\", \"N\u002FA\", \"-\", \"ok\", \"tbc\"],\n    \"amount\": [120, 45, 980, 15, 300, 60],\n})\norders.to_excel(\"orders.xlsx\", index=False)\ndf = pd.read_excel(\"orders.xlsx\")\n","python",[190,219,220,236,249,256,268,310,348,385,422,460,466,489],{"__ignoreMap":188},[193,221,222,226,230,233],{"class":75,"line":195},[193,223,225],{"class":224},"s-kum","import",[193,227,229],{"class":228},"skGVy"," numpy ",[193,231,232],{"class":224},"as",[193,234,235],{"class":228}," np\n",[193,237,239,241,244,246],{"class":75,"line":238},2,[193,240,225],{"class":224},[193,242,243],{"class":228}," pandas ",[193,245,232],{"class":224},[193,247,248],{"class":228}," pd\n",[193,250,252],{"class":75,"line":251},3,[193,253,255],{"emptyLinePlaceholder":254},true,"\n",[193,257,259,262,265],{"class":75,"line":258},4,[193,260,261],{"class":228},"orders ",[193,263,264],{"class":224},"=",[193,266,267],{"class":228}," pd.DataFrame({\n",[193,269,271,274,277,281,284,287,289,292,294,297,299,302,304,307],{"class":75,"line":270},5,[193,272,273],{"class":202},"    \"order\"",[193,275,276],{"class":228},": [",[193,278,280],{"class":279},"sP0c6","101",[193,282,283],{"class":228},", ",[193,285,286],{"class":279},"102",[193,288,283],{"class":228},[193,290,291],{"class":279},"103",[193,293,283],{"class":228},[193,295,296],{"class":279},"104",[193,298,283],{"class":228},[193,300,301],{"class":279},"105",[193,303,283],{"class":228},[193,305,306],{"class":279},"106",[193,308,309],{"class":228},"],\n",[193,311,313,316,318,321,323,326,328,331,333,336,338,341,343,346],{"class":75,"line":312},6,[193,314,315],{"class":202},"    \"region\"",[193,317,276],{"class":228},[193,319,320],{"class":202},"\"N\"",[193,322,283],{"class":228},[193,324,325],{"class":202},"\"north\"",[193,327,283],{"class":228},[193,329,330],{"class":202},"\"S\"",[193,332,283],{"class":228},[193,334,335],{"class":202},"\"E \"",[193,337,283],{"class":228},[193,339,340],{"class":202},"\"W\"",[193,342,283],{"class":228},[193,344,345],{"class":202},"\"X\"",[193,347,309],{"class":228},[193,349,351,354,356,359,361,364,366,369,371,374,376,378,380,383],{"class":75,"line":350},7,[193,352,353],{"class":202},"    \"status\"",[193,355,276],{"class":228},[193,357,358],{"class":279},"1",[193,360,283],{"class":228},[193,362,363],{"class":279},"2",[193,365,283],{"class":228},[193,367,368],{"class":202},"\"2\"",[193,370,283],{"class":228},[193,372,373],{"class":279},"3",[193,375,283],{"class":228},[193,377,358],{"class":279},[193,379,283],{"class":228},[193,381,382],{"class":279},"9",[193,384,309],{"class":228},[193,386,388,391,393,396,398,401,403,406,408,411,413,415,417,420],{"class":75,"line":387},8,[193,389,390],{"class":202},"    \"notes\"",[193,392,276],{"class":228},[193,394,395],{"class":202},"\"n\u002Fa\"",[193,397,283],{"class":228},[193,399,400],{"class":202},"\"ok\"",[193,402,283],{"class":228},[193,404,405],{"class":202},"\"N\u002FA\"",[193,407,283],{"class":228},[193,409,410],{"class":202},"\"-\"",[193,412,283],{"class":228},[193,414,400],{"class":202},[193,416,283],{"class":228},[193,418,419],{"class":202},"\"tbc\"",[193,421,309],{"class":228},[193,423,425,428,430,433,435,438,440,443,445,448,450,453,455,458],{"class":75,"line":424},9,[193,426,427],{"class":202},"    \"amount\"",[193,429,276],{"class":228},[193,431,432],{"class":279},"120",[193,434,283],{"class":228},[193,436,437],{"class":279},"45",[193,439,283],{"class":228},[193,441,442],{"class":279},"980",[193,444,283],{"class":228},[193,446,447],{"class":279},"15",[193,449,283],{"class":228},[193,451,452],{"class":279},"300",[193,454,283],{"class":228},[193,456,457],{"class":279},"60",[193,459,309],{"class":228},[193,461,463],{"class":75,"line":462},10,[193,464,465],{"class":228},"})\n",[193,467,469,472,475,477,481,483,486],{"class":75,"line":468},11,[193,470,471],{"class":228},"orders.to_excel(",[193,473,474],{"class":202},"\"orders.xlsx\"",[193,476,283],{"class":228},[193,478,480],{"class":479},"sa561","index",[193,482,264],{"class":224},[193,484,485],{"class":279},"False",[193,487,488],{"class":228},")\n",[193,490,492,495,497,500,502],{"class":75,"line":491},12,[193,493,494],{"class":228},"df ",[193,496,264],{"class":224},[193,498,499],{"class":228}," pd.read_excel(",[193,501,474],{"class":202},[193,503,488],{"class":228},[178,505,507],{"id":506},"step-1-corrections-with-replace","Step 1 — Corrections with replace",[10,509,510,513],{},[190,511,512],{},"Series.replace"," with a dictionary changes the listed values and leaves every other value alone. That makes it the right tool for fixing known mistakes in a column that is otherwise fine:",[183,515,517],{"className":215,"code":516,"language":217,"meta":188,"style":188},"fixes = {\"N\": \"North\", \"north\": \"North\", \"S\": \"South\", \"E\": \"East\", \"W\": \"West\"}\nprint(df[\"region\"].replace(fixes).tolist())\n# ['North', 'North', 'South', 'E ', 'West', 'X']\n",[190,518,519,576,590],{"__ignoreMap":188},[193,520,521,524,526,529,531,534,537,539,541,543,545,547,549,551,554,556,559,561,564,566,568,570,573],{"class":75,"line":195},[193,522,523],{"class":228},"fixes ",[193,525,264],{"class":224},[193,527,528],{"class":228}," {",[193,530,320],{"class":202},[193,532,533],{"class":228},": ",[193,535,536],{"class":202},"\"North\"",[193,538,283],{"class":228},[193,540,325],{"class":202},[193,542,533],{"class":228},[193,544,536],{"class":202},[193,546,283],{"class":228},[193,548,330],{"class":202},[193,550,533],{"class":228},[193,552,553],{"class":202},"\"South\"",[193,555,283],{"class":228},[193,557,558],{"class":202},"\"E\"",[193,560,533],{"class":228},[193,562,563],{"class":202},"\"East\"",[193,565,283],{"class":228},[193,567,340],{"class":202},[193,569,533],{"class":228},[193,571,572],{"class":202},"\"West\"",[193,574,575],{"class":228},"}\n",[193,577,578,581,584,587],{"class":75,"line":238},[193,579,580],{"class":279},"print",[193,582,583],{"class":228},"(df[",[193,585,586],{"class":202},"\"region\"",[193,588,589],{"class":228},"].replace(fixes).tolist())\n",[193,591,592],{"class":75,"line":251},[193,593,595],{"class":594},"s-wDw","# ['North', 'North', 'South', 'E ', 'West', 'X']\n",[10,597,598,599,601,602,604,605,608,609,611],{},"Two values slipped through. ",[190,600,335],{}," has a trailing space, so it does not equal ",[190,603,558],{},"; ",[190,606,607],{},"replace"," matches whole cell values exactly. And ",[190,610,345],{}," is not in the dictionary at all, so it is left as it was — silently. For corrections that is what you want. For a recode, where every value must end up in the new scheme, it hides problems.",[178,613,615],{"id":614},"step-2-complete-recodes-with-map","Step 2 — Complete recodes with map",[10,617,618,621,622,625],{},[190,619,620],{},"Series.map"," looks every value up and returns ",[190,623,624],{},"NaN"," for anything missing. Normalise the text first so that trivial differences in spacing and case do not count as missing:",[183,627,629],{"className":215,"code":628,"language":217,"meta":188,"style":188},"key = df[\"region\"].str.strip().str.lower()\nregions = {\"n\": \"North\", \"north\": \"North\", \"s\": \"South\", \"e\": \"East\", \"w\": \"West\"}\ndf[\"region_name\"] = key.map(regions)\nprint(df[\"region_name\"].tolist())\n# ['North', 'North', 'South', 'East', 'West', nan]\n",[190,630,631,646,699,715,726],{"__ignoreMap":188},[193,632,633,636,638,641,643],{"class":75,"line":195},[193,634,635],{"class":228},"key ",[193,637,264],{"class":224},[193,639,640],{"class":228}," df[",[193,642,586],{"class":202},[193,644,645],{"class":228},"].str.strip().str.lower()\n",[193,647,648,651,653,655,658,660,662,664,666,668,670,672,675,677,679,681,684,686,688,690,693,695,697],{"class":75,"line":238},[193,649,650],{"class":228},"regions ",[193,652,264],{"class":224},[193,654,528],{"class":228},[193,656,657],{"class":202},"\"n\"",[193,659,533],{"class":228},[193,661,536],{"class":202},[193,663,283],{"class":228},[193,665,325],{"class":202},[193,667,533],{"class":228},[193,669,536],{"class":202},[193,671,283],{"class":228},[193,673,674],{"class":202},"\"s\"",[193,676,533],{"class":228},[193,678,553],{"class":202},[193,680,283],{"class":228},[193,682,683],{"class":202},"\"e\"",[193,685,533],{"class":228},[193,687,563],{"class":202},[193,689,283],{"class":228},[193,691,692],{"class":202},"\"w\"",[193,694,533],{"class":228},[193,696,572],{"class":202},[193,698,575],{"class":228},[193,700,701,704,707,710,712],{"class":75,"line":251},[193,702,703],{"class":228},"df[",[193,705,706],{"class":202},"\"region_name\"",[193,708,709],{"class":228},"] ",[193,711,264],{"class":224},[193,713,714],{"class":228}," key.map(regions)\n",[193,716,717,719,721,723],{"class":75,"line":258},[193,718,580],{"class":279},[193,720,583],{"class":228},[193,722,706],{"class":202},[193,724,725],{"class":228},"].tolist())\n",[193,727,728],{"class":75,"line":270},[193,729,730],{"class":594},"# ['North', 'North', 'South', 'East', 'West', nan]\n",[10,732,733,734,736,737,741],{},"Now the only gap is the genuinely unknown code, ",[190,735,345],{},", and it shows up as a missing value you can count and report. Normalising text before comparing is covered in depth in ",[14,738,740],{"href":739},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fstrip-whitespace-and-normalise-text-columns-with-pandas\u002F","Strip Whitespace and Normalise Text Columns with pandas",".",[178,743,745],{"id":744},"step-3-keep-the-mapping-in-a-workbook","Step 3 — Keep the mapping in a workbook",[10,747,748],{},"Hard-coded dictionaries go stale. When the codes belong to the business — region codes, product families, cost centres — keep the mapping in a sheet the owners can edit, and load it at run time:",[183,750,752],{"className":215,"code":751,"language":217,"meta":188,"style":188},"mapping = pd.DataFrame({\n    \"code\": [\"n\", \"north\", \"s\", \"e\", \"w\", \"s\"],\n    \"region\": [\"North\", \"North\", \"South\", \"East\", \"West\", \"Southern\"],\n})\nmapping.to_excel(\"region_map.xlsx\", index=False)\n\ntable = pd.read_excel(\"region_map.xlsx\", dtype=str)\ntable[\"code\"] = table[\"code\"].str.strip().str.lower()\ndupes = table[table[\"code\"].duplicated(keep=False)]\nif not dupes.empty:\n    print(\"conflicting rules:\\n\", dupes)\nlookup = table.drop_duplicates(\"code\", keep=\"first\").set_index(\"code\")[\"region\"]\ndf[\"region_name\"] = key.map(lookup)\n",[190,753,754,763,794,825,829,847,851,874,893,918,929,950,984],{"__ignoreMap":188},[193,755,756,759,761],{"class":75,"line":195},[193,757,758],{"class":228},"mapping ",[193,760,264],{"class":224},[193,762,267],{"class":228},[193,764,765,768,770,772,774,776,778,780,782,784,786,788,790,792],{"class":75,"line":238},[193,766,767],{"class":202},"    \"code\"",[193,769,276],{"class":228},[193,771,657],{"class":202},[193,773,283],{"class":228},[193,775,325],{"class":202},[193,777,283],{"class":228},[193,779,674],{"class":202},[193,781,283],{"class":228},[193,783,683],{"class":202},[193,785,283],{"class":228},[193,787,692],{"class":202},[193,789,283],{"class":228},[193,791,674],{"class":202},[193,793,309],{"class":228},[193,795,796,798,800,802,804,806,808,810,812,814,816,818,820,823],{"class":75,"line":251},[193,797,315],{"class":202},[193,799,276],{"class":228},[193,801,536],{"class":202},[193,803,283],{"class":228},[193,805,536],{"class":202},[193,807,283],{"class":228},[193,809,553],{"class":202},[193,811,283],{"class":228},[193,813,563],{"class":202},[193,815,283],{"class":228},[193,817,572],{"class":202},[193,819,283],{"class":228},[193,821,822],{"class":202},"\"Southern\"",[193,824,309],{"class":228},[193,826,827],{"class":75,"line":258},[193,828,465],{"class":228},[193,830,831,834,837,839,841,843,845],{"class":75,"line":270},[193,832,833],{"class":228},"mapping.to_excel(",[193,835,836],{"class":202},"\"region_map.xlsx\"",[193,838,283],{"class":228},[193,840,480],{"class":479},[193,842,264],{"class":224},[193,844,485],{"class":279},[193,846,488],{"class":228},[193,848,849],{"class":75,"line":312},[193,850,255],{"emptyLinePlaceholder":254},[193,852,853,856,858,860,862,864,867,869,872],{"class":75,"line":350},[193,854,855],{"class":228},"table ",[193,857,264],{"class":224},[193,859,499],{"class":228},[193,861,836],{"class":202},[193,863,283],{"class":228},[193,865,866],{"class":479},"dtype",[193,868,264],{"class":224},[193,870,871],{"class":279},"str",[193,873,488],{"class":228},[193,875,876,879,882,884,886,889,891],{"class":75,"line":387},[193,877,878],{"class":228},"table[",[193,880,881],{"class":202},"\"code\"",[193,883,709],{"class":228},[193,885,264],{"class":224},[193,887,888],{"class":228}," table[",[193,890,881],{"class":202},[193,892,645],{"class":228},[193,894,895,898,900,903,905,908,911,913,915],{"class":75,"line":424},[193,896,897],{"class":228},"dupes ",[193,899,264],{"class":224},[193,901,902],{"class":228}," table[table[",[193,904,881],{"class":202},[193,906,907],{"class":228},"].duplicated(",[193,909,910],{"class":479},"keep",[193,912,264],{"class":224},[193,914,485],{"class":279},[193,916,917],{"class":228},")]\n",[193,919,920,923,926],{"class":75,"line":462},[193,921,922],{"class":224},"if",[193,924,925],{"class":224}," not",[193,927,928],{"class":228}," dupes.empty:\n",[193,930,931,934,937,940,944,947],{"class":75,"line":468},[193,932,933],{"class":279},"    print",[193,935,936],{"class":228},"(",[193,938,939],{"class":202},"\"conflicting rules:",[193,941,943],{"class":942},"sSjpA","\\n",[193,945,946],{"class":202},"\"",[193,948,949],{"class":228},", dupes)\n",[193,951,952,955,957,960,962,964,966,968,971,974,976,979,981],{"class":75,"line":491},[193,953,954],{"class":228},"lookup ",[193,956,264],{"class":224},[193,958,959],{"class":228}," table.drop_duplicates(",[193,961,881],{"class":202},[193,963,283],{"class":228},[193,965,910],{"class":479},[193,967,264],{"class":224},[193,969,970],{"class":202},"\"first\"",[193,972,973],{"class":228},").set_index(",[193,975,881],{"class":202},[193,977,978],{"class":228},")[",[193,980,586],{"class":202},[193,982,983],{"class":228},"]\n",[193,985,987,989,991,993,995],{"class":75,"line":986},13,[193,988,703],{"class":228},[193,990,706],{"class":202},[193,992,709],{"class":228},[193,994,264],{"class":224},[193,996,997],{"class":228}," key.map(lookup)\n",[10,999,1000,1003,1004,1006,1007,1010],{},[190,1001,1002],{},"map"," accepts a Series directly, so there is no need to build a dictionary. The duplicate check matters: someone has added a second rule for ",[190,1005,674],{},", and ",[190,1008,1009],{},"dict(zip(...))"," would quietly keep the last one. Report conflicts and decide which rule wins rather than letting row order decide.",[20,1012,29,1017,29,1020,29,1023,29,1026,29,1031,29,1038,29,1044,29,1048,29,1052,29,1057,29,1062,29,1067,29,1070,29,1076,29,1081,29,1085,29,1089,29,1093,29,1096,29,1099,29,1104,29,1109,29,1112,29,1115,29,1119,29,1122,29,1125,29,1130,29,1134,29,1137,29,1140,29,1144,29,1147,29,1151,29,1158,29,1163,29,1166],{"viewBox":1013,"role":23,"ariaLabelledBy":1014,"xmlns":27,"style":28},"4 0 752 160",[1015,1016],"rv-flow-t","rv-flow-d",[31,1018,1019],{"id":1015},"Recoding a column from a mapping sheet",[35,1021,1022],{"id":1016},"Read the mapping sheet as text, normalise the codes, report duplicate codes, map the normalised column through the lookup, and list values that received no mapping before the file is written.",[39,1024],{"x":41,"y":42,"width":43,"height":1025,"fill":45},"160",[39,1027],{"x":48,"y":49,"width":1028,"height":1029,"rx":1030,"fill":53,"stroke":54,"style":55},"115.2","128.0","12",[57,1032,1034],{"transform":1033},"translate(65.6,29.0) scale(1.000)",[61,1035],{"d":1036,"fill":64,"stroke":65,"style":1037},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[68,1039,1043],{"x":1040,"y":1041,"style":1042},"77.6","75.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Read",[68,1045,1047],{"x":1040,"y":1046,"style":1042},"93.0","mapping",[68,1049,1051],{"x":1040,"y":1050,"style":1042},"110.5","sheet",[68,1053,1056],{"x":1040,"y":1054,"style":1055},"130.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","dtype=str",[75,1058],{"x1":1059,"y1":1060,"x2":1061,"y2":1060,"stroke":54,"style":55},"140.2","80.0","162.2",[1063,1064],"polygon",{"points":1065,"fill":1066},"166.2,80.0 157.2,85.0 157.2,75.0","#5b5cf0",[39,1068],{"x":1069,"y":49,"width":1028,"height":1029,"rx":1030,"fill":53,"stroke":54,"style":55},"171.2",[57,1071,1073],{"transform":1072},"translate(216.8,37.8) scale(1.000)",[61,1074],{"d":1075,"fill":64,"stroke":65,"style":1037},"M3 5h18l-7 8v6l-4 2v-8z",[68,1077,1080],{"x":1078,"y":1079,"style":1042},"228.8","84.2","Normalise",[68,1082,1084],{"x":1078,"y":1083,"style":1042},"101.8","codes",[68,1086,1088],{"x":1078,"y":1087,"style":1055},"121.2","strip and lower",[75,1090],{"x1":1091,"y1":1060,"x2":1092,"y2":1060,"stroke":54,"style":55},"291.4","313.4",[1063,1094],{"points":1095,"fill":1066},"317.4,80.0 308.4,85.0 308.4,75.0",[39,1097],{"x":1098,"y":49,"width":1028,"height":1029,"rx":1030,"fill":127,"stroke":114,"style":55},"322.4",[57,1100,1102],{"transform":1101},"translate(368.0,37.8) scale(1.000)",[61,1103],{"d":113,"fill":64,"stroke":134,"style":1037},[68,1105,1108],{"x":1106,"y":1079,"style":1107},"380.0","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Check",[68,1110,1111],{"x":1106,"y":1083,"style":1107},"duplicates",[68,1113,1114],{"x":1106,"y":1087,"style":1055},"conflicting rules",[75,1116],{"x1":1117,"y1":1060,"x2":1118,"y2":1060,"stroke":54,"style":55},"442.6","464.6",[1063,1120],{"points":1121,"fill":1066},"468.6,80.0 459.6,85.0 459.6,75.0",[39,1123],{"x":1124,"y":49,"width":1028,"height":1029,"rx":1030,"fill":53,"stroke":54,"style":55},"473.6",[57,1126,1128],{"transform":1127},"translate(519.2,37.8) scale(1.000)",[61,1129],{"d":133,"fill":64,"stroke":65,"style":1037},[68,1131,1133],{"x":1132,"y":1079,"style":1042},"531.2","Map the",[68,1135,1136],{"x":1132,"y":1083,"style":1042},"column",[68,1138,1139],{"x":1132,"y":1087,"style":1055},"key.map(lookup)",[75,1141],{"x1":1142,"y1":1060,"x2":1143,"y2":1060,"stroke":54,"style":55},"593.8","615.8",[1063,1145],{"points":1146,"fill":1066},"619.8,80.0 610.8,85.0 610.8,75.0",[39,1148],{"x":1149,"y":49,"width":1028,"height":1029,"rx":1030,"fill":1150,"stroke":168,"style":55},"624.8","#fee8f2",[57,1152,1154],{"transform":1153},"translate(670.4,37.8) scale(1.000)",[61,1155],{"d":1156,"fill":64,"stroke":1157,"style":1037},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--accent-ink,#be185d)",[68,1159,1162],{"x":1160,"y":1079,"style":1161},"682.4","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Report",[68,1164,1165],{"x":1160,"y":1083,"style":1161},"unmapped",[68,1167,1168],{"x":1160,"y":1087,"style":1055},"before writing",[178,1170,1172],{"id":1171},"step-4-report-the-values-no-rule-covered","Step 4 — Report the values no rule covered",[10,1174,1175],{},"After a recode, list the source values that ended up empty, with counts, so the mapping sheet can be extended:",[183,1177,1179],{"className":215,"code":1178,"language":217,"meta":188,"style":188},"unmapped = df.loc[df[\"region_name\"].isna(), \"region\"].value_counts()\nprint(unmapped.to_dict())                 # {'X': 1}\nif len(unmapped):\n    unmapped.rename(\"rows\").to_frame().to_excel(\"unmapped_regions.xlsx\")\n",[190,1180,1181,1201,1211,1221],{"__ignoreMap":188},[193,1182,1183,1186,1188,1191,1193,1196,1198],{"class":75,"line":195},[193,1184,1185],{"class":228},"unmapped ",[193,1187,264],{"class":224},[193,1189,1190],{"class":228}," df.loc[df[",[193,1192,706],{"class":202},[193,1194,1195],{"class":228},"].isna(), ",[193,1197,586],{"class":202},[193,1199,1200],{"class":228},"].value_counts()\n",[193,1202,1203,1205,1208],{"class":75,"line":238},[193,1204,580],{"class":279},[193,1206,1207],{"class":228},"(unmapped.to_dict())                 ",[193,1209,1210],{"class":594},"# {'X': 1}\n",[193,1212,1213,1215,1218],{"class":75,"line":251},[193,1214,922],{"class":224},[193,1216,1217],{"class":279}," len",[193,1219,1220],{"class":228},"(unmapped):\n",[193,1222,1223,1226,1229,1232,1235],{"class":75,"line":258},[193,1224,1225],{"class":228},"    unmapped.rename(",[193,1227,1228],{"class":202},"\"rows\"",[193,1230,1231],{"class":228},").to_frame().to_excel(",[193,1233,1234],{"class":202},"\"unmapped_regions.xlsx\"",[193,1236,488],{"class":228},[10,1238,1239],{},"Write the report next to the output, or fail the run if the column must be complete. Either way, the owner of the mapping sees exactly which codes to add — far better than discovering a blank region in a published report.",[178,1241,1243],{"id":1242},"step-5-match-the-key-type-to-the-column-type","Step 5 — Match the key type to the column type",[10,1245,1246,1247,1249,1250,1253,1254,1256],{},"The status column in the workbook mixes real numbers with a text cell, ",[190,1248,368],{},". By default ",[190,1251,1252],{},"read_excel"," infers a type for each column and turns numeric-looking text into numbers, so a plain read gives integers and an integer-keyed dictionary works. Many pipelines, though, read code columns with ",[190,1255,1056],{}," to protect leading zeros in IDs — and then every key misses, without an error:",[183,1258,1260],{"className":215,"code":1259,"language":217,"meta":188,"style":188},"status_names = {1: \"Open\", 2: \"Closed\", 3: \"Cancelled\"}\nas_text = pd.read_excel(\"orders.xlsx\", dtype={\"status\": str})[\"status\"]\nprint(as_text.replace(status_names).tolist())\n# ['1', '2', '2', '3', '1', '9']\nstatus = pd.to_numeric(as_text.str.strip(), errors=\"coerce\").astype(\"Int64\")\nprint(status.map(status_names).tolist())\n# ['Open', 'Closed', 'Closed', 'Cancelled', 'Open', nan]\n",[190,1261,1262,1298,1332,1339,1344,1370,1377],{"__ignoreMap":188},[193,1263,1264,1267,1269,1271,1273,1275,1278,1280,1282,1284,1287,1289,1291,1293,1296],{"class":75,"line":195},[193,1265,1266],{"class":228},"status_names ",[193,1268,264],{"class":224},[193,1270,528],{"class":228},[193,1272,358],{"class":279},[193,1274,533],{"class":228},[193,1276,1277],{"class":202},"\"Open\"",[193,1279,283],{"class":228},[193,1281,363],{"class":279},[193,1283,533],{"class":228},[193,1285,1286],{"class":202},"\"Closed\"",[193,1288,283],{"class":228},[193,1290,373],{"class":279},[193,1292,533],{"class":228},[193,1294,1295],{"class":202},"\"Cancelled\"",[193,1297,575],{"class":228},[193,1299,1300,1303,1305,1307,1309,1311,1313,1315,1318,1321,1323,1325,1328,1330],{"class":75,"line":238},[193,1301,1302],{"class":228},"as_text ",[193,1304,264],{"class":224},[193,1306,499],{"class":228},[193,1308,474],{"class":202},[193,1310,283],{"class":228},[193,1312,866],{"class":479},[193,1314,264],{"class":224},[193,1316,1317],{"class":228},"{",[193,1319,1320],{"class":202},"\"status\"",[193,1322,533],{"class":228},[193,1324,871],{"class":279},[193,1326,1327],{"class":228},"})[",[193,1329,1320],{"class":202},[193,1331,983],{"class":228},[193,1333,1334,1336],{"class":75,"line":251},[193,1335,580],{"class":279},[193,1337,1338],{"class":228},"(as_text.replace(status_names).tolist())\n",[193,1340,1341],{"class":75,"line":258},[193,1342,1343],{"class":594},"# ['1', '2', '2', '3', '1', '9']\n",[193,1345,1346,1349,1351,1354,1357,1359,1362,1365,1368],{"class":75,"line":270},[193,1347,1348],{"class":228},"status ",[193,1350,264],{"class":224},[193,1352,1353],{"class":228}," pd.to_numeric(as_text.str.strip(), ",[193,1355,1356],{"class":479},"errors",[193,1358,264],{"class":224},[193,1360,1361],{"class":202},"\"coerce\"",[193,1363,1364],{"class":228},").astype(",[193,1366,1367],{"class":202},"\"Int64\"",[193,1369,488],{"class":228},[193,1371,1372,1374],{"class":75,"line":312},[193,1373,580],{"class":279},[193,1375,1376],{"class":228},"(status.map(status_names).tolist())\n",[193,1378,1379],{"class":75,"line":350},[193,1380,1381],{"class":594},"# ['Open', 'Closed', 'Closed', 'Cancelled', 'Open', nan]\n",[10,1383,1384,1385,1387,1388,1390,1391,1394,1395,1397,1398,1401,1402,1405,1406,741],{},"Python treats ",[190,1386,363],{}," and ",[190,1389,368],{}," as different values, so decide on one type for the column, convert it explicitly, and write the mapping keys in that type. ",[190,1392,1393],{},"errors=\"coerce\""," turns anything that is not a number into a missing value, which then shows up in the unmapped report alongside the unknown status ",[190,1396,382],{},". If the codes are genuinely text — ",[190,1399,1400],{},"\"007\""," must stay distinct from ",[190,1403,1404],{},"\"7\""," — keep the column as text and write the keys as strings instead. The general problem is covered in ",[14,1407,1409],{"href":1408},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fconvert-excel-text-columns-to-numbers-with-pandas\u002F","Convert Excel Text Columns to Numbers with pandas",[178,1411,1413],{"id":1412},"step-6-placeholders-and-partial-text-with-regex","Step 6 — Placeholders and partial text with regex",[10,1415,1416,1417,1420],{},"Placeholder text such as \"n\u002Fa\", \"N\u002FA\", \"-\" and \"tbc\" is best turned into real missing values with one pattern. Pass ",[190,1418,1419],{},"regex=True"," and anchor the pattern so it matches whole cells only:",[183,1422,1424],{"className":215,"code":1423,"language":217,"meta":188,"style":188},"df[\"notes\"] = df[\"notes\"].replace(r\"(?i)^\\s*(n\u002F?a|-|tbc)\\s*$\", np.nan, regex=True)\nprint(df[\"notes\"].tolist())               # [nan, 'ok', nan, nan, 'ok', nan]\n",[190,1425,1426,1502],{"__ignoreMap":188},[193,1427,1428,1430,1433,1435,1437,1439,1441,1444,1447,1449,1452,1455,1458,1460,1463,1466,1468,1471,1474,1476,1479,1482,1484,1487,1489,1492,1495,1497,1500],{"class":75,"line":195},[193,1429,703],{"class":228},[193,1431,1432],{"class":202},"\"notes\"",[193,1434,709],{"class":228},[193,1436,264],{"class":224},[193,1438,640],{"class":228},[193,1440,1432],{"class":202},[193,1442,1443],{"class":228},"].replace(",[193,1445,1446],{"class":224},"r",[193,1448,946],{"class":202},[193,1450,1451],{"class":224},"(?i)",[193,1453,1454],{"class":279},"^\\s",[193,1456,1457],{"class":224},"*",[193,1459,936],{"class":279},[193,1461,1462],{"class":202},"n\u002F",[193,1464,1465],{"class":224},"?",[193,1467,14],{"class":202},[193,1469,1470],{"class":224},"|",[193,1472,1473],{"class":202},"-",[193,1475,1470],{"class":224},[193,1477,1478],{"class":202},"tbc",[193,1480,1481],{"class":279},")\\s",[193,1483,1457],{"class":224},[193,1485,1486],{"class":279},"$",[193,1488,946],{"class":202},[193,1490,1491],{"class":228},", np.nan, ",[193,1493,1494],{"class":479},"regex",[193,1496,264],{"class":224},[193,1498,1499],{"class":279},"True",[193,1501,488],{"class":228},[193,1503,1504,1506,1508,1510,1513],{"class":75,"line":238},[193,1505,580],{"class":279},[193,1507,583],{"class":228},[193,1509,1432],{"class":202},[193,1511,1512],{"class":228},"].tolist())               ",[193,1514,1515],{"class":594},"# [nan, 'ok', nan, nan, 'ok', nan]\n",[10,1517,1518,1519,1387,1522,1524,1525,1528,1529,1532],{},"Without ",[190,1520,1521],{},"^",[190,1523,1486],{},", the pattern would also match \"-\" inside \"re-order\". To change text within a cell — \"Ltd.\" to \"Limited\" in company names — use ",[190,1526,1527],{},"Series.str.replace",", which works on substrings, and pass ",[190,1530,1531],{},"regex=False"," so the dot is literal:",[183,1534,1536],{"className":215,"code":1535,"language":217,"meta":188,"style":188},"names = pd.Series([\"Acme Ltd.\", \"Birch Ltd\", \"Ltd. Holdings\"])\nprint(names.str.replace(\"Ltd.\", \"Limited\", regex=False).tolist())\n# ['Acme Limited', 'Birch Ltd', 'Limited Holdings']\n",[190,1537,1538,1564,1590],{"__ignoreMap":188},[193,1539,1540,1543,1545,1548,1551,1553,1556,1558,1561],{"class":75,"line":195},[193,1541,1542],{"class":228},"names ",[193,1544,264],{"class":224},[193,1546,1547],{"class":228}," pd.Series([",[193,1549,1550],{"class":202},"\"Acme Ltd.\"",[193,1552,283],{"class":228},[193,1554,1555],{"class":202},"\"Birch Ltd\"",[193,1557,283],{"class":228},[193,1559,1560],{"class":202},"\"Ltd. Holdings\"",[193,1562,1563],{"class":228},"])\n",[193,1565,1566,1568,1571,1574,1576,1579,1581,1583,1585,1587],{"class":75,"line":238},[193,1567,580],{"class":279},[193,1569,1570],{"class":228},"(names.str.replace(",[193,1572,1573],{"class":202},"\"Ltd.\"",[193,1575,283],{"class":228},[193,1577,1578],{"class":202},"\"Limited\"",[193,1580,283],{"class":228},[193,1582,1494],{"class":479},[193,1584,264],{"class":224},[193,1586,485],{"class":279},[193,1588,1589],{"class":228},").tolist())\n",[193,1591,1592],{"class":75,"line":251},[193,1593,1594],{"class":594},"# ['Acme Limited', 'Birch Ltd', 'Limited Holdings']\n",[178,1596,1598],{"id":1597},"step-7-different-rules-per-column","Step 7 — Different rules per column",[10,1600,1601,1604],{},[190,1602,1603],{},"DataFrame.replace"," accepts a nested dictionary keyed by column name, so one call can apply separate rules to separate columns without touching the others:",[183,1606,1608],{"className":215,"code":1607,"language":217,"meta":188,"style":188},"cleaned = df.replace({\n    \"region\": {\"N\": \"North\", \"north\": \"North\"},\n    \"notes\": {\"ok\": \"OK\"},\n})\nprint(cleaned[[\"region\", \"notes\"]].head(2).values.tolist())\n# [['North', nan], ['North', 'OK']]\n",[190,1609,1610,1620,1644,1659,1663,1684],{"__ignoreMap":188},[193,1611,1612,1615,1617],{"class":75,"line":195},[193,1613,1614],{"class":228},"cleaned ",[193,1616,264],{"class":224},[193,1618,1619],{"class":228}," df.replace({\n",[193,1621,1622,1624,1627,1629,1631,1633,1635,1637,1639,1641],{"class":75,"line":238},[193,1623,315],{"class":202},[193,1625,1626],{"class":228},": {",[193,1628,320],{"class":202},[193,1630,533],{"class":228},[193,1632,536],{"class":202},[193,1634,283],{"class":228},[193,1636,325],{"class":202},[193,1638,533],{"class":228},[193,1640,536],{"class":202},[193,1642,1643],{"class":228},"},\n",[193,1645,1646,1648,1650,1652,1654,1657],{"class":75,"line":251},[193,1647,390],{"class":202},[193,1649,1626],{"class":228},[193,1651,400],{"class":202},[193,1653,533],{"class":228},[193,1655,1656],{"class":202},"\"OK\"",[193,1658,1643],{"class":228},[193,1660,1661],{"class":75,"line":258},[193,1662,465],{"class":228},[193,1664,1665,1667,1670,1672,1674,1676,1679,1681],{"class":75,"line":270},[193,1666,580],{"class":279},[193,1668,1669],{"class":228},"(cleaned[[",[193,1671,586],{"class":202},[193,1673,283],{"class":228},[193,1675,1432],{"class":202},[193,1677,1678],{"class":228},"]].head(",[193,1680,363],{"class":279},[193,1682,1683],{"class":228},").values.tolist())\n",[193,1685,1686],{"class":75,"line":312},[193,1687,1688],{"class":594},"# [['North', nan], ['North', 'OK']]\n",[10,1690,1691],{},"This is safer than a flat dictionary on the whole frame, which would also replace a stray \"N\" in any other text column.",[178,1693,1695],{"id":1694},"step-8-numeric-bands-with-case_when","Step 8 — Numeric bands with case_when",[10,1697,1698,1699,1702],{},"Replacing ranges of numbers — order size bands, age groups — is not a lookup at all. ",[190,1700,1701],{},"Series.case_when"," (pandas 2.2 and later) applies conditions in order, like nested IF formulas in Excel:",[183,1704,1706],{"className":215,"code":1705,"language":217,"meta":188,"style":188},"amount = df[\"amount\"]\ndf[\"size\"] = pd.Series(\"large\", index=df.index).case_when([\n    (amount \u003C 50, \"small\"),\n    (amount \u003C 500, \"medium\"),\n])\nprint(df[\"size\"].tolist())   # ['medium', 'small', 'large', 'small', 'medium', 'medium']\n",[190,1707,1708,1722,1748,1767,1783,1787],{"__ignoreMap":188},[193,1709,1710,1713,1715,1717,1720],{"class":75,"line":195},[193,1711,1712],{"class":228},"amount ",[193,1714,264],{"class":224},[193,1716,640],{"class":228},[193,1718,1719],{"class":202},"\"amount\"",[193,1721,983],{"class":228},[193,1723,1724,1726,1729,1731,1733,1736,1739,1741,1743,1745],{"class":75,"line":238},[193,1725,703],{"class":228},[193,1727,1728],{"class":202},"\"size\"",[193,1730,709],{"class":228},[193,1732,264],{"class":224},[193,1734,1735],{"class":228}," pd.Series(",[193,1737,1738],{"class":202},"\"large\"",[193,1740,283],{"class":228},[193,1742,480],{"class":479},[193,1744,264],{"class":224},[193,1746,1747],{"class":228},"df.index).case_when([\n",[193,1749,1750,1753,1756,1759,1761,1764],{"class":75,"line":251},[193,1751,1752],{"class":228},"    (amount ",[193,1754,1755],{"class":224},"\u003C",[193,1757,1758],{"class":279}," 50",[193,1760,283],{"class":228},[193,1762,1763],{"class":202},"\"small\"",[193,1765,1766],{"class":228},"),\n",[193,1768,1769,1771,1773,1776,1778,1781],{"class":75,"line":258},[193,1770,1752],{"class":228},[193,1772,1755],{"class":224},[193,1774,1775],{"class":279}," 500",[193,1777,283],{"class":228},[193,1779,1780],{"class":202},"\"medium\"",[193,1782,1766],{"class":228},[193,1784,1785],{"class":75,"line":270},[193,1786,1563],{"class":228},[193,1788,1789,1791,1793,1795,1798],{"class":75,"line":312},[193,1790,580],{"class":279},[193,1792,583],{"class":228},[193,1794,1728],{"class":202},[193,1796,1797],{"class":228},"].tolist())   ",[193,1799,1800],{"class":594},"# ['medium', 'small', 'large', 'small', 'medium', 'medium']\n",[10,1802,1803,1804,741],{},"The first matching condition wins, so list them from narrowest to widest. Excel-style IF logic in general is covered in ",[14,1805,1807],{"href":1806},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fexcel-if-formulas-as-pandas-conditional-columns\u002F","Excel IF Formulas as pandas Conditional Columns",[20,1809,29,1814,29,1817,29,1820,29,1823,29,1827,29,1832,29,1835,29,1839,29,1843,29,1846,29,1849,29,1858,29,1863,29,1868,29,1870,29,1874,29,1877,29,1880,29,1884,29,1887,29,1890,29,1892,29,1895,29,1898,29,1901,29,1905,29,1908,29,1912,29,1916,29,1918,29,1920,29,1923,29,1927,29,1930,29,1933,29,1936],{"viewBox":1810,"role":23,"ariaLabelledBy":1811,"xmlns":27,"style":28},"4 0 752 238",[1812,1813],"rv-choose-t","rv-choose-d",[31,1815,1816],{"id":1812},"Which pandas tool replaces the values you have",[35,1818,1819],{"id":1813},"Fix a few known mistakes with replace. Recode every value with map and report the missing ones. Replace text inside cells with str.replace. Turn placeholder text into missing values with an anchored regex. Assign numeric bands with case_when.",[39,1821],{"x":41,"y":42,"width":43,"height":1822,"fill":45},"238",[39,1824],{"x":1825,"y":49,"width":1826,"height":1041,"rx":1030,"fill":53,"stroke":54,"style":55},"240.0","280.0",[57,1828,1830],{"transform":1829},"translate(368.0,29.0) scale(1.000)",[61,1831],{"d":1156,"fill":64,"stroke":65,"style":1037},[68,1833,1834],{"x":1106,"y":1041,"style":1042},"What kind of replacement is it?",[75,1836],{"x1":1106,"y1":1837,"x2":1106,"y2":1838,"stroke":54,"style":55},"91.5","111.5",[75,1840],{"x1":1841,"y1":1838,"x2":1842,"y2":1838,"stroke":54,"style":55},"104.0","656.0",[75,1844],{"x1":1841,"y1":1838,"x2":1841,"y2":1845,"stroke":54,"style":55},"157.5",[1063,1847],{"points":1848,"fill":1066},"104.0,161.5 99.0,152.5 109.0,152.5",[39,1850],{"x":1851,"y":1852,"width":1853,"height":1854,"rx":1855,"fill":45,"stroke":1856,"style":1857},"38.0","121.5","132.0","21.0","10","var(--line,#cdd5e6)","stroke-width:1.2px",[68,1859,1862],{"x":1841,"y":1860,"style":1861},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","fix known mistakes",[39,1864],{"x":48,"y":1865,"width":1866,"height":1867,"rx":1030,"fill":53,"stroke":54,"style":55},"163.5","168.0","59.0",[68,1869,607],{"x":1841,"y":117,"style":1042},[68,1871,1873],{"x":1841,"y":1872,"style":1055},"208.5","others untouched",[75,1875],{"x1":1876,"y1":1838,"x2":1876,"y2":1845,"stroke":54,"style":55},"288.0",[1063,1878],{"points":1879,"fill":1066},"288.0,161.5 283.0,152.5 293.0,152.5",[39,1881],{"x":1882,"y":1852,"width":1883,"height":1854,"rx":1855,"fill":45,"stroke":1856,"style":1857},"222.4","131.2",[68,1885,1886],{"x":1876,"y":1860,"style":1861},"recode every value",[39,1888],{"x":1889,"y":1865,"width":1866,"height":1867,"rx":1030,"fill":127,"stroke":114,"style":55},"204.0",[68,1891,1002],{"x":1876,"y":117,"style":1107},[68,1893,1894],{"x":1876,"y":1872,"style":1055},"gaps become NaN",[75,1896],{"x1":1897,"y1":1838,"x2":1897,"y2":1845,"stroke":54,"style":55},"472.0",[1063,1899],{"points":1900,"fill":1066},"472.0,161.5 467.0,152.5 477.0,152.5",[39,1902],{"x":1903,"y":1852,"width":1904,"height":1854,"rx":1855,"fill":45,"stroke":1856,"style":1857},"417.0","110.0",[68,1906,1907],{"x":1897,"y":1860,"style":1861},"text inside cells",[39,1909],{"x":1910,"y":1865,"width":1866,"height":1867,"rx":1030,"fill":1911,"stroke":93,"style":55},"388.0","#d9f4f1",[68,1913,1915],{"x":1897,"y":117,"style":1914},"font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","str.replace",[68,1917,1531],{"x":1897,"y":1872,"style":1055},[75,1919],{"x1":1842,"y1":1838,"x2":1842,"y2":1845,"stroke":54,"style":55},[1063,1921],{"points":1922,"fill":1066},"656.0,161.5 651.0,152.5 661.0,152.5",[39,1924],{"x":1925,"y":1852,"width":1926,"height":1854,"rx":1855,"fill":45,"stroke":1856,"style":1857},"602.2","107.7",[68,1928,1929],{"x":1842,"y":1860,"style":1861},"number ranges",[39,1931],{"x":1932,"y":1865,"width":1866,"height":1867,"rx":1030,"fill":1150,"stroke":168,"style":55},"572.0",[68,1934,1935],{"x":1842,"y":117,"style":1161},"case_when",[68,1937,1938],{"x":1842,"y":1872,"style":1055},"first match wins",[178,1940,1942],{"id":1941},"common-pitfalls","Common pitfalls",[1944,1945,1946,1961,1970,1986,1992],"ul",{},[1947,1948,1949,1953,1954,1957,1958,1960],"li",{},[1950,1951,1952],"strong",{},"Expecting chained rules."," ",[190,1955,1956],{},"replace({\"A\": \"B\", \"B\": \"C\"})"," turns A into B and B into C in a single pass; it does not turn A into C. If you need chaining, call ",[190,1959,607],{}," twice.",[1947,1962,1963,1966,1967,1969],{},[1950,1964,1965],{},"Replacing on the whole frame."," A flat dictionary passed to ",[190,1968,1603],{}," changes matching values in every column. Target columns explicitly.",[1947,1971,1972,1975,1976,1979,1980,1982,1983,1985],{},[1950,1973,1974],{},"Unanchored regexes."," A pattern without ",[190,1977,1978],{},"^…$"," replaces fragments of longer values — and with ",[190,1981,1419],{}," on ",[190,1984,607],{},", only the matched part is substituted.",[1947,1987,1988,1991],{},[1950,1989,1990],{},"Case-only differences."," \"North\" and \"NORTH\" are different keys. Lower-case both the column and the mapping codes, as in Step 2, rather than listing every spelling.",[1947,1993,1994,1997],{},[1950,1995,1996],{},"Leaving the result as text."," A recoded status column read by another tool can still be sorted alphabetically. Use an ordered categorical when the order matters.",[178,1999,2001],{"id":2000},"conclusion","Conclusion",[10,2003,2004,2005,2007,2008,2010,2011,2013,2014,2016],{},"Use ",[190,2006,607],{}," for corrections that should leave everything else alone, ",[190,2009,1002],{}," for complete recodes where a missing rule must show up as a gap, ",[190,2012,1915],{}," for text inside cells and ",[190,2015,1935],{}," for numeric bands. Normalise text and types before matching, keep business mappings in a workbook with a duplicate check, and always report the values no rule covered before the output is written.",[178,2018,2020],{"id":2019},"frequently-asked-questions","Frequently asked questions",[10,2022,2023,2026],{},[1950,2024,2025],{},"What is the difference between replace and map in pandas?","\nreplace changes only the values that appear in your dictionary and leaves everything else untouched. map looks every value up and returns NaN for anything missing from the dictionary. Use replace for corrections and map for complete recodes where unmapped values should stand out.",[10,2028,2029,2032],{},[1950,2030,2031],{},"Why did replace not change part of a string?","\nSeries.replace matches whole cell values by default. To replace text inside a cell, use Series.str.replace, or pass regex=True to replace with a pattern.",[10,2034,2035,2038],{},[1950,2036,2037],{},"Does replace apply rules one after another?","\nNo. All the pairs in one dictionary are applied at the same time to the original values, so {\"A\":\"B\",\"B\":\"C\"} turns A into B and B into C, not A into C.",[10,2040,2041,2044],{},[1950,2042,2043],{},"How do I replace values in only some columns?","\nPass a nested dictionary to DataFrame.replace, keyed by column name, or call replace on each column you want to change.",[178,2046,2048],{"id":2047},"related","Related",[1944,2050,2051,2057,2064,2071],{},[1947,2052,2053,2054,2056],{},"Up one level: ",[14,2055,17],{"href":16}," — the full cleaning toolkit.",[1947,2058,2059,2063],{},[14,2060,2062],{"href":2061},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas\u002F","Split a Column into Multiple Columns with pandas"," — the next step when one cell holds several values.",[1947,2065,2066,2070],{},[14,2067,2069],{"href":2068},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fpandas-drop-duplicates-from-excel-column\u002F","Pandas: Drop Duplicates From an Excel Column"," — deduplicating once the values are consistent.",[1947,2072,2073,2077],{},[14,2074,2076],{"href":2075},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Findex-match-equivalent-in-pandas\u002F","INDEX MATCH Equivalent in pandas"," — lookups that return more than one column.",[2079,2080,2081],"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 .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":188,"searchDepth":238,"depth":238,"links":2083},[2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096],{"id":180,"depth":238,"text":181},{"id":506,"depth":238,"text":507},{"id":614,"depth":238,"text":615},{"id":744,"depth":238,"text":745},{"id":1171,"depth":238,"text":1172},{"id":1242,"depth":238,"text":1243},{"id":1412,"depth":238,"text":1413},{"id":1597,"depth":238,"text":1598},{"id":1694,"depth":238,"text":1695},{"id":1941,"depth":238,"text":1942},{"id":2000,"depth":238,"text":2001},{"id":2019,"depth":238,"text":2020},{"id":2047,"depth":238,"text":2048},"2026-09-23","Recode values in an Excel column with pandas — replace versus map, mapping tables kept in a workbook, regex replacements, per-column rules, numeric bands with case_when, and a report of values that no rule covered.","md",[2101,2103,2105,2107],{"q":2025,"a":2102},"replace changes only the values that appear in your dictionary and leaves everything else untouched. map looks every value up and returns NaN for anything missing from the dictionary. Use replace for corrections and map for complete recodes where unmapped values should stand out.",{"q":2031,"a":2104},"Series.replace matches whole cell values by default. To replace text inside a cell, use Series.str.replace, or pass regex=True to replace with a pattern.",{"q":2037,"a":2106},"No. All the pairs in one dictionary are applied at the same time to the original values, so {\"A\":\"B\",\"B\":\"C\"} turns A into B and B into C, not A into C.",{"q":2043,"a":2108},"Pass a nested dictionary to DataFrame.replace, keyed by column name, or call replace on each column you want to change.","replace values in an excel column with pandas",null,{"breadcrumb":2112},[2113,2116,2119],{"name":2114,"item":2115},"Home","\u002F",{"name":2117,"item":2118},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2120,"item":16},"Cleaning Excel Data With Pandas: A Production Workflow","\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-values-in-an-excel-column-with-pandas",{"title":2123,"description":2124},"Replace Values in an Excel Column with pandas (replace, map, regex)","Replace values in an Excel column with pandas — replace vs map, a mapping sheet as the source of truth, regex and substring replacement, per-column dictionaries, case_when bands and catching unmapped codes.","replace-values-in-an-excel-column-with-pandas","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-values-in-an-excel-column-with-pandas\u002Findex",[2128,2129],"data-cleaning","pandas","how-to","HuVb2ioub0K0iVo1_tIgiYGOkD-E9HrMebdi0ESCseo",[2133,2137],{"title":2134,"path":2135,"stem":2136,"children":-1},"Reorder Columns to Match a Template Layout with pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freorder-columns-to-match-a-template-layout-with-pandas","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freorder-columns-to-match-a-template-layout-with-pandas\u002Findex",{"title":2062,"path":2138,"stem":2139,"children":-1},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas\u002Findex",[2141,2143],{"path":2142,"title":2120},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas",{"path":2144,"title":2117},"\u002Fadvanced-data-transformation-and-cleaning",[],[2147,2150,2153,2156,2159,2162],{"path":2148,"title":2149,"kind":2130},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Ffind-duplicate-rows-in-excel-with-python","Find Duplicate Rows in Excel with Python",{"path":2151,"title":2152,"kind":2130},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-duplicate-values-in-excel-with-openpyxl","Highlight Duplicate Values in Excel with openpyxl",{"path":2154,"title":2155,"kind":2130},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns","Clean Mixed-Currency Amounts into Amount and Currency Columns",{"path":2157,"title":2158,"kind":2130},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fcoalesce-several-excel-columns-into-one-with-pandas","Coalesce Several Excel Columns into One with pandas",{"path":2160,"title":2161,"kind":2130},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fconvert-currency-strings-to-numbers-with-pandas","Convert Currency Strings Like \"$1,234.56\" and \"(500)\" to Numbers with pandas",{"path":2163,"title":1409,"kind":2130},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fconvert-excel-text-columns-to-numbers-with-pandas",1790972085779]