[{"data":1,"prerenderedAt":2427},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names":2393,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names":2402,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names":2407,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names":2408},{"id":4,"title":5,"body":6,"dateModified":2358,"datePublished":2358,"description":2359,"extension":2360,"faq":2361,"keyword":2370,"kind":2371,"meta":2372,"navigation":233,"path":2382,"seo":2383,"slug":2385,"stem":2386,"topics":2387,"type":2391,"__hash__":2392},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names\u002Findex.md","Merge Excel Files with Different Column Names in pandas",{"type":7,"value":8,"toc":2344},"minimark",[9,44,169,174,202,205,496,500,513,604,607,611,618,864,872,876,879,1009,1022,1309,1313,1320,1432,1451,1455,1462,1715,1718,1853,1857,1873,2025,2037,2041,2044,2206,2216,2220,2272,2276,2279,2283,2289,2295,2301,2307,2311,2340],[10,11,12,13,17,18,21,22,25,26,29,30,33,34,37,38,43],"p",{},"A CRM export and an ERP export describe the same customers. The CRM calls the key \"Customer No\" and writes it as ",[14,15,16],"code",{},"00123","; the ERP calls it ",[14,19,20],{},"cust_id"," and stores ",[14,23,24],{},"123",". The country is \"DE\" in one file and \"de\" in the other, and both files carry an email address under different headers. ",[14,27,28],{},"merge"," cannot guess that these columns belong together, and when it is forced to — with ",[14,31,32],{},"left_on"," and ",[14,35,36],{},"right_on"," — the result has two of everything. This guide, part of ",[39,40,42],"a",{"href":41},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002F","Merging and Joining Excel DataFrames",", maps both files to one schema, fixes the key formats, merges on two columns and resolves the fields both files provide.",[45,46,54,55,54,59,54,63,54,71,54,81,54,92,54,99,54,104,54,112,54,119,54,125,54,130,54,133,54,138,54,144,54,151,54,156,54,160,54,164,54,167],"svg",{"viewBox":47,"role":48,"ariaLabelledBy":49,"xmlns":52,"style":53},"4 0 752 245","img",[50,51],"mf-schema-t","mf-schema-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  ",[56,57,58],"title",{"id":50},"Two sets of headers mapped onto one schema",[60,61,62],"desc",{"id":51},"The CRM columns Customer No, Country, Name and Email and the ERP columns cust_id, country_code, customer_name, email_address and balance are each renamed to the shared names customer_id, country, name, email and balance before the files are merged.",[64,65],"rect",{"x":66,"y":67,"width":68,"height":69,"fill":70},"4","0","752","245","#ffffff",[64,72],{"x":73,"y":74,"width":75,"height":76,"rx":77,"fill":78,"stroke":79,"style":80},"520.0","76.0","220.0","93.0","12","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[82,83,85],"g",{"transform":84},"translate(618.0,89.0) scale(1.000)",[86,87],"path",{"d":88,"fill":89,"stroke":90,"style":91},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","none","var(--teal-ink,#0b6157)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[93,94,98],"text",{"x":95,"y":96,"style":97},"630.0","135.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Shared schema",[93,100,103],{"x":95,"y":101,"style":102},"155.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","customer_id, country, name, email",[64,105],{"x":106,"y":107,"width":108,"height":109,"rx":77,"fill":110,"stroke":111,"style":80},"20.0","16.0","250.0","92.0","#f0f4ff","var(--brand,#5b5cf0)",[82,113,115],{"transform":114},"translate(133.0,29.0) scale(1.000)",[86,116],{"d":117,"fill":89,"stroke":118,"style":91},"M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z M2.5 20c0-3.6 2.9-6 6.5-6s6.5 2.4 6.5 6 M16 4.5a3.3 3.3 0 0 1 0 6.3 M18 14.3c2.2.7 3.5 2.8 3.5 5.7","var(--brand-strong,#4338ca)",[93,120,124],{"x":121,"y":122,"style":123},"145.0","75.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","CRM export",[93,126,129],{"x":121,"y":127,"style":128},"94.0","font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Customer No, Country, Name, Email",[86,131],{"d":132,"fill":89,"stroke":111,"style":80},"M274.0,62.0 C394.0,62.0 394.0,122.5 510.0,122.5",[134,135],"polygon",{"points":136,"fill":137},"514.0,122.5 505.0,127.5 505.0,117.5","#5b5cf0",[64,139],{"x":106,"y":140,"width":108,"height":141,"rx":77,"fill":142,"stroke":143,"style":80},"120.0","109.0","#fdefd8","var(--gold,#b4740a)",[82,145,147],{"transform":146},"translate(133.0,133.0) scale(1.000)",[86,148],{"d":149,"fill":89,"stroke":150,"style":91},"M4 4h16v6H4z M4 14h16v6H4z M8 7h.01 M8 17h.01","var(--gold-ink,#7a4e06)",[93,152,155],{"x":121,"y":153,"style":154},"179.0","font-size:13px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","ERP export",[93,157,159],{"x":121,"y":158,"style":128},"198.0","cust_id, country_code, customer_name,",[93,161,163],{"x":121,"y":162,"style":128},"215.0","email_address",[86,165],{"d":166,"fill":89,"stroke":111,"style":80},"M274.0,174.5 C394.0,174.5 394.0,122.5 510.0,122.5",[134,168],{"points":136,"fill":137},[170,171,173],"h2",{"id":172},"prerequisites","Prerequisites",[175,176,181],"pre",{"className":177,"code":178,"language":179,"meta":180,"style":180},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[14,182,183],{"__ignoreMap":180},[184,185,188,192,196,199],"span",{"class":186,"line":187},"line",1,[184,189,191],{"class":190},"sMTad","pip",[184,193,195],{"class":194},"srMev"," install",[184,197,198],{"class":194}," pandas",[184,200,201],{"class":194}," openpyxl\n",[10,203,204],{},"The two exports:",[175,206,210],{"className":207,"code":208,"language":209,"meta":180,"style":180},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\npd.DataFrame({\n    \"Customer No\": [\"00123\", \"00456\", \"00789\"],\n    \"Country\": [\"DE\", \"FR\", \"UK\"],\n    \"Name\": [\"Acme GmbH\", \"Birch SA\", \"Cedar Ltd\"],\n    \"Email\": [\"a@x.de\", None, \"c@x.uk\"],\n}).to_excel(\"crm.xlsx\", index=False)\npd.DataFrame({\n    \"cust_id\": [123, 456, 999],\n    \"country_code\": [\"de\", \"FR\", \"US\"],\n    \"customer_name\": [\"ACME GMBH\", \"Birch S.A.\", \"Dune Inc\"],\n    \"email_address\": [\"acct@x.de\", \"b@x.fr\", None],\n    \"balance\": [1200, 300, 50],\n}).to_excel(\"erp.xlsx\", index=False)\n","python",[14,211,212,228,235,241,267,290,313,337,361,366,388,410,433,455,478],{"__ignoreMap":180},[184,213,214,218,222,225],{"class":186,"line":187},[184,215,217],{"class":216},"s-kum","import",[184,219,221],{"class":220},"skGVy"," pandas ",[184,223,224],{"class":216},"as",[184,226,227],{"class":220}," pd\n",[184,229,231],{"class":186,"line":230},2,[184,232,234],{"emptyLinePlaceholder":233},true,"\n",[184,236,238],{"class":186,"line":237},3,[184,239,240],{"class":220},"pd.DataFrame({\n",[184,242,244,247,250,253,256,259,261,264],{"class":186,"line":243},4,[184,245,246],{"class":194},"    \"Customer No\"",[184,248,249],{"class":220},": [",[184,251,252],{"class":194},"\"00123\"",[184,254,255],{"class":220},", ",[184,257,258],{"class":194},"\"00456\"",[184,260,255],{"class":220},[184,262,263],{"class":194},"\"00789\"",[184,265,266],{"class":220},"],\n",[184,268,270,273,275,278,280,283,285,288],{"class":186,"line":269},5,[184,271,272],{"class":194},"    \"Country\"",[184,274,249],{"class":220},[184,276,277],{"class":194},"\"DE\"",[184,279,255],{"class":220},[184,281,282],{"class":194},"\"FR\"",[184,284,255],{"class":220},[184,286,287],{"class":194},"\"UK\"",[184,289,266],{"class":220},[184,291,293,296,298,301,303,306,308,311],{"class":186,"line":292},6,[184,294,295],{"class":194},"    \"Name\"",[184,297,249],{"class":220},[184,299,300],{"class":194},"\"Acme GmbH\"",[184,302,255],{"class":220},[184,304,305],{"class":194},"\"Birch SA\"",[184,307,255],{"class":220},[184,309,310],{"class":194},"\"Cedar Ltd\"",[184,312,266],{"class":220},[184,314,316,319,321,324,326,330,332,335],{"class":186,"line":315},7,[184,317,318],{"class":194},"    \"Email\"",[184,320,249],{"class":220},[184,322,323],{"class":194},"\"a@x.de\"",[184,325,255],{"class":220},[184,327,329],{"class":328},"sP0c6","None",[184,331,255],{"class":220},[184,333,334],{"class":194},"\"c@x.uk\"",[184,336,266],{"class":220},[184,338,340,343,346,348,352,355,358],{"class":186,"line":339},8,[184,341,342],{"class":220},"}).to_excel(",[184,344,345],{"class":194},"\"crm.xlsx\"",[184,347,255],{"class":220},[184,349,351],{"class":350},"sa561","index",[184,353,354],{"class":216},"=",[184,356,357],{"class":328},"False",[184,359,360],{"class":220},")\n",[184,362,364],{"class":186,"line":363},9,[184,365,240],{"class":220},[184,367,369,372,374,376,378,381,383,386],{"class":186,"line":368},10,[184,370,371],{"class":194},"    \"cust_id\"",[184,373,249],{"class":220},[184,375,24],{"class":328},[184,377,255],{"class":220},[184,379,380],{"class":328},"456",[184,382,255],{"class":220},[184,384,385],{"class":328},"999",[184,387,266],{"class":220},[184,389,391,394,396,399,401,403,405,408],{"class":186,"line":390},11,[184,392,393],{"class":194},"    \"country_code\"",[184,395,249],{"class":220},[184,397,398],{"class":194},"\"de\"",[184,400,255],{"class":220},[184,402,282],{"class":194},[184,404,255],{"class":220},[184,406,407],{"class":194},"\"US\"",[184,409,266],{"class":220},[184,411,413,416,418,421,423,426,428,431],{"class":186,"line":412},12,[184,414,415],{"class":194},"    \"customer_name\"",[184,417,249],{"class":220},[184,419,420],{"class":194},"\"ACME GMBH\"",[184,422,255],{"class":220},[184,424,425],{"class":194},"\"Birch S.A.\"",[184,427,255],{"class":220},[184,429,430],{"class":194},"\"Dune Inc\"",[184,432,266],{"class":220},[184,434,436,439,441,444,446,449,451,453],{"class":186,"line":435},13,[184,437,438],{"class":194},"    \"email_address\"",[184,440,249],{"class":220},[184,442,443],{"class":194},"\"acct@x.de\"",[184,445,255],{"class":220},[184,447,448],{"class":194},"\"b@x.fr\"",[184,450,255],{"class":220},[184,452,329],{"class":328},[184,454,266],{"class":220},[184,456,458,461,463,466,468,471,473,476],{"class":186,"line":457},14,[184,459,460],{"class":194},"    \"balance\"",[184,462,249],{"class":220},[184,464,465],{"class":328},"1200",[184,467,255],{"class":220},[184,469,470],{"class":328},"300",[184,472,255],{"class":220},[184,474,475],{"class":328},"50",[184,477,266],{"class":220},[184,479,481,483,486,488,490,492,494],{"class":186,"line":480},15,[184,482,342],{"class":220},[184,484,485],{"class":194},"\"erp.xlsx\"",[184,487,255],{"class":220},[184,489,351],{"class":350},[184,491,354],{"class":216},[184,493,357],{"class":328},[184,495,360],{"class":220},[170,497,499],{"id":498},"step-1-read-keys-as-text","Step 1 — Read keys as text",[10,501,502,503,505,506,508,509,512],{},"Read both files with the key columns as strings. Without that, pandas infers types: the CRM's ",[14,504,252],{}," text cells come back as the integer 123 — the leading zeros are simply gone — and if one file stays text while the other is numeric, ",[14,507,28],{}," refuses with ",[14,510,511],{},"ValueError: You are trying to merge on str and int64 columns",":",[175,514,516],{"className":207,"code":515,"language":209,"meta":180,"style":180},"crm = pd.read_excel(\"crm.xlsx\", dtype={\"Customer No\": str})\nerp = pd.read_excel(\"erp.xlsx\", dtype={\"cust_id\": str})\nprint(crm[\"Customer No\"].tolist(), erp[\"cust_id\"].tolist())\n# ['00123', '00456', '00789'] ['123', '456', '999']\n",[14,517,518,552,580,598],{"__ignoreMap":180},[184,519,520,523,525,528,530,532,535,537,540,543,546,549],{"class":186,"line":187},[184,521,522],{"class":220},"crm ",[184,524,354],{"class":216},[184,526,527],{"class":220}," pd.read_excel(",[184,529,345],{"class":194},[184,531,255],{"class":220},[184,533,534],{"class":350},"dtype",[184,536,354],{"class":216},[184,538,539],{"class":220},"{",[184,541,542],{"class":194},"\"Customer No\"",[184,544,545],{"class":220},": ",[184,547,548],{"class":328},"str",[184,550,551],{"class":220},"})\n",[184,553,554,557,559,561,563,565,567,569,571,574,576,578],{"class":186,"line":230},[184,555,556],{"class":220},"erp ",[184,558,354],{"class":216},[184,560,527],{"class":220},[184,562,485],{"class":194},[184,564,255],{"class":220},[184,566,534],{"class":350},[184,568,354],{"class":216},[184,570,539],{"class":220},[184,572,573],{"class":194},"\"cust_id\"",[184,575,545],{"class":220},[184,577,548],{"class":328},[184,579,551],{"class":220},[184,581,582,585,588,590,593,595],{"class":186,"line":237},[184,583,584],{"class":328},"print",[184,586,587],{"class":220},"(crm[",[184,589,542],{"class":194},[184,591,592],{"class":220},"].tolist(), erp[",[184,594,573],{"class":194},[184,596,597],{"class":220},"].tolist())\n",[184,599,600],{"class":186,"line":243},[184,601,603],{"class":602},"s-wDw","# ['00123', '00456', '00789'] ['123', '456', '999']\n",[10,605,606],{},"Reading as text keeps the values exactly as the sheet shows them, so you decide how to normalise them rather than letting type inference decide. It also protects IDs that only look numeric, such as account codes with a letter in some rows, from being split into numbers and text within one column.",[170,608,610],{"id":609},"step-2-map-both-files-to-one-schema","Step 2 — Map both files to one schema",[10,612,613,33,615,617],{},[14,614,32],{},[14,616,36],{}," handle a single differently named key, but here four fields differ. Rename each file to a shared set of names instead, with one mapping per source kept in one place:",[175,619,621],{"className":207,"code":620,"language":209,"meta":180,"style":180},"SCHEMA = {\n    \"crm\": {\"Customer No\": \"customer_id\", \"Country\": \"country\", \"Name\": \"name\", \"Email\": \"email\"},\n    \"erp\": {\"cust_id\": \"customer_id\", \"country_code\": \"country\", \"customer_name\": \"name\",\n            \"email_address\": \"email\", \"balance\": \"balance\"},\n}\n\ndef prepare(frame, source):\n    mapping = SCHEMA[source]\n    missing = set(mapping) - set(frame.columns)\n    if missing:\n        raise ValueError(f\"{source}: missing columns {sorted(missing)}\")\n    return frame.rename(columns=mapping)[list(mapping.values())]\n",[14,622,623,634,682,716,736,741,745,757,770,791,799,842],{"__ignoreMap":180},[184,624,625,628,631],{"class":186,"line":187},[184,626,627],{"class":328},"SCHEMA",[184,629,630],{"class":216}," =",[184,632,633],{"class":220}," {\n",[184,635,636,639,642,644,646,649,651,654,656,659,661,664,666,669,671,674,676,679],{"class":186,"line":230},[184,637,638],{"class":194},"    \"crm\"",[184,640,641],{"class":220},": {",[184,643,542],{"class":194},[184,645,545],{"class":220},[184,647,648],{"class":194},"\"customer_id\"",[184,650,255],{"class":220},[184,652,653],{"class":194},"\"Country\"",[184,655,545],{"class":220},[184,657,658],{"class":194},"\"country\"",[184,660,255],{"class":220},[184,662,663],{"class":194},"\"Name\"",[184,665,545],{"class":220},[184,667,668],{"class":194},"\"name\"",[184,670,255],{"class":220},[184,672,673],{"class":194},"\"Email\"",[184,675,545],{"class":220},[184,677,678],{"class":194},"\"email\"",[184,680,681],{"class":220},"},\n",[184,683,684,687,689,691,693,695,697,700,702,704,706,709,711,713],{"class":186,"line":237},[184,685,686],{"class":194},"    \"erp\"",[184,688,641],{"class":220},[184,690,573],{"class":194},[184,692,545],{"class":220},[184,694,648],{"class":194},[184,696,255],{"class":220},[184,698,699],{"class":194},"\"country_code\"",[184,701,545],{"class":220},[184,703,658],{"class":194},[184,705,255],{"class":220},[184,707,708],{"class":194},"\"customer_name\"",[184,710,545],{"class":220},[184,712,668],{"class":194},[184,714,715],{"class":220},",\n",[184,717,718,721,723,725,727,730,732,734],{"class":186,"line":243},[184,719,720],{"class":194},"            \"email_address\"",[184,722,545],{"class":220},[184,724,678],{"class":194},[184,726,255],{"class":220},[184,728,729],{"class":194},"\"balance\"",[184,731,545],{"class":220},[184,733,729],{"class":194},[184,735,681],{"class":220},[184,737,738],{"class":186,"line":269},[184,739,740],{"class":220},"}\n",[184,742,743],{"class":186,"line":292},[184,744,234],{"emptyLinePlaceholder":233},[184,746,747,750,754],{"class":186,"line":315},[184,748,749],{"class":216},"def",[184,751,753],{"class":752},"s_Opv"," prepare",[184,755,756],{"class":220},"(frame, source):\n",[184,758,759,762,764,767],{"class":186,"line":339},[184,760,761],{"class":220},"    mapping ",[184,763,354],{"class":216},[184,765,766],{"class":328}," SCHEMA",[184,768,769],{"class":220},"[source]\n",[184,771,772,775,777,780,783,786,788],{"class":186,"line":363},[184,773,774],{"class":220},"    missing ",[184,776,354],{"class":216},[184,778,779],{"class":328}," set",[184,781,782],{"class":220},"(mapping) ",[184,784,785],{"class":216},"-",[184,787,779],{"class":328},[184,789,790],{"class":220},"(frame.columns)\n",[184,792,793,796],{"class":186,"line":368},[184,794,795],{"class":216},"    if",[184,797,798],{"class":220}," missing:\n",[184,800,801,804,807,810,813,816,819,822,825,828,830,833,836,838,840],{"class":186,"line":390},[184,802,803],{"class":216},"        raise",[184,805,806],{"class":328}," ValueError",[184,808,809],{"class":220},"(",[184,811,812],{"class":216},"f",[184,814,815],{"class":194},"\"",[184,817,539],{"class":818},"sSjpA",[184,820,821],{"class":220},"source",[184,823,824],{"class":818},"}",[184,826,827],{"class":194},": missing columns ",[184,829,539],{"class":818},[184,831,832],{"class":328},"sorted",[184,834,835],{"class":220},"(missing)",[184,837,824],{"class":818},[184,839,815],{"class":194},[184,841,360],{"class":220},[184,843,844,847,850,853,855,858,861],{"class":186,"line":412},[184,845,846],{"class":216},"    return",[184,848,849],{"class":220}," frame.rename(",[184,851,852],{"class":350},"columns",[184,854,354],{"class":216},[184,856,857],{"class":220},"mapping)[",[184,859,860],{"class":328},"list",[184,862,863],{"class":220},"(mapping.values())]\n",[10,865,866,867,871],{},"Selecting only the mapped columns drops anything unexpected, and the check turns a renamed column in next month's export into a clear error. Cleaning messy headers before mapping — spaces, case, symbols — is covered in ",[39,868,870],{"href":869},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fstandardise-excel-column-names-with-pandas\u002F","Standardise Excel Column Names with pandas",".",[170,873,875],{"id":874},"step-3-normalise-the-key-values","Step 3 — Normalise the key values",[10,877,878],{},"Matching names is half the job; the values must match too. Strip spaces, remove leading zeros from the IDs and upper-case the country codes, the same way on both sides:",[175,880,882],{"className":207,"code":881,"language":209,"meta":180,"style":180},"def normalise_keys(frame):\n    out = frame.copy()\n    out[\"customer_id\"] = out[\"customer_id\"].str.strip().str.lstrip(\"0\")\n    out[\"country\"] = out[\"country\"].str.strip().str.upper()\n    return out\n\na = normalise_keys(prepare(crm, \"crm\"))\nb = normalise_keys(prepare(erp, \"erp\"))\nprint(a[\"customer_id\"].tolist(), b[\"customer_id\"].tolist())\n# ['123', '456', '789'] ['123', '456', '999']\n",[14,883,884,894,904,929,946,953,957,973,988,1004],{"__ignoreMap":180},[184,885,886,888,891],{"class":186,"line":187},[184,887,749],{"class":216},[184,889,890],{"class":752}," normalise_keys",[184,892,893],{"class":220},"(frame):\n",[184,895,896,899,901],{"class":186,"line":230},[184,897,898],{"class":220},"    out ",[184,900,354],{"class":216},[184,902,903],{"class":220}," frame.copy()\n",[184,905,906,909,911,914,916,919,921,924,927],{"class":186,"line":237},[184,907,908],{"class":220},"    out[",[184,910,648],{"class":194},[184,912,913],{"class":220},"] ",[184,915,354],{"class":216},[184,917,918],{"class":220}," out[",[184,920,648],{"class":194},[184,922,923],{"class":220},"].str.strip().str.lstrip(",[184,925,926],{"class":194},"\"0\"",[184,928,360],{"class":220},[184,930,931,933,935,937,939,941,943],{"class":186,"line":243},[184,932,908],{"class":220},[184,934,658],{"class":194},[184,936,913],{"class":220},[184,938,354],{"class":216},[184,940,918],{"class":220},[184,942,658],{"class":194},[184,944,945],{"class":220},"].str.strip().str.upper()\n",[184,947,948,950],{"class":186,"line":269},[184,949,846],{"class":216},[184,951,952],{"class":220}," out\n",[184,954,955],{"class":186,"line":292},[184,956,234],{"emptyLinePlaceholder":233},[184,958,959,962,964,967,970],{"class":186,"line":315},[184,960,961],{"class":220},"a ",[184,963,354],{"class":216},[184,965,966],{"class":220}," normalise_keys(prepare(crm, ",[184,968,969],{"class":194},"\"crm\"",[184,971,972],{"class":220},"))\n",[184,974,975,978,980,983,986],{"class":186,"line":339},[184,976,977],{"class":220},"b ",[184,979,354],{"class":216},[184,981,982],{"class":220}," normalise_keys(prepare(erp, ",[184,984,985],{"class":194},"\"erp\"",[184,987,972],{"class":220},[184,989,990,992,995,997,1000,1002],{"class":186,"line":363},[184,991,584],{"class":328},[184,993,994],{"class":220},"(a[",[184,996,648],{"class":194},[184,998,999],{"class":220},"].tolist(), b[",[184,1001,648],{"class":194},[184,1003,597],{"class":220},[184,1005,1006],{"class":186,"line":368},[184,1007,1008],{"class":602},"# ['123', '456', '789'] ['123', '456', '999']\n",[10,1010,1011,1012,33,1015,1017,1018,1021],{},"Removing zeros is the right choice when the numeric value is the identity. If ",[14,1013,1014],{},"0123",[14,1016,24],{}," can be different customers, pad both sides to a fixed width with ",[14,1019,1020],{},"str.zfill(5)"," instead. Either way, apply one function to both files, so the rule cannot drift between them.",[45,1023,54,1028,54,1031,54,1034,54,1037,54,1045,54,1049,54,1055,54,1059,54,1063,54,1067,54,1071,54,1075,54,1080,54,1082,54,1085,54,1087,54,1090,54,1092,54,1095,54,1097,54,1101,54,1103,54,1107,54,1109,54,1111,54,1113,54,1116,54,1118,54,1122,54,1124,54,1126,54,1128,54,1131,54,1133,54,1136,54,1139,54,1142,54,1144,54,1147,54,1149,54,1151,54,1153,54,1156,54,1159,54,1163,54,1165,54,1167,54,1169,54,1171,54,1173,54,1175,54,1178,54,1181,54,1184,54,1187,54,1190,54,1193,54,1196,54,1198,54,1201,54,1203,54,1205,54,1207,54,1209,54,1211,54,1213,54,1215,54,1217,54,1219,54,1221,54,1223,54,1225,54,1227,54,1229,54,1231,54,1233,54,1235,54,1237,54,1239,54,1241,54,1243,54,1245,54,1247,54,1249,54,1251,54,1253,54,1255,54,1257,54,1259,54,1261,54,1263,54,1265,54,1267,54,1269,54,1271,54,1273,54,1275,54,1277,54,1283,54,1287,54,1292,54,1295,54,1303],{"viewBox":1024,"role":48,"ariaLabelledBy":1025,"xmlns":52,"style":53},"4 0 752 220",[1026,1027],"mf-keys-t","mf-keys-d",[56,1029,1030],{"id":1026},"Normalising the composite key on both sides",[60,1032,1033],{"id":1027},"The CRM keys 00123 with DE and 00456 with FR and the ERP keys 123 with de and 456 with FR differ in leading zeros and case. After stripping zeros and upper-casing the country, both sides read 123 DE and 456 FR and can be matched.",[64,1035],{"x":66,"y":67,"width":68,"height":1036,"fill":70},"220",[64,1038],{"x":106,"y":1039,"width":1040,"height":1041,"rx":67,"fill":1042,"stroke":1043,"style":1044},"40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[64,1046],{"x":1047,"y":1039,"width":1048,"height":1041,"rx":67,"fill":1042,"stroke":1043,"style":1044},"52.0","64.7",[93,1050,1054],{"x":1051,"y":1052,"style":1053},"84.4","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[64,1056],{"x":1057,"y":1039,"width":1058,"height":1041,"rx":67,"fill":1042,"stroke":1043,"style":1044},"116.7","97.2",[93,1060,1062],{"x":1061,"y":1052,"style":1053},"165.3","B",[64,1064],{"x":1065,"y":1039,"width":1066,"height":1041,"rx":67,"fill":1042,"stroke":1043,"style":1044},"213.9","70.0",[93,1068,1070],{"x":1069,"y":1052,"style":1053},"248.9","C",[64,1072],{"x":106,"y":1073,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},"64.0","28.0",[93,1076,1079],{"x":1077,"y":1078,"style":1053},"36.0","83.0","1",[64,1081],{"x":1047,"y":1073,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1083,821],{"x":1051,"y":1078,"style":1084},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[64,1086],{"x":1057,"y":1073,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1088,1089],{"x":1061,"y":1078,"style":1084},"customer_id",[64,1091],{"x":1065,"y":1073,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1093,1094],{"x":1069,"y":1078,"style":1084},"country",[64,1096],{"x":106,"y":109,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},[93,1098,1100],{"x":1077,"y":1099,"style":1053},"111.0","2",[64,1102],{"x":1047,"y":109,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1104,1106],{"x":1051,"y":1099,"style":1105},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","CRM",[64,1108],{"x":1057,"y":109,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1110,16],{"x":1061,"y":1099,"style":1105},[64,1112],{"x":1065,"y":109,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1114,1115],{"x":1069,"y":1099,"style":1105},"DE",[64,1117],{"x":106,"y":140,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},[93,1119,1121],{"x":1077,"y":1120,"style":1053},"139.0","3",[64,1123],{"x":1047,"y":140,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1125,1106],{"x":1051,"y":1120,"style":1105},[64,1127],{"x":1057,"y":140,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1129,1130],{"x":1061,"y":1120,"style":1105},"00456",[64,1132],{"x":1065,"y":140,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1134,1135],{"x":1069,"y":1120,"style":1105},"FR",[64,1137],{"x":106,"y":1138,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},"148.0",[93,1140,66],{"x":1077,"y":1141,"style":1053},"167.0",[64,1143],{"x":1047,"y":1138,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1145,1146],{"x":1051,"y":1141,"style":1105},"ERP",[64,1148],{"x":1057,"y":1138,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1150,24],{"x":1061,"y":1141,"style":1105},[64,1152],{"x":1065,"y":1138,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1154,1155],{"x":1069,"y":1141,"style":1105},"de",[64,1157],{"x":106,"y":1158,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},"176.0",[93,1160,1162],{"x":1077,"y":1161,"style":1053},"195.0","5",[64,1164],{"x":1047,"y":1158,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1166,1146],{"x":1051,"y":1161,"style":1105},[64,1168],{"x":1057,"y":1158,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1170,380],{"x":1061,"y":1161,"style":1105},[64,1172],{"x":1065,"y":1158,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1174,1135],{"x":1069,"y":1161,"style":1105},[64,1176],{"x":1177,"y":1039,"width":1040,"height":1041,"rx":67,"fill":1042,"stroke":1043,"style":1044},"476.1",[64,1179],{"x":1180,"y":1039,"width":1048,"height":1041,"rx":67,"fill":1042,"stroke":1043,"style":1044},"508.1",[93,1182,1054],{"x":1183,"y":1052,"style":1053},"540.5",[64,1185],{"x":1186,"y":1039,"width":1058,"height":1041,"rx":67,"fill":1042,"stroke":1043,"style":1044},"572.8",[93,1188,1062],{"x":1189,"y":1052,"style":1053},"621.4",[64,1191],{"x":1192,"y":1039,"width":1066,"height":1041,"rx":67,"fill":1042,"stroke":1043,"style":1044},"670.0",[93,1194,1070],{"x":1195,"y":1052,"style":1053},"705.0",[64,1197],{"x":1177,"y":1073,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},[93,1199,1079],{"x":1200,"y":1078,"style":1053},"492.1",[64,1202],{"x":1180,"y":1073,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1204,821],{"x":1183,"y":1078,"style":1084},[64,1206],{"x":1186,"y":1073,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1208,1089],{"x":1189,"y":1078,"style":1084},[64,1210],{"x":1192,"y":1073,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1212,1094],{"x":1195,"y":1078,"style":1084},[64,1214],{"x":1177,"y":109,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},[93,1216,1100],{"x":1200,"y":1099,"style":1053},[64,1218],{"x":1180,"y":109,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1220,1106],{"x":1183,"y":1099,"style":1105},[64,1222],{"x":1186,"y":109,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1224,24],{"x":1189,"y":1099,"style":1105},[64,1226],{"x":1192,"y":109,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1228,1115],{"x":1195,"y":1099,"style":1105},[64,1230],{"x":1177,"y":140,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},[93,1232,1121],{"x":1200,"y":1120,"style":1053},[64,1234],{"x":1180,"y":140,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1236,1106],{"x":1183,"y":1120,"style":1105},[64,1238],{"x":1186,"y":140,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1240,380],{"x":1189,"y":1120,"style":1105},[64,1242],{"x":1192,"y":140,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1244,1135],{"x":1195,"y":1120,"style":1105},[64,1246],{"x":1177,"y":1138,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},[93,1248,66],{"x":1200,"y":1141,"style":1053},[64,1250],{"x":1180,"y":1138,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1252,1146],{"x":1183,"y":1141,"style":1105},[64,1254],{"x":1186,"y":1138,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1256,24],{"x":1189,"y":1141,"style":1105},[64,1258],{"x":1192,"y":1138,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1260,1115],{"x":1195,"y":1141,"style":1105},[64,1262],{"x":1177,"y":1158,"width":1040,"height":1074,"rx":67,"fill":1042,"stroke":1043,"style":1044},[93,1264,1162],{"x":1200,"y":1161,"style":1053},[64,1266],{"x":1180,"y":1158,"width":1048,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1268,1146],{"x":1183,"y":1161,"style":1105},[64,1270],{"x":1186,"y":1158,"width":1058,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1272,380],{"x":1189,"y":1161,"style":1105},[64,1274],{"x":1192,"y":1158,"width":1066,"height":1074,"rx":67,"fill":70,"stroke":1043,"style":1044},[93,1276,1135],{"x":1195,"y":1161,"style":1105},[93,1278,1282],{"x":1279,"y":1280,"style":1281},"151.9","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","before",[93,1284,1286],{"x":1285,"y":1280,"style":1281},"608.1","after",[186,1288],{"x1":1289,"y1":1290,"x2":1291,"y2":1290,"stroke":111,"style":80},"293.9","122.0","462.1",[134,1293],{"points":1294,"fill":137},"466.1,122.0 457.1,127.0 457.1,117.0",[64,1296],{"x":1297,"y":1298,"width":1299,"height":1300,"rx":1301,"fill":70,"stroke":1043,"style":1302},"319.1","89.0","121.8","22.0","11","stroke-width:1.2px",[93,1304,1308],{"x":1305,"y":1306,"style":1307},"380.0","104.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","normalise_keys",[170,1310,1312],{"id":1311},"step-4-merge-on-the-composite-key","Step 4 — Merge on the composite key",[10,1314,1315,1316,1319],{},"The same customer number can exist in two countries, so the key is the pair. Pass both columns to ",[14,1317,1318],{},"on",", keep all customers from both files with an outer join, and label the overlapping fields with suffixes:",[175,1321,1323],{"className":207,"code":1322,"language":209,"meta":180,"style":180},"merged = a.merge(b, on=[\"customer_id\", \"country\"], how=\"outer\",\n                 suffixes=(\"_crm\", \"_erp\"), validate=\"one_to_one\", indicator=True)\nprint(merged[[\"customer_id\", \"country\", \"name_crm\", \"name_erp\", \"_merge\"]].values.tolist())\n",[14,1324,1325,1361,1401],{"__ignoreMap":180},[184,1326,1327,1330,1332,1335,1337,1339,1342,1344,1346,1348,1351,1354,1356,1359],{"class":186,"line":187},[184,1328,1329],{"class":220},"merged ",[184,1331,354],{"class":216},[184,1333,1334],{"class":220}," a.merge(b, ",[184,1336,1318],{"class":350},[184,1338,354],{"class":216},[184,1340,1341],{"class":220},"[",[184,1343,648],{"class":194},[184,1345,255],{"class":220},[184,1347,658],{"class":194},[184,1349,1350],{"class":220},"], ",[184,1352,1353],{"class":350},"how",[184,1355,354],{"class":216},[184,1357,1358],{"class":194},"\"outer\"",[184,1360,715],{"class":220},[184,1362,1363,1366,1368,1370,1373,1375,1378,1381,1384,1386,1389,1391,1394,1396,1399],{"class":186,"line":230},[184,1364,1365],{"class":350},"                 suffixes",[184,1367,354],{"class":216},[184,1369,809],{"class":220},[184,1371,1372],{"class":194},"\"_crm\"",[184,1374,255],{"class":220},[184,1376,1377],{"class":194},"\"_erp\"",[184,1379,1380],{"class":220},"), ",[184,1382,1383],{"class":350},"validate",[184,1385,354],{"class":216},[184,1387,1388],{"class":194},"\"one_to_one\"",[184,1390,255],{"class":220},[184,1392,1393],{"class":350},"indicator",[184,1395,354],{"class":216},[184,1397,1398],{"class":328},"True",[184,1400,360],{"class":220},[184,1402,1403,1405,1408,1410,1412,1414,1416,1419,1421,1424,1426,1429],{"class":186,"line":237},[184,1404,584],{"class":328},[184,1406,1407],{"class":220},"(merged[[",[184,1409,648],{"class":194},[184,1411,255],{"class":220},[184,1413,658],{"class":194},[184,1415,255],{"class":220},[184,1417,1418],{"class":194},"\"name_crm\"",[184,1420,255],{"class":220},[184,1422,1423],{"class":194},"\"name_erp\"",[184,1425,255],{"class":220},[184,1427,1428],{"class":194},"\"_merge\"",[184,1430,1431],{"class":220},"]].values.tolist())\n",[10,1433,1434,1437,1438,1441,1442,1446,1447,871],{},[14,1435,1436],{},"validate=\"one_to_one\""," fails if either file lists a customer twice, and ",[14,1439,1440],{},"indicator=True"," shows that 789 exists only in the CRM and 999 only in the ERP. Those are exactly the records someone should look at, and they are covered in more depth in ",[39,1443,1445],{"href":1444},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Ffind-rows-in-one-excel-file-missing-from-another\u002F","Find Rows in One Excel File Missing from Another",". Why validation matters on every merge is explained in ",[39,1448,1450],{"href":1449},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fvalidate-a-merge-to-avoid-duplicate-rows\u002F","Validate a pandas Merge to Avoid Duplicate Rows",[170,1452,1454],{"id":1453},"step-5-combine-the-fields-both-files-provide","Step 5 — Combine the fields both files provide",[10,1456,1457,1458,1461],{},"Both files have a name and an email. Decide, per field, which source is authoritative, fill its gaps from the other with ",[14,1459,1460],{},"combine_first",", and report real disagreements:",[175,1463,1465],{"className":207,"code":1464,"language":209,"meta":180,"style":180},"PREFER = {\"name\": \"erp\", \"email\": \"crm\"}\nfor field, source in PREFER.items():\n    other = \"erp\" if source == \"crm\" else \"crm\"\n    merged[field] = merged[f\"{field}_{source}\"].combine_first(merged[f\"{field}_{other}\"])\n\nconflict = (merged[\"email_crm\"].notna() & merged[\"email_erp\"].notna()\n            & (merged[\"email_crm\"] != merged[\"email_erp\"]))\nprint(merged.loc[conflict, [\"customer_id\", \"email_crm\", \"email_erp\"]].values.tolist())\n# [['123', 'a@x.de', 'acct@x.de']]\nresult = merged[[\"customer_id\", \"country\", \"name\", \"email\", \"balance\", \"_merge\"]]\nprint(result)\n",[14,1466,1467,1493,1510,1538,1597,1601,1628,1649,1668,1673,1708],{"__ignoreMap":180},[184,1468,1469,1472,1474,1477,1479,1481,1483,1485,1487,1489,1491],{"class":186,"line":187},[184,1470,1471],{"class":328},"PREFER",[184,1473,630],{"class":216},[184,1475,1476],{"class":220}," {",[184,1478,668],{"class":194},[184,1480,545],{"class":220},[184,1482,985],{"class":194},[184,1484,255],{"class":220},[184,1486,678],{"class":194},[184,1488,545],{"class":220},[184,1490,969],{"class":194},[184,1492,740],{"class":220},[184,1494,1495,1498,1501,1504,1507],{"class":186,"line":230},[184,1496,1497],{"class":216},"for",[184,1499,1500],{"class":220}," field, source ",[184,1502,1503],{"class":216},"in",[184,1505,1506],{"class":328}," PREFER",[184,1508,1509],{"class":220},".items():\n",[184,1511,1512,1515,1517,1520,1523,1526,1529,1532,1535],{"class":186,"line":237},[184,1513,1514],{"class":220},"    other ",[184,1516,354],{"class":216},[184,1518,1519],{"class":194}," \"erp\"",[184,1521,1522],{"class":216}," if",[184,1524,1525],{"class":220}," source ",[184,1527,1528],{"class":216},"==",[184,1530,1531],{"class":194}," \"crm\"",[184,1533,1534],{"class":216}," else",[184,1536,1537],{"class":194}," \"crm\"\n",[184,1539,1540,1543,1545,1548,1550,1552,1554,1557,1559,1562,1564,1566,1568,1570,1573,1575,1577,1579,1581,1583,1585,1587,1590,1592,1594],{"class":186,"line":243},[184,1541,1542],{"class":220},"    merged[field] ",[184,1544,354],{"class":216},[184,1546,1547],{"class":220}," merged[",[184,1549,812],{"class":216},[184,1551,815],{"class":194},[184,1553,539],{"class":818},[184,1555,1556],{"class":220},"field",[184,1558,824],{"class":818},[184,1560,1561],{"class":194},"_",[184,1563,539],{"class":818},[184,1565,821],{"class":220},[184,1567,824],{"class":818},[184,1569,815],{"class":194},[184,1571,1572],{"class":220},"].combine_first(merged[",[184,1574,812],{"class":216},[184,1576,815],{"class":194},[184,1578,539],{"class":818},[184,1580,1556],{"class":220},[184,1582,824],{"class":818},[184,1584,1561],{"class":194},[184,1586,539],{"class":818},[184,1588,1589],{"class":220},"other",[184,1591,824],{"class":818},[184,1593,815],{"class":194},[184,1595,1596],{"class":220},"])\n",[184,1598,1599],{"class":186,"line":269},[184,1600,234],{"emptyLinePlaceholder":233},[184,1602,1603,1606,1608,1611,1614,1617,1620,1622,1625],{"class":186,"line":292},[184,1604,1605],{"class":220},"conflict ",[184,1607,354],{"class":216},[184,1609,1610],{"class":220}," (merged[",[184,1612,1613],{"class":194},"\"email_crm\"",[184,1615,1616],{"class":220},"].notna() ",[184,1618,1619],{"class":216},"&",[184,1621,1547],{"class":220},[184,1623,1624],{"class":194},"\"email_erp\"",[184,1626,1627],{"class":220},"].notna()\n",[184,1629,1630,1633,1635,1637,1639,1642,1644,1646],{"class":186,"line":315},[184,1631,1632],{"class":216},"            &",[184,1634,1610],{"class":220},[184,1636,1613],{"class":194},[184,1638,913],{"class":220},[184,1640,1641],{"class":216},"!=",[184,1643,1547],{"class":220},[184,1645,1624],{"class":194},[184,1647,1648],{"class":220},"]))\n",[184,1650,1651,1653,1656,1658,1660,1662,1664,1666],{"class":186,"line":339},[184,1652,584],{"class":328},[184,1654,1655],{"class":220},"(merged.loc[conflict, [",[184,1657,648],{"class":194},[184,1659,255],{"class":220},[184,1661,1613],{"class":194},[184,1663,255],{"class":220},[184,1665,1624],{"class":194},[184,1667,1431],{"class":220},[184,1669,1670],{"class":186,"line":363},[184,1671,1672],{"class":602},"# [['123', 'a@x.de', 'acct@x.de']]\n",[184,1674,1675,1678,1680,1683,1685,1687,1689,1691,1693,1695,1697,1699,1701,1703,1705],{"class":186,"line":368},[184,1676,1677],{"class":220},"result ",[184,1679,354],{"class":216},[184,1681,1682],{"class":220}," merged[[",[184,1684,648],{"class":194},[184,1686,255],{"class":220},[184,1688,658],{"class":194},[184,1690,255],{"class":220},[184,1692,668],{"class":194},[184,1694,255],{"class":220},[184,1696,678],{"class":194},[184,1698,255],{"class":220},[184,1700,729],{"class":194},[184,1702,255],{"class":220},[184,1704,1428],{"class":194},[184,1706,1707],{"class":220},"]]\n",[184,1709,1710,1712],{"class":186,"line":390},[184,1711,584],{"class":328},[184,1713,1714],{"class":220},"(result)\n",[10,1716,1717],{},"The ERP is the legal record for names, so its \"ACME GMBH\" wins; the CRM is maintained by the sales team, so its email wins where it has one, and Birch's missing CRM email is filled from the ERP. Customer 123 has two different emails — not necessarily an error, since one may be an accounts address, but worth a line in a review sheet rather than a silent choice.",[45,1719,54,1724,54,1727,54,1730,54,1733,54,1738,54,1744,54,1748,54,1752,54,1755,54,1758,54,1761,54,1768,54,1773,54,1778,54,1782,54,1786,54,1789,54,1792,54,1796,54,1799,54,1802,54,1805,54,1808,54,1811,54,1814,54,1818,54,1821,54,1824,54,1828,54,1831,54,1833,54,1836,54,1840,54,1843,54,1846,54,1850],{"viewBox":1720,"role":48,"ariaLabelledBy":1721,"xmlns":52,"style":53},"4 0 752 238",[1722,1723],"mf-combine-t","mf-combine-d",[56,1725,1726],{"id":1722},"Deciding the value of a field both files provide",[60,1728,1729],{"id":1723},"When only one file has a value, use it. When both have the same value, use either. When both have different values, take the preferred source's value and list the row in a conflict report. When neither has a value, leave the field empty.",[64,1731],{"x":66,"y":67,"width":68,"height":1732,"fill":70},"238",[64,1734],{"x":1735,"y":107,"width":1736,"height":1737,"rx":77,"fill":110,"stroke":111,"style":80},"218.8","322.4","75.5",[82,1739,1741],{"transform":1740},"translate(368.0,29.0) scale(1.000)",[86,1742],{"d":1743,"fill":89,"stroke":118,"style":91},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5",[93,1745,1747],{"x":1305,"y":1737,"style":1746},"font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Which files have a value for this field?",[186,1749],{"x1":1305,"y1":1750,"x2":1305,"y2":1751,"stroke":111,"style":80},"91.5","111.5",[186,1753],{"x1":1306,"y1":1751,"x2":1754,"y2":1751,"stroke":111,"style":80},"656.0",[186,1756],{"x1":1306,"y1":1751,"x2":1306,"y2":1757,"stroke":111,"style":80},"157.5",[134,1759],{"points":1760,"fill":137},"104.0,161.5 99.0,152.5 109.0,152.5",[64,1762],{"x":1763,"y":1764,"width":1765,"height":1766,"rx":1767,"fill":70,"stroke":1043,"style":1302},"69.8","121.5","68.4","21.0","10",[93,1769,1772],{"x":1306,"y":1770,"style":1771},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","only one",[64,1774],{"x":106,"y":1775,"width":1776,"height":1777,"rx":77,"fill":78,"stroke":79,"style":80},"163.5","168.0","59.0",[93,1779,1781],{"x":1306,"y":1780,"style":97},"189.0","use it",[93,1783,1785],{"x":1306,"y":1784,"style":102},"208.5","combine_first fills gaps",[186,1787],{"x1":1788,"y1":1751,"x2":1788,"y2":1757,"stroke":111,"style":80},"288.0",[134,1790],{"points":1791,"fill":137},"288.0,161.5 283.0,152.5 293.0,152.5",[64,1793],{"x":1794,"y":1764,"width":1795,"height":1766,"rx":1767,"fill":70,"stroke":1043,"style":1302},"245.8","84.5",[93,1797,1798],{"x":1788,"y":1770,"style":1771},"both, equal",[64,1800],{"x":1801,"y":1775,"width":1776,"height":1777,"rx":77,"fill":110,"stroke":111,"style":80},"204.0",[93,1803,1804],{"x":1788,"y":1780,"style":1746},"use either",[93,1806,1807],{"x":1788,"y":1784,"style":102},"no action",[186,1809],{"x1":1810,"y1":1751,"x2":1810,"y2":1757,"stroke":111,"style":80},"472.0",[134,1812],{"points":1813,"fill":137},"472.0,161.5 467.0,152.5 477.0,152.5",[64,1815],{"x":1816,"y":1764,"width":1817,"height":1766,"rx":1767,"fill":70,"stroke":1043,"style":1302},"420.2","103.6",[93,1819,1820],{"x":1810,"y":1770,"style":1771},"both, different",[64,1822],{"x":1823,"y":1775,"width":1776,"height":1777,"rx":77,"fill":142,"stroke":143,"style":80},"388.0",[93,1825,1827],{"x":1810,"y":1780,"style":1826},"font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","preferred source",[93,1829,1830],{"x":1810,"y":1784,"style":102},"+ conflict report",[186,1832],{"x1":1754,"y1":1751,"x2":1754,"y2":1757,"stroke":111,"style":80},[134,1834],{"points":1835,"fill":137},"656.0,161.5 651.0,152.5 661.0,152.5",[64,1837],{"x":1838,"y":1764,"width":1839,"height":1766,"rx":1767,"fill":70,"stroke":1043,"style":1302},"626.0","60.0",[93,1841,1842],{"x":1754,"y":1770,"style":1771},"neither",[64,1844],{"x":1845,"y":1775,"width":1776,"height":1777,"rx":77,"fill":1042,"stroke":1043,"style":80},"572.0",[93,1847,1849],{"x":1754,"y":1780,"style":1848},"font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","leave empty",[93,1851,1852],{"x":1754,"y":1784,"style":102},"flag if required",[170,1854,1856],{"id":1855},"step-6-more-than-two-sources","Step 6 — More than two sources",[10,1858,1859,1860,255,1863,255,1866,1869,1870,1872],{},"With a third export — a web shop, say — chaining merges multiplies the suffixes: ",[14,1861,1862],{},"email_crm",[14,1864,1865],{},"email_erp",[14,1867,1868],{},"email_shop",". A tidier pattern is to stack the prepared sources with a ",[14,1871,821],{}," column and pick each field's value by priority:",[175,1874,1876],{"className":207,"code":1875,"language":209,"meta":180,"style":180},"stacked = pd.concat([a.assign(source=\"crm\"), b.assign(source=\"erp\")], ignore_index=True)\nrank = {\"crm\": 0, \"erp\": 1}                     # lower rank wins\nbest = (stacked.assign(rank=stacked[\"source\"].map(rank))\n               .sort_values(\"rank\")\n               .groupby([\"customer_id\", \"country\"], as_index=False)\n               .first())\nprint(best[[\"customer_id\", \"email\"]].values.tolist())\n# [['123', 'a@x.de'], ['456', 'b@x.fr'], ['789', 'c@x.uk'], ['999', nan]]\n",[14,1877,1878,1915,1944,1968,1978,2000,2005,2020],{"__ignoreMap":180},[184,1879,1880,1883,1885,1888,1890,1892,1894,1897,1899,1901,1903,1906,1909,1911,1913],{"class":186,"line":187},[184,1881,1882],{"class":220},"stacked ",[184,1884,354],{"class":216},[184,1886,1887],{"class":220}," pd.concat([a.assign(",[184,1889,821],{"class":350},[184,1891,354],{"class":216},[184,1893,969],{"class":194},[184,1895,1896],{"class":220},"), b.assign(",[184,1898,821],{"class":350},[184,1900,354],{"class":216},[184,1902,985],{"class":194},[184,1904,1905],{"class":220},")], ",[184,1907,1908],{"class":350},"ignore_index",[184,1910,354],{"class":216},[184,1912,1398],{"class":328},[184,1914,360],{"class":220},[184,1916,1917,1920,1922,1924,1926,1928,1930,1932,1934,1936,1938,1941],{"class":186,"line":230},[184,1918,1919],{"class":220},"rank ",[184,1921,354],{"class":216},[184,1923,1476],{"class":220},[184,1925,969],{"class":194},[184,1927,545],{"class":220},[184,1929,67],{"class":328},[184,1931,255],{"class":220},[184,1933,985],{"class":194},[184,1935,545],{"class":220},[184,1937,1079],{"class":328},[184,1939,1940],{"class":220},"}                     ",[184,1942,1943],{"class":602},"# lower rank wins\n",[184,1945,1946,1949,1951,1954,1957,1959,1962,1965],{"class":186,"line":237},[184,1947,1948],{"class":220},"best ",[184,1950,354],{"class":216},[184,1952,1953],{"class":220}," (stacked.assign(",[184,1955,1956],{"class":350},"rank",[184,1958,354],{"class":216},[184,1960,1961],{"class":220},"stacked[",[184,1963,1964],{"class":194},"\"source\"",[184,1966,1967],{"class":220},"].map(rank))\n",[184,1969,1970,1973,1976],{"class":186,"line":243},[184,1971,1972],{"class":220},"               .sort_values(",[184,1974,1975],{"class":194},"\"rank\"",[184,1977,360],{"class":220},[184,1979,1980,1983,1985,1987,1989,1991,1994,1996,1998],{"class":186,"line":269},[184,1981,1982],{"class":220},"               .groupby([",[184,1984,648],{"class":194},[184,1986,255],{"class":220},[184,1988,658],{"class":194},[184,1990,1350],{"class":220},[184,1992,1993],{"class":350},"as_index",[184,1995,354],{"class":216},[184,1997,357],{"class":328},[184,1999,360],{"class":220},[184,2001,2002],{"class":186,"line":292},[184,2003,2004],{"class":220},"               .first())\n",[184,2006,2007,2009,2012,2014,2016,2018],{"class":186,"line":315},[184,2008,584],{"class":328},[184,2010,2011],{"class":220},"(best[[",[184,2013,648],{"class":194},[184,2015,255],{"class":220},[184,2017,678],{"class":194},[184,2019,1431],{"class":220},[184,2021,2022],{"class":186,"line":339},[184,2023,2024],{"class":602},"# [['123', 'a@x.de'], ['456', 'b@x.fr'], ['789', 'c@x.uk'], ['999', nan]]\n",[10,2026,2027,2030,2031,2033,2034,2036],{},[14,2028,2029],{},"groupby().first()"," takes the first non-missing value per column, so after sorting by rank each field comes from the highest-priority source that has it. Adding a source means one more mapping in ",[14,2032,627],{}," and one entry in ",[14,2035,1956],{},". For per-field priorities, as in Step 5, run the same pattern once per field with its own ranking.",[170,2038,2040],{"id":2039},"step-7-write-the-combined-file-with-its-review-sheets","Step 7 — Write the combined file with its review sheets",[10,2042,2043],{},"Write the merged customers alongside the conflicts and the one-sided records, so the people who own each system can act on them:",[175,2045,2047],{"className":207,"code":2046,"language":209,"meta":180,"style":180},"with pd.ExcelWriter(\"customers_combined.xlsx\") as writer:\n    result.drop(columns=\"_merge\").to_excel(writer, sheet_name=\"Customers\", index=False)\n    merged.loc[conflict, [\"customer_id\", \"country\", \"email_crm\", \"email_erp\"]].to_excel(\n        writer, sheet_name=\"Email conflicts\", index=False)\n    merged.loc[merged[\"_merge\"] != \"both\", [\"customer_id\", \"country\", \"_merge\"]].to_excel(\n        writer, sheet_name=\"Only in one system\", index=False)\nprint(pd.ExcelFile(\"customers_combined.xlsx\").sheet_names)\n",[14,2048,2049,2068,2100,2122,2144,2173,2194],{"__ignoreMap":180},[184,2050,2051,2054,2057,2060,2063,2065],{"class":186,"line":187},[184,2052,2053],{"class":216},"with",[184,2055,2056],{"class":220}," pd.ExcelWriter(",[184,2058,2059],{"class":194},"\"customers_combined.xlsx\"",[184,2061,2062],{"class":220},") ",[184,2064,224],{"class":216},[184,2066,2067],{"class":220}," writer:\n",[184,2069,2070,2073,2075,2077,2079,2082,2085,2087,2090,2092,2094,2096,2098],{"class":186,"line":230},[184,2071,2072],{"class":220},"    result.drop(",[184,2074,852],{"class":350},[184,2076,354],{"class":216},[184,2078,1428],{"class":194},[184,2080,2081],{"class":220},").to_excel(writer, ",[184,2083,2084],{"class":350},"sheet_name",[184,2086,354],{"class":216},[184,2088,2089],{"class":194},"\"Customers\"",[184,2091,255],{"class":220},[184,2093,351],{"class":350},[184,2095,354],{"class":216},[184,2097,357],{"class":328},[184,2099,360],{"class":220},[184,2101,2102,2105,2107,2109,2111,2113,2115,2117,2119],{"class":186,"line":237},[184,2103,2104],{"class":220},"    merged.loc[conflict, [",[184,2106,648],{"class":194},[184,2108,255],{"class":220},[184,2110,658],{"class":194},[184,2112,255],{"class":220},[184,2114,1613],{"class":194},[184,2116,255],{"class":220},[184,2118,1624],{"class":194},[184,2120,2121],{"class":220},"]].to_excel(\n",[184,2123,2124,2127,2129,2131,2134,2136,2138,2140,2142],{"class":186,"line":243},[184,2125,2126],{"class":220},"        writer, ",[184,2128,2084],{"class":350},[184,2130,354],{"class":216},[184,2132,2133],{"class":194},"\"Email conflicts\"",[184,2135,255],{"class":220},[184,2137,351],{"class":350},[184,2139,354],{"class":216},[184,2141,357],{"class":328},[184,2143,360],{"class":220},[184,2145,2146,2149,2151,2153,2155,2158,2161,2163,2165,2167,2169,2171],{"class":186,"line":269},[184,2147,2148],{"class":220},"    merged.loc[merged[",[184,2150,1428],{"class":194},[184,2152,913],{"class":220},[184,2154,1641],{"class":216},[184,2156,2157],{"class":194}," \"both\"",[184,2159,2160],{"class":220},", [",[184,2162,648],{"class":194},[184,2164,255],{"class":220},[184,2166,658],{"class":194},[184,2168,255],{"class":220},[184,2170,1428],{"class":194},[184,2172,2121],{"class":220},[184,2174,2175,2177,2179,2181,2184,2186,2188,2190,2192],{"class":186,"line":292},[184,2176,2126],{"class":220},[184,2178,2084],{"class":350},[184,2180,354],{"class":216},[184,2182,2183],{"class":194},"\"Only in one system\"",[184,2185,255],{"class":220},[184,2187,351],{"class":350},[184,2189,354],{"class":216},[184,2191,357],{"class":328},[184,2193,360],{"class":220},[184,2195,2196,2198,2201,2203],{"class":186,"line":315},[184,2197,584],{"class":328},[184,2199,2200],{"class":220},"(pd.ExcelFile(",[184,2202,2059],{"class":194},[184,2204,2205],{"class":220},").sheet_names)\n",[10,2207,2208,2209,2211,2212,2215],{},"Remember that the key columns were read as text: if the output must show ",[14,2210,16],{}," again, pad with ",[14,2213,2214],{},"str.zfill"," before writing, and the cells will stay text in Excel.",[170,2217,2219],{"id":2218},"common-pitfalls","Common pitfalls",[2221,2222,2223,2231,2245,2255],"ul",{},[2224,2225,2226,2230],"li",{},[2227,2228,2229],"strong",{},"Merging before normalising."," Keys that differ only by zeros, spaces or case never match, and the merge reports them as one-sided rather than failing.",[2224,2232,2233,2236,2237,2240,2241,2244],{},[2227,2234,2235],{},"Stripping zeros from a zero."," ",[14,2238,2239],{},"\"0\".lstrip(\"0\")"," is an empty string, which then matches nothing, or matches every other empty key. If an ID of 0 is possible, use ",[14,2242,2243],{},"str.lstrip(\"0\").replace(\"\", \"0\")"," or convert to integers after validating that every key is numeric.",[2224,2246,2247,2250,2251,2254],{},[2227,2248,2249],{},"Positional renaming."," Assigning ",[14,2252,2253],{},"df.columns = [...]"," breaks as soon as a column is added. Rename by name with a mapping.",[2224,2256,2257,2260,2261,2264,2265,33,2268,2271],{},[2227,2258,2259],{},"Unlabelled overlaps."," Without ",[14,2262,2263],{},"suffixes",", pandas adds ",[14,2266,2267],{},"_x",[14,2269,2270],{},"_y",", and nobody remembers which file was which. Name the sources.",[170,2273,2275],{"id":2274},"conclusion","Conclusion",[10,2277,2278],{},"Merging files that name the same fields differently is a mapping problem before it is a merge problem. Read keys as text, rename each file to one shared schema, normalise key values with one function applied to both sides, and merge on the full composite key with validation and an indicator. Resolve fields both files provide with an explicit source priority, and hand the conflicts and one-sided records back to the people who own the data.",[170,2280,2282],{"id":2281},"frequently-asked-questions","Frequently asked questions",[10,2284,2285,2288],{},[2227,2286,2287],{},"How do I merge two DataFrames when the key columns have different names?","\nEither pass left_on and right_on with the two names, or rename one or both frames to a shared name first. Renaming is clearer when several columns differ, because the merged frame then has one name per field.",[10,2290,2291,2294],{},[2227,2292,2293],{},"Why does pandas refuse to merge on str and int64 columns?","\nOne file stores the key as text, the other as a number, and pandas will not guess how to compare them. Read both keys as text with dtype=str and normalise them the same way before merging.",[10,2296,2297,2300],{},[2227,2298,2299],{},"How do I keep leading zeros in an ID column from Excel?","\nPass dtype={\"column\": str} to read_excel. Without it, pandas converts text such as \"00123\" to the number 123 and the zeros are gone.",[10,2302,2303,2306],{},[2227,2304,2305],{},"How do I combine two columns that hold the same field from different files?","\nMerge with suffixes so both survive, then use combine_first on the preferred column to fill its gaps from the other. Report rows where both have values that disagree.",[170,2308,2310],{"id":2309},"related","Related",[2221,2312,2313,2319,2326,2333],{},[2224,2314,2315,2316,2318],{},"Up one level: ",[39,2317,42],{"href":41}," — combining data from several workbooks.",[2224,2320,2321,2325],{},[39,2322,2324],{"href":2323},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-two-excel-files-on-common-column-python\u002F","Merge Two Excel Files on a Common Column in Python"," — the basic merge.",[2224,2327,2328,2332],{},[39,2329,2331],{"href":2330},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fconcatenate-excel-sheets-with-different-columns\u002F","Concatenate Excel Sheets with Different Columns"," — stacking rather than joining.",[2224,2334,2335,2339],{},[39,2336,2338],{"href":2337},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Ffuzzy-match-names-between-two-excel-files-with-python\u002F","Fuzzy Match Names Between Two Excel Files with Python"," — when there is no shared key at all.",[2341,2342,2343],"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 .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":180,"searchDepth":230,"depth":230,"links":2345},[2346,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357],{"id":172,"depth":230,"text":173},{"id":498,"depth":230,"text":499},{"id":609,"depth":230,"text":610},{"id":874,"depth":230,"text":875},{"id":1311,"depth":230,"text":1312},{"id":1453,"depth":230,"text":1454},{"id":1855,"depth":230,"text":1856},{"id":2039,"depth":230,"text":2040},{"id":2218,"depth":230,"text":2219},{"id":2274,"depth":230,"text":2275},{"id":2281,"depth":230,"text":2282},{"id":2309,"depth":230,"text":2310},"2026-09-23","Two systems export the same customers under different headers — \"Customer No\" and \"cust_id\", \"Email\" and \"email_address\" — with keys formatted differently. Map both files to one schema, normalise the keys, merge on several columns and combine the overlapping fields with a clear rule for which source wins.","md",[2362,2364,2366,2368],{"q":2287,"a":2363},"Either pass left_on and right_on with the two names, or rename one or both frames to a shared name first. Renaming is clearer when several columns differ, because the merged frame then has one name per field.",{"q":2293,"a":2365},"One file stores the key as text, the other as a number, and pandas will not guess how to compare them. Read both keys as text with dtype=str and normalise them the same way before merging.",{"q":2299,"a":2367},"Pass dtype={\"column\": str} to read_excel. Without it, pandas converts text such as \"00123\" to the number 123 and the zeros are gone.",{"q":2305,"a":2369},"Merge with suffixes so both survive, then use combine_first on the preferred column to fill its gaps from the other. Report rows where both have values that disagree.","merge excel files with different column names in pandas",null,{"breadcrumb":2373},[2374,2377,2380],{"name":2375,"item":2376},"Home","\u002F",{"name":2378,"item":2379},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2381,"item":41},"Merging and Joining Excel DataFrames with Pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names",{"title":5,"description":2384},"Join two Excel exports whose headers and key formats differ — rename to a shared schema, fix leading zeros and str-versus-int keys, composite keys, suffixes for overlapping columns, combine_first with a source priority and a conflict report.","merge-excel-files-with-different-column-names","advanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names\u002Findex",[2388,2389,2390],"joins-and-lookups","sheets-and-files","pandas","how-to","b2QK4kOAJeFWeSCJrr1imv1xuMf2l31NhXwZFPkrgto",[2394,2398],{"title":2395,"path":2396,"stem":2397,"children":-1},"Merge Excel Data on Multiple Key Columns with pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-data-on-multiple-key-columns","advanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-data-on-multiple-key-columns\u002Findex",{"title":2399,"path":2400,"stem":2401,"children":-1},"Merge More Than Two Excel Files on a Key Column","\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-more-than-two-excel-files-on-a-key-column","advanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-more-than-two-excel-files-on-a-key-column\u002Findex",[2403,2405],{"path":2404,"title":2378},"\u002Fadvanced-data-transformation-and-cleaning",{"path":2406,"title":2381},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes",[],[2409,2412,2415,2418,2421,2424],{"path":2410,"title":2411,"kind":2391},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fcompare-two-excel-files-for-differences-with-python","Compare Two Excel Files for Differences with Python",{"path":2413,"title":2414,"kind":2391},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fconvert-multi-currency-transactions-with-an-fx-rate-table","Convert Multi-Currency Transactions with an FX Rate Table",{"path":2416,"title":2417,"kind":2391},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-differences-between-two-columns-with-openpyxl","Highlight Differences Between Two Columns with openpyxl",{"path":2419,"title":2420,"kind":2391},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fmap-free-text-job-titles-to-standard-categories","Map Free-Text Job Titles to Standard Categories",{"path":2422,"title":2423,"kind":2391},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fstandardise-category-values-with-a-mapping-table","Standardise Category Values with a Mapping Table in pandas",{"path":2425,"title":2426,"kind":2391},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fapproximate-match-vlookup-in-pandas","Approximate-Match VLOOKUP for Tiered Rates in pandas",1790972096372]