[{"data":1,"prerenderedAt":2133},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas":2098,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas":2107,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas":2114,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas":2115},{"id":4,"title":5,"body":6,"dateModified":2064,"datePublished":2064,"description":2065,"extension":2066,"faq":2067,"keyword":2076,"kind":2077,"meta":2078,"navigation":288,"path":2087,"seo":2088,"slug":2091,"stem":2092,"topics":2093,"type":2096,"__hash__":2097},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas\u002Findex.md","Split a Column into Multiple Columns with pandas",{"type":7,"value":8,"toc":2049},"minimark",[9,41,220,225,253,260,489,493,503,598,619,623,646,793,801,872,876,883,1091,1110,1114,1117,1218,1231,1235,1248,1392,1407,1494,1498,1501,1598,1611,1615,1618,1798,1804,1808,1927,1931,1952,1956,1975,1979,1985,1991,1997,2003,2007,2045],[10,11,12,13,17,18,21,22,25,26,29,30,34,35,40],"p",{},"Exports love to cram several facts into one cell: ",[14,15,16],"code",{},"Smith, Jane"," in a name column, ",[14,19,20],{},"UK-LON-0042"," as a store\ncode, ",[14,23,24],{},"12 High Street, Leeds, LS1 4AB"," as an address, or ",[14,27,28],{},"red; blue; green"," as a list of tags. Excel's\n",[31,32,33],"strong",{},"Data → Text to Columns"," wizard splits them once, by hand, and has to be repeated on every new file. pandas\ndoes the same split in a line that runs on every file automatically — and handles the awkward cases the wizard\ndoes not. This guide, part of ",[36,37,39],"a",{"href":38},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002F","Cleaning Excel Data With Pandas",",\ncovers each shape of split you are likely to meet.",[42,43,51,52,51,56,51,60,51,67,51,75,51,79,51,86,51,89,51,93,51,97,51,101,51,104,51,109,51,111,51,115,51,117,51,120,51,122,51,125,51,128,51,132,51,134,51,137,51,139,51,141,51,143,51,146,51,155,51,161,51,164,51,168,51,170,51,173,51,175,51,178,51,180,51,183,51,186,51,189,51,191,51,194,51,196,51,199,51,201,51,204,51,209,51,214],"svg",{"viewBox":44,"role":45,"ariaLabelledBy":46,"xmlns":49,"style":50},"0 0 646 224","img",[47,48],"spl-before-t","spl-before-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:646px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[53,54,55],"title",{"id":47},"Columns that pack several values into one cell",[57,58,59],"desc",{"id":48},"A sheet where the Customer column holds surname and first name separated by a comma, Store holds country, city and number separated by hyphens, and Tags holds a semicolon separated list.",[61,62],"rect",{"x":63,"y":63,"width":64,"height":65,"fill":66},"0","646","224","#ffffff",[61,68],{"x":69,"y":69,"width":70,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},"20","36","30","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[61,76],{"x":77,"y":69,"width":78,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},"56","120",[80,81,85],"text",{"x":82,"y":83,"style":84},"116","40","font-size:11.5px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[61,87],{"x":88,"y":69,"width":78,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},"176",[80,90,92],{"x":91,"y":83,"style":84},"236","B",[61,94],{"x":95,"y":69,"width":96,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},"296","150",[80,98,100],{"x":99,"y":83,"style":84},"371","C",[61,102],{"x":69,"y":103,"width":70,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},"50",[80,105,108],{"x":106,"y":107,"style":84},"38","70","1",[61,110],{"x":77,"y":103,"width":78,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},[80,112,114],{"x":82,"y":107,"style":113},"font-size:11.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","Customer",[61,116],{"x":88,"y":103,"width":78,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},[80,118,119],{"x":91,"y":107,"style":113},"Store",[61,121],{"x":95,"y":103,"width":96,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},[80,123,124],{"x":99,"y":107,"style":113},"Tags",[61,126],{"x":69,"y":127,"width":70,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},"80",[80,129,131],{"x":106,"y":130,"style":84},"100","2",[61,133],{"x":77,"y":127,"width":78,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,135,16],{"x":82,"y":130,"style":136},"font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[61,138],{"x":88,"y":127,"width":78,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,140,20],{"x":91,"y":130,"style":136},[61,142],{"x":95,"y":127,"width":96,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,144,145],{"x":99,"y":130,"style":136},"red; blue",[61,147],{"x":148,"y":149,"width":150,"height":151,"rx":152,"fill":153,"stroke":154,"style":74},"466","82","160","26","8","#fdefd8","var(--gold,#b4740a)",[80,156,160],{"x":157,"y":158,"style":159},"546","99","font-size:11.5px;font-weight:600;fill:var(--gold-ink,#7a4e06);text-anchor:middle","comma, hyphen, list",[61,162],{"x":69,"y":163,"width":70,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},"110",[80,165,167],{"x":106,"y":166,"style":84},"130","3",[61,169],{"x":77,"y":163,"width":78,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,171,172],{"x":82,"y":166,"style":136},"Okafor, Chidi",[61,174],{"x":88,"y":163,"width":78,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,176,177],{"x":91,"y":166,"style":136},"NG-LOS-0007",[61,179],{"x":95,"y":163,"width":96,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,181,182],{"x":99,"y":166,"style":136},"green",[61,184],{"x":69,"y":185,"width":70,"height":71,"rx":63,"fill":72,"stroke":73,"style":74},"140",[80,187,188],{"x":106,"y":150,"style":84},"4",[61,190],{"x":77,"y":185,"width":78,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,192,193],{"x":82,"y":150,"style":136},"de la Cruz, Ana",[61,195],{"x":88,"y":185,"width":78,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,197,198],{"x":91,"y":150,"style":136},"ES-MAD-0113",[61,200],{"x":95,"y":185,"width":96,"height":71,"rx":63,"fill":66,"stroke":73,"style":74},[80,202,203],{"x":99,"y":150,"style":136},"blue; green; red",[61,205],{"x":148,"y":206,"width":150,"height":151,"rx":152,"fill":207,"stroke":208,"style":74},"142","#fee8f2","var(--accent,#f43f8f)",[80,210,213],{"x":157,"y":211,"style":212},"159","font-size:11.5px;font-weight:600;fill:var(--accent-ink,#be185d);text-anchor:middle","extra spaces in name",[80,215,219],{"x":216,"y":217,"style":218},"323","202","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","three columns, three different splitting rules",[221,222,224],"h2",{"id":223},"prerequisites","Prerequisites",[226,227,232],"pre",{"className":228,"code":229,"language":230,"meta":231,"style":231},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[14,233,234],{"__ignoreMap":231},[235,236,239,243,247,250],"span",{"class":237,"line":238},"line",1,[235,240,242],{"class":241},"sMTad","pip",[235,244,246],{"class":245},"srMev"," install",[235,248,249],{"class":245}," pandas",[235,251,252],{"class":245}," openpyxl\n",[10,254,255,256,259],{},"The examples use this sheet, written to ",[14,257,258],{},"customers.xlsx"," so every block can read it back:",[226,261,265],{"className":262,"code":263,"language":264,"meta":231,"style":231},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\npd.DataFrame({\n    \"Customer\": [\"Smith, Jane\", \"Okafor, Chidi\", \"de la Cruz, Ana\", \"Lee,Min\"],\n    \"Store\": [\"UK-LON-0042\", \"NG-LOS-0007\", \"ES-MAD-0113\", \"KR-SEL-0021\"],\n    \"Address\": [\"12 High Street, Leeds, LS1 4AB\", \"3 Marina Road, Lagos, 101241\",\n                \"Calle Mayor 5, Madrid, 28013\", \"88 Jong-ro, Seoul, 03161\"],\n    \"Tags\": [\"red; blue\", \"green\", \"blue; green; red\", \"\"],\n}).to_excel(\"customers.xlsx\", index=False)\n\ndf = pd.read_excel(\"customers.xlsx\", dtype={\"Tags\": str}).fillna({\"Tags\": \"\"})\n","python",[14,266,267,283,290,296,327,355,374,387,415,440,445],{"__ignoreMap":231},[235,268,269,273,277,280],{"class":237,"line":238},[235,270,272],{"class":271},"s-kum","import",[235,274,276],{"class":275},"skGVy"," pandas ",[235,278,279],{"class":271},"as",[235,281,282],{"class":275}," pd\n",[235,284,286],{"class":237,"line":285},2,[235,287,289],{"emptyLinePlaceholder":288},true,"\n",[235,291,293],{"class":237,"line":292},3,[235,294,295],{"class":275},"pd.DataFrame({\n",[235,297,299,302,305,308,311,314,316,319,321,324],{"class":237,"line":298},4,[235,300,301],{"class":245},"    \"Customer\"",[235,303,304],{"class":275},": [",[235,306,307],{"class":245},"\"Smith, Jane\"",[235,309,310],{"class":275},", ",[235,312,313],{"class":245},"\"Okafor, Chidi\"",[235,315,310],{"class":275},[235,317,318],{"class":245},"\"de la Cruz, Ana\"",[235,320,310],{"class":275},[235,322,323],{"class":245},"\"Lee,Min\"",[235,325,326],{"class":275},"],\n",[235,328,330,333,335,338,340,343,345,348,350,353],{"class":237,"line":329},5,[235,331,332],{"class":245},"    \"Store\"",[235,334,304],{"class":275},[235,336,337],{"class":245},"\"UK-LON-0042\"",[235,339,310],{"class":275},[235,341,342],{"class":245},"\"NG-LOS-0007\"",[235,344,310],{"class":275},[235,346,347],{"class":245},"\"ES-MAD-0113\"",[235,349,310],{"class":275},[235,351,352],{"class":245},"\"KR-SEL-0021\"",[235,354,326],{"class":275},[235,356,358,361,363,366,368,371],{"class":237,"line":357},6,[235,359,360],{"class":245},"    \"Address\"",[235,362,304],{"class":275},[235,364,365],{"class":245},"\"12 High Street, Leeds, LS1 4AB\"",[235,367,310],{"class":275},[235,369,370],{"class":245},"\"3 Marina Road, Lagos, 101241\"",[235,372,373],{"class":275},",\n",[235,375,377,380,382,385],{"class":237,"line":376},7,[235,378,379],{"class":245},"                \"Calle Mayor 5, Madrid, 28013\"",[235,381,310],{"class":275},[235,383,384],{"class":245},"\"88 Jong-ro, Seoul, 03161\"",[235,386,326],{"class":275},[235,388,390,393,395,398,400,403,405,408,410,413],{"class":237,"line":389},8,[235,391,392],{"class":245},"    \"Tags\"",[235,394,304],{"class":275},[235,396,397],{"class":245},"\"red; blue\"",[235,399,310],{"class":275},[235,401,402],{"class":245},"\"green\"",[235,404,310],{"class":275},[235,406,407],{"class":245},"\"blue; green; red\"",[235,409,310],{"class":275},[235,411,412],{"class":245},"\"\"",[235,414,326],{"class":275},[235,416,418,421,424,426,430,433,437],{"class":237,"line":417},9,[235,419,420],{"class":275},"}).to_excel(",[235,422,423],{"class":245},"\"customers.xlsx\"",[235,425,310],{"class":275},[235,427,429],{"class":428},"sa561","index",[235,431,432],{"class":271},"=",[235,434,436],{"class":435},"sP0c6","False",[235,438,439],{"class":275},")\n",[235,441,443],{"class":237,"line":442},10,[235,444,289],{"emptyLinePlaceholder":288},[235,446,448,451,453,456,458,460,463,465,468,471,474,477,480,482,484,486],{"class":237,"line":447},11,[235,449,450],{"class":275},"df ",[235,452,432],{"class":271},[235,454,455],{"class":275}," pd.read_excel(",[235,457,423],{"class":245},[235,459,310],{"class":275},[235,461,462],{"class":428},"dtype",[235,464,432],{"class":271},[235,466,467],{"class":275},"{",[235,469,470],{"class":245},"\"Tags\"",[235,472,473],{"class":275},": ",[235,475,476],{"class":435},"str",[235,478,479],{"class":275},"}).fillna({",[235,481,470],{"class":245},[235,483,473],{"class":275},[235,485,412],{"class":245},[235,487,488],{"class":275},"})\n",[221,490,492],{"id":491},"step-1-split-on-a-delimiter-into-new-columns","Step 1 — Split on a delimiter into new columns",[10,494,495,498,499,502],{},[14,496,497],{},"Series.str.split(sep, expand=True)"," returns a DataFrame with one column per piece. Assign its columns into the original frame by name, and strip whitespace from\neach piece, because a delimiter such as ",[14,500,501],{},"\", \""," is rarely applied consistently.",[226,504,506],{"className":262,"code":505,"language":264,"meta":231,"style":231},"parts = df[\"Customer\"].str.split(\",\", expand=True)\ndf[\"LastName\"] = parts[0].str.strip()\ndf[\"FirstName\"] = parts[1].str.strip()\nprint(df[[\"Customer\", \"LastName\", \"FirstName\"]])\n",[14,507,508,539,560,577],{"__ignoreMap":231},[235,509,510,513,515,518,521,524,527,529,532,534,537],{"class":237,"line":238},[235,511,512],{"class":275},"parts ",[235,514,432],{"class":271},[235,516,517],{"class":275}," df[",[235,519,520],{"class":245},"\"Customer\"",[235,522,523],{"class":275},"].str.split(",[235,525,526],{"class":245},"\",\"",[235,528,310],{"class":275},[235,530,531],{"class":428},"expand",[235,533,432],{"class":271},[235,535,536],{"class":435},"True",[235,538,439],{"class":275},[235,540,541,544,547,550,552,555,557],{"class":237,"line":285},[235,542,543],{"class":275},"df[",[235,545,546],{"class":245},"\"LastName\"",[235,548,549],{"class":275},"] ",[235,551,432],{"class":271},[235,553,554],{"class":275}," parts[",[235,556,63],{"class":435},[235,558,559],{"class":275},"].str.strip()\n",[235,561,562,564,567,569,571,573,575],{"class":237,"line":292},[235,563,543],{"class":275},[235,565,566],{"class":245},"\"FirstName\"",[235,568,549],{"class":275},[235,570,432],{"class":271},[235,572,554],{"class":275},[235,574,108],{"class":435},[235,576,559],{"class":275},[235,578,579,582,585,587,589,591,593,595],{"class":237,"line":298},[235,580,581],{"class":435},"print",[235,583,584],{"class":275},"(df[[",[235,586,520],{"class":245},[235,588,310],{"class":275},[235,590,546],{"class":245},[235,592,310],{"class":275},[235,594,566],{"class":245},[235,596,597],{"class":275},"]])\n",[10,599,600,601,603,604,606,607,610,611,613,614,618],{},"Splitting on ",[14,602,526],{}," rather than ",[14,605,501],{}," and stripping afterwards is the robust habit: it handles ",[14,608,609],{},"Lee,Min"," with no space as well as ",[14,612,16],{},". Cleaning whitespace\nmore generally — non-breaking spaces, doubled spaces — is covered in\n",[36,615,617],{"href":616},"\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",".",[221,620,622],{"id":621},"step-2-cap-the-number-of-pieces-with-n-and-rsplit","Step 2 — Cap the number of pieces with n and rsplit",[10,624,625,626,628,629,632,633,637,638,641,642,645],{},"An address such as ",[14,627,24],{}," splits into three parts — until one arrives as ",[14,630,631],{},"Flat 2, 12 High Street, Leeds, LS1 4AB"," and produces four,\nshifting every column. Decide which end of the string is reliable and split from that end with a limit. Here the city and postcode are always the ",[634,635,636],"em",{},"last"," two parts,\nso ",[14,639,640],{},"rsplit"," with ",[14,643,644],{},"n=2"," keeps any extra commas in the street part.",[226,647,649],{"className":262,"code":648,"language":264,"meta":231,"style":231},"address = df[\"Address\"].str.rsplit(\",\", n=2, expand=True)\ndf[[\"Street\", \"City\", \"Postcode\"]] = address.apply(lambda col: col.str.strip())\nprint(df[[\"Street\", \"City\", \"Postcode\"]])\n\nodd = pd.Series([\"Flat 2, 12 High Street, Leeds, LS1 4AB\"]).str.rsplit(\",\", n=2, expand=True)\nprint(odd.iloc[0].tolist())       # ['Flat 2, 12 High Street', ' Leeds', ' LS1 4AB']\n",[14,650,651,687,719,737,741,777],{"__ignoreMap":231},[235,652,653,656,658,660,663,666,668,670,673,675,677,679,681,683,685],{"class":237,"line":238},[235,654,655],{"class":275},"address ",[235,657,432],{"class":271},[235,659,517],{"class":275},[235,661,662],{"class":245},"\"Address\"",[235,664,665],{"class":275},"].str.rsplit(",[235,667,526],{"class":245},[235,669,310],{"class":275},[235,671,672],{"class":428},"n",[235,674,432],{"class":271},[235,676,131],{"class":435},[235,678,310],{"class":275},[235,680,531],{"class":428},[235,682,432],{"class":271},[235,684,536],{"class":435},[235,686,439],{"class":275},[235,688,689,692,695,697,700,702,705,708,710,713,716],{"class":237,"line":285},[235,690,691],{"class":275},"df[[",[235,693,694],{"class":245},"\"Street\"",[235,696,310],{"class":275},[235,698,699],{"class":245},"\"City\"",[235,701,310],{"class":275},[235,703,704],{"class":245},"\"Postcode\"",[235,706,707],{"class":275},"]] ",[235,709,432],{"class":271},[235,711,712],{"class":275}," address.apply(",[235,714,715],{"class":271},"lambda",[235,717,718],{"class":275}," col: col.str.strip())\n",[235,720,721,723,725,727,729,731,733,735],{"class":237,"line":292},[235,722,581],{"class":435},[235,724,584],{"class":275},[235,726,694],{"class":245},[235,728,310],{"class":275},[235,730,699],{"class":245},[235,732,310],{"class":275},[235,734,704],{"class":245},[235,736,597],{"class":275},[235,738,739],{"class":237,"line":298},[235,740,289],{"emptyLinePlaceholder":288},[235,742,743,746,748,751,754,757,759,761,763,765,767,769,771,773,775],{"class":237,"line":329},[235,744,745],{"class":275},"odd ",[235,747,432],{"class":271},[235,749,750],{"class":275}," pd.Series([",[235,752,753],{"class":245},"\"Flat 2, 12 High Street, Leeds, LS1 4AB\"",[235,755,756],{"class":275},"]).str.rsplit(",[235,758,526],{"class":245},[235,760,310],{"class":275},[235,762,672],{"class":428},[235,764,432],{"class":271},[235,766,131],{"class":435},[235,768,310],{"class":275},[235,770,531],{"class":428},[235,772,432],{"class":271},[235,774,536],{"class":435},[235,776,439],{"class":275},[235,778,779,781,784,786,789],{"class":237,"line":357},[235,780,581],{"class":435},[235,782,783],{"class":275},"(odd.iloc[",[235,785,63],{"class":435},[235,787,788],{"class":275},"].tolist())       ",[235,790,792],{"class":791},"s-wDw","# ['Flat 2, 12 High Street', ' Leeds', ' LS1 4AB']\n",[10,794,795,641,798,800],{},[14,796,797],{},"split",[14,799,672],{}," works the same way from the left. Without a limit, a single row with an extra delimiter adds a column to the whole result, and assigning three\ncolumn names to four columns raises a length error — which is at least loud.",[42,802,51,808,51,811,51,814,51,818,51,824,51,830,51,833,51,837,51,841,51,845,51,850,51,855,51,859,51,862,51,864,51,867],{"viewBox":803,"role":45,"ariaLabelledBy":804,"xmlns":49,"style":807},"0 0 760 191",[805,806],"spl-limit-t","spl-limit-d","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[53,809,810],{"id":805},"Splitting an address with and without a limit",[57,812,813],{"id":806},"Splitting on every comma turns an address with an extra comma into four pieces and misaligns the columns. Splitting from the right with n equal to 2 always yields street, city and postcode, keeping extra commas in the street.",[61,815],{"x":63,"y":63,"width":816,"height":817,"fill":66},"760","191",[61,819],{"x":69,"y":69,"width":820,"height":821,"rx":822,"fill":207,"stroke":208,"style":823},"350","127","14","stroke-width:2px",[80,825,829],{"x":826,"y":827,"style":828},"195","46","font-size:13px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","str.split(\",\")",[237,831],{"x1":70,"y1":77,"x2":832,"y2":77,"stroke":208,"style":74},"354",[80,834,836],{"x":826,"y":835,"style":136},"78","Flat 2 | 12 High Street",[80,838,840],{"x":826,"y":839,"style":136},"101","Leeds | LS1 4AB",[80,842,844],{"x":826,"y":843,"style":136},"124","four pieces, columns shift",[61,846],{"x":847,"y":69,"width":820,"height":821,"rx":822,"fill":848,"stroke":849,"style":823},"390","#d9f4f1","var(--teal,#0f9488)",[80,851,854],{"x":852,"y":827,"style":853},"565","font-size:13px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","str.rsplit(\",\", n=2)",[237,856],{"x1":857,"y1":77,"x2":858,"y2":77,"stroke":849,"style":74},"406","724",[80,860,861],{"x":852,"y":835,"style":136},"Flat 2, 12 High Street",[80,863,840],{"x":852,"y":839,"style":136},[80,865,866],{"x":852,"y":843,"style":136},"always three pieces",[80,868,871],{"x":869,"y":870,"style":218},"380","177","split from the end whose structure never changes",[221,873,875],{"id":874},"step-3-extract-parts-with-a-regular-expression","Step 3 — Extract parts with a regular expression",[10,877,878,879,882],{},"Codes with a fixed structure are better described than split. ",[14,880,881],{},"str.extract"," with named groups returns a DataFrame whose column names come from the pattern, and rows\nthat do not match come back as missing values rather than silently wrong pieces.",[226,884,886],{"className":262,"code":885,"language":264,"meta":231,"style":231},"store = df[\"Store\"].str.extract(r\"^(?P\u003CCountry>[A-Z]{2})-(?P\u003CCityCode>[A-Z]{3})-(?P\u003CStoreNo>\\d{4})$\")\ndf = df.join(store)\ndf[\"StoreNo\"] = df[\"StoreNo\"].astype(\"Int64\")\nprint(df[[\"Store\", \"Country\", \"CityCode\", \"StoreNo\"]])\n\nbad = df[\"Store\"].str.extract(r\"^(?P\u003CCountry>[A-Z]{2})-\")[\"Country\"].isna()\nprint(\"codes that do not match:\", df.loc[bad, \"Store\"].tolist())\n",[14,887,888,972,981,1004,1028,1032,1074],{"__ignoreMap":231},[235,889,890,893,895,897,900,903,906,909,912,916,919,923,926,929,932,935,938,941,943,945,947,950,952,954,956,959,962,965,968,970],{"class":237,"line":238},[235,891,892],{"class":275},"store ",[235,894,432],{"class":271},[235,896,517],{"class":275},[235,898,899],{"class":245},"\"Store\"",[235,901,902],{"class":275},"].str.extract(",[235,904,905],{"class":271},"r",[235,907,908],{"class":245},"\"",[235,910,911],{"class":435},"^(",[235,913,915],{"class":914},"sx1sP","?P\u003CCountry>",[235,917,918],{"class":435},"[",[235,920,922],{"class":921},"sSjpA","A-Z",[235,924,925],{"class":435},"]",[235,927,928],{"class":271},"{2}",[235,930,931],{"class":435},")",[235,933,934],{"class":245},"-",[235,936,937],{"class":435},"(",[235,939,940],{"class":914},"?P\u003CCityCode>",[235,942,918],{"class":435},[235,944,922],{"class":921},[235,946,925],{"class":435},[235,948,949],{"class":271},"{3}",[235,951,931],{"class":435},[235,953,934],{"class":245},[235,955,937],{"class":435},[235,957,958],{"class":914},"?P\u003CStoreNo>",[235,960,961],{"class":435},"\\d",[235,963,964],{"class":271},"{4}",[235,966,967],{"class":435},")$",[235,969,908],{"class":245},[235,971,439],{"class":275},[235,973,974,976,978],{"class":237,"line":285},[235,975,450],{"class":275},[235,977,432],{"class":271},[235,979,980],{"class":275}," df.join(store)\n",[235,982,983,985,988,990,992,994,996,999,1002],{"class":237,"line":292},[235,984,543],{"class":275},[235,986,987],{"class":245},"\"StoreNo\"",[235,989,549],{"class":275},[235,991,432],{"class":271},[235,993,517],{"class":275},[235,995,987],{"class":245},[235,997,998],{"class":275},"].astype(",[235,1000,1001],{"class":245},"\"Int64\"",[235,1003,439],{"class":275},[235,1005,1006,1008,1010,1012,1014,1017,1019,1022,1024,1026],{"class":237,"line":298},[235,1007,581],{"class":435},[235,1009,584],{"class":275},[235,1011,899],{"class":245},[235,1013,310],{"class":275},[235,1015,1016],{"class":245},"\"Country\"",[235,1018,310],{"class":275},[235,1020,1021],{"class":245},"\"CityCode\"",[235,1023,310],{"class":275},[235,1025,987],{"class":245},[235,1027,597],{"class":275},[235,1029,1030],{"class":237,"line":329},[235,1031,289],{"emptyLinePlaceholder":288},[235,1033,1034,1037,1039,1041,1043,1045,1047,1049,1051,1053,1055,1057,1059,1061,1063,1066,1069,1071],{"class":237,"line":357},[235,1035,1036],{"class":275},"bad ",[235,1038,432],{"class":271},[235,1040,517],{"class":275},[235,1042,899],{"class":245},[235,1044,902],{"class":275},[235,1046,905],{"class":271},[235,1048,908],{"class":245},[235,1050,911],{"class":435},[235,1052,915],{"class":914},[235,1054,918],{"class":435},[235,1056,922],{"class":921},[235,1058,925],{"class":435},[235,1060,928],{"class":271},[235,1062,931],{"class":435},[235,1064,1065],{"class":245},"-\"",[235,1067,1068],{"class":275},")[",[235,1070,1016],{"class":245},[235,1072,1073],{"class":275},"].isna()\n",[235,1075,1076,1078,1080,1083,1086,1088],{"class":237,"line":376},[235,1077,581],{"class":435},[235,1079,937],{"class":275},[235,1081,1082],{"class":245},"\"codes that do not match:\"",[235,1084,1085],{"class":275},", df.loc[bad, ",[235,1087,899],{"class":245},[235,1089,1090],{"class":275},"].tolist())\n",[10,1092,1093,1094,1097,1098,1101,1102,1105,1106,1109],{},"The anchors ",[14,1095,1096],{},"^"," and ",[14,1099,1100],{},"$"," make the pattern reject codes that merely contain a valid code somewhere inside them, and the named groups document the structure better than a\ncomment would. ",[14,1103,1104],{},"Int64"," turns the numeric part into a nullable integer, so a non-matching row stays ",[14,1107,1108],{},"\u003CNA>"," instead of forcing the column to float.",[221,1111,1113],{"id":1112},"step-4-handle-inconsistent-delimiters","Step 4 — Handle inconsistent delimiters",[10,1115,1116],{},"Hand-typed lists use whatever separator the person reached for: semicolons, commas, slashes, the word \"and\". A regular expression as the separator covers them all at once.",[226,1118,1120],{"className":262,"code":1119,"language":264,"meta":231,"style":231},"messy = pd.Series([\"red; blue\", \"green\u002Fred\", \"blue , green and red\", \"red\"])\ntags = messy.str.split(r\"\\s*(?:[;,\u002F]|\\band\\b)\\s*\", regex=True)\nprint(tags.tolist())\n# [['red', 'blue'], ['green', 'red'], ['blue', 'green', 'red'], ['red']]\n",[14,1121,1122,1151,1206,1213],{"__ignoreMap":231},[235,1123,1124,1127,1129,1131,1133,1135,1138,1140,1143,1145,1148],{"class":237,"line":238},[235,1125,1126],{"class":275},"messy ",[235,1128,432],{"class":271},[235,1130,750],{"class":275},[235,1132,397],{"class":245},[235,1134,310],{"class":275},[235,1136,1137],{"class":245},"\"green\u002Fred\"",[235,1139,310],{"class":275},[235,1141,1142],{"class":245},"\"blue , green and red\"",[235,1144,310],{"class":275},[235,1146,1147],{"class":245},"\"red\"",[235,1149,1150],{"class":275},"])\n",[235,1152,1153,1156,1158,1161,1163,1165,1168,1171,1174,1177,1179,1182,1185,1188,1191,1193,1195,1197,1200,1202,1204],{"class":237,"line":285},[235,1154,1155],{"class":275},"tags ",[235,1157,432],{"class":271},[235,1159,1160],{"class":275}," messy.str.split(",[235,1162,905],{"class":271},[235,1164,908],{"class":245},[235,1166,1167],{"class":435},"\\s",[235,1169,1170],{"class":271},"*",[235,1172,1173],{"class":435},"(?:[",[235,1175,1176],{"class":921},";,\u002F",[235,1178,925],{"class":435},[235,1180,1181],{"class":271},"|",[235,1183,1184],{"class":435},"\\b",[235,1186,1187],{"class":245},"and",[235,1189,1190],{"class":435},"\\b)\\s",[235,1192,1170],{"class":271},[235,1194,908],{"class":245},[235,1196,310],{"class":275},[235,1198,1199],{"class":428},"regex",[235,1201,432],{"class":271},[235,1203,536],{"class":435},[235,1205,439],{"class":275},[235,1207,1208,1210],{"class":237,"line":292},[235,1209,581],{"class":435},[235,1211,1212],{"class":275},"(tags.tolist())\n",[235,1214,1215],{"class":237,"line":298},[235,1216,1217],{"class":791},"# [['red', 'blue'], ['green', 'red'], ['blue', 'green', 'red'], ['red']]\n",[10,1219,1220,1221,310,1224,1226,1227,1230],{},"Without ",[14,1222,1223],{},"expand=True",[14,1225,797],{}," returns a list per row, which is the right shape when rows hold different numbers of values — the next step turns those lists into rows.\nPassing ",[14,1228,1229],{},"regex=True"," explicitly avoids ambiguity: pandas otherwise treats a separator longer than one character as a regex, and a single character as a literal.",[221,1232,1234],{"id":1233},"step-5-turn-multi-value-cells-into-rows","Step 5 — Turn multi-value cells into rows",[10,1236,1237,1238,1240,1241,1243,1244,1247],{},"A ",[14,1239,124],{}," column with ",[14,1242,203],{}," in one cell is really three facts. Split into lists, then ",[14,1245,1246],{},"explode"," gives each tag its own row with the rest of the record\nrepeated, which is the shape counting, filtering and pivoting need.",[226,1249,1251],{"className":262,"code":1250,"language":264,"meta":231,"style":231},"tag_rows = (\n    df[[\"Customer\", \"Tags\"]]\n      .assign(Tag=df[\"Tags\"].str.split(r\"\\s*;\\s*\", regex=True))\n      .explode(\"Tag\")\n      .query(\"Tag != ''\")\n      .drop(columns=\"Tags\")\n      .reset_index(drop=True)\n)\nprint(tag_rows)\nprint(tag_rows[\"Tag\"].value_counts())\n",[14,1252,1253,1263,1277,1321,1331,1341,1355,1369,1373,1380],{"__ignoreMap":231},[235,1254,1255,1258,1260],{"class":237,"line":238},[235,1256,1257],{"class":275},"tag_rows ",[235,1259,432],{"class":271},[235,1261,1262],{"class":275}," (\n",[235,1264,1265,1268,1270,1272,1274],{"class":237,"line":285},[235,1266,1267],{"class":275},"    df[[",[235,1269,520],{"class":245},[235,1271,310],{"class":275},[235,1273,470],{"class":245},[235,1275,1276],{"class":275},"]]\n",[235,1278,1279,1282,1285,1287,1289,1291,1293,1295,1297,1299,1301,1304,1306,1308,1310,1312,1314,1316,1318],{"class":237,"line":292},[235,1280,1281],{"class":275},"      .assign(",[235,1283,1284],{"class":428},"Tag",[235,1286,432],{"class":271},[235,1288,543],{"class":275},[235,1290,470],{"class":245},[235,1292,523],{"class":275},[235,1294,905],{"class":271},[235,1296,908],{"class":245},[235,1298,1167],{"class":435},[235,1300,1170],{"class":271},[235,1302,1303],{"class":245},";",[235,1305,1167],{"class":435},[235,1307,1170],{"class":271},[235,1309,908],{"class":245},[235,1311,310],{"class":275},[235,1313,1199],{"class":428},[235,1315,432],{"class":271},[235,1317,536],{"class":435},[235,1319,1320],{"class":275},"))\n",[235,1322,1323,1326,1329],{"class":237,"line":298},[235,1324,1325],{"class":275},"      .explode(",[235,1327,1328],{"class":245},"\"Tag\"",[235,1330,439],{"class":275},[235,1332,1333,1336,1339],{"class":237,"line":329},[235,1334,1335],{"class":275},"      .query(",[235,1337,1338],{"class":245},"\"Tag != ''\"",[235,1340,439],{"class":275},[235,1342,1343,1346,1349,1351,1353],{"class":237,"line":357},[235,1344,1345],{"class":275},"      .drop(",[235,1347,1348],{"class":428},"columns",[235,1350,432],{"class":271},[235,1352,470],{"class":245},[235,1354,439],{"class":275},[235,1356,1357,1360,1363,1365,1367],{"class":237,"line":376},[235,1358,1359],{"class":275},"      .reset_index(",[235,1361,1362],{"class":428},"drop",[235,1364,432],{"class":271},[235,1366,536],{"class":435},[235,1368,439],{"class":275},[235,1370,1371],{"class":237,"line":389},[235,1372,439],{"class":275},[235,1374,1375,1377],{"class":237,"line":417},[235,1376,581],{"class":435},[235,1378,1379],{"class":275},"(tag_rows)\n",[235,1381,1382,1384,1387,1389],{"class":237,"line":442},[235,1383,581],{"class":435},[235,1385,1386],{"class":275},"(tag_rows[",[235,1388,1328],{"class":245},[235,1390,1391],{"class":275},"].value_counts())\n",[10,1393,1394,1395,1398,1399,1402,1403,618],{},"The ",[14,1396,1397],{},"query"," removes the empty tag produced by customers with no tags at all. To go the other way — one column per possible tag with a true\u002Ffalse flag — use\n",[14,1400,1401],{},"df[\"Tags\"].str.get_dummies(sep=\"; \")",", which is often the most convenient input for a summary pivot like those in\n",[36,1404,1406],{"href":1405},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcreate-pivot-table-from-excel-with-pandas\u002F","Create a Pivot Table from Excel with Pandas",[42,1408,51,1413,51,1416,51,1419,51,1422,51,1426,51,1431,51,1434,51,1440,51,1445,51,1449,51,1454,51,1457,51,1461,51,1464,51,1467,51,1470,51,1473,51,1477,51,1480,51,1483,51,1488,51,1491],{"viewBox":1409,"role":45,"ariaLabelledBy":1410,"xmlns":49,"style":807},"0 0 760 136",[1411,1412],"spl-explode-t","spl-explode-d",[53,1414,1415],{"id":1411},"From a multi-value cell to one row per value",[57,1417,1418],{"id":1412},"A cell holding blue, green and red separated by semicolons is split into a list, exploded into three rows that repeat the customer, and empty values are filtered out before counting.",[61,1420],{"x":63,"y":63,"width":816,"height":1421,"fill":66},"136",[61,1423],{"x":69,"y":69,"width":96,"height":1424,"rx":1425,"fill":72,"stroke":73,"style":823},"66","12",[80,1427,1430],{"x":1428,"y":103,"style":1429},"95","font-size:14px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","one cell",[80,1432,203],{"x":1428,"y":1433,"style":113},"72",[237,1435],{"x1":1436,"y1":1437,"x2":1438,"y2":1437,"stroke":1439,"style":823},"175","53","204","var(--brand,#5b5cf0)",[1441,1442],"polygon",{"points":1443,"fill":1444},"207,53 198,48 198,58","#5b5cf0",[61,1446],{"x":1447,"y":69,"width":96,"height":1424,"rx":1425,"fill":1448,"stroke":1439,"style":823},"210","#f0f4ff",[80,1450,1453],{"x":1451,"y":103,"style":1452},"285","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","str.split",[80,1455,1456],{"x":1451,"y":1433,"style":136},"a list per row",[237,1458],{"x1":1459,"y1":1437,"x2":1460,"y2":1437,"stroke":1439,"style":823},"365","394",[1441,1462],{"points":1463,"fill":1444},"397,53 388,48 388,58",[61,1465],{"x":1466,"y":69,"width":96,"height":1424,"rx":1425,"fill":1448,"stroke":1439,"style":823},"400",[80,1468,1246],{"x":1469,"y":103,"style":1452},"475",[80,1471,1472],{"x":1469,"y":1433,"style":136},"a row per tag",[237,1474],{"x1":1475,"y1":1437,"x2":1476,"y2":1437,"stroke":1439,"style":823},"555","584",[1441,1478],{"points":1479,"fill":1444},"587,53 578,48 578,58",[61,1481],{"x":1482,"y":69,"width":96,"height":1424,"rx":1425,"fill":848,"stroke":849,"style":823},"590",[80,1484,1487],{"x":1485,"y":103,"style":1486},"665","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","value_counts",[80,1489,1490],{"x":1485,"y":1433,"style":136},"tags counted",[80,1492,1493],{"x":869,"y":78,"style":218},"one fact per row is the shape analysis expects",[221,1495,1497],{"id":1496},"step-6-write-the-split-columns-back-next-to-the-original","Step 6 — Write the split columns back next to the original",[10,1499,1500],{},"When the result goes back to Excel for people, place the new columns beside the source column rather than at the far right, so the sheet reads naturally. Build the\ncolumn order explicitly and write once.",[226,1502,1504],{"className":262,"code":1503,"language":264,"meta":231,"style":231},"order = [\"Customer\", \"LastName\", \"FirstName\", \"Store\", \"Country\", \"CityCode\", \"StoreNo\",\n         \"Address\", \"Street\", \"City\", \"Postcode\", \"Tags\"]\ndf[order].to_excel(\"customers_split.xlsx\", index=False)\nprint(pd.read_excel(\"customers_split.xlsx\").columns.tolist())\n",[14,1505,1506,1544,1568,1586],{"__ignoreMap":231},[235,1507,1508,1511,1513,1516,1518,1520,1522,1524,1526,1528,1530,1532,1534,1536,1538,1540,1542],{"class":237,"line":238},[235,1509,1510],{"class":275},"order ",[235,1512,432],{"class":271},[235,1514,1515],{"class":275}," [",[235,1517,520],{"class":245},[235,1519,310],{"class":275},[235,1521,546],{"class":245},[235,1523,310],{"class":275},[235,1525,566],{"class":245},[235,1527,310],{"class":275},[235,1529,899],{"class":245},[235,1531,310],{"class":275},[235,1533,1016],{"class":245},[235,1535,310],{"class":275},[235,1537,1021],{"class":245},[235,1539,310],{"class":275},[235,1541,987],{"class":245},[235,1543,373],{"class":275},[235,1545,1546,1549,1551,1553,1555,1557,1559,1561,1563,1565],{"class":237,"line":285},[235,1547,1548],{"class":245},"         \"Address\"",[235,1550,310],{"class":275},[235,1552,694],{"class":245},[235,1554,310],{"class":275},[235,1556,699],{"class":245},[235,1558,310],{"class":275},[235,1560,704],{"class":245},[235,1562,310],{"class":275},[235,1564,470],{"class":245},[235,1566,1567],{"class":275},"]\n",[235,1569,1570,1573,1576,1578,1580,1582,1584],{"class":237,"line":292},[235,1571,1572],{"class":275},"df[order].to_excel(",[235,1574,1575],{"class":245},"\"customers_split.xlsx\"",[235,1577,310],{"class":275},[235,1579,429],{"class":428},[235,1581,432],{"class":271},[235,1583,436],{"class":435},[235,1585,439],{"class":275},[235,1587,1588,1590,1593,1595],{"class":237,"line":298},[235,1589,581],{"class":435},[235,1591,1592],{"class":275},"(pd.read_excel(",[235,1594,1575],{"class":245},[235,1596,1597],{"class":275},").columns.tolist())\n",[10,1599,1600,1601,1603,1604,1097,1607,1610],{},"Keeping the original column alongside the parts makes the split auditable: a reviewer can see ",[14,1602,193],{}," next to ",[14,1605,1606],{},"de la Cruz",[14,1608,1609],{},"Ana"," and spot a bad rule at\na glance. Drop it only once the rule has been checked on real data.",[221,1612,1614],{"id":1613},"step-7-check-the-split-with-a-round-trip","Step 7 — Check the split with a round trip",[10,1616,1617],{},"The strongest test of a split rule is that the pieces can rebuild the original. Join the parts with the same delimiter, compare with the normalised source,\nand list every row where they differ. Rows that fail the round trip are exactly the ones the rule does not understand — an extra comma, a missing part,\na delimiter nobody expected.",[226,1619,1621],{"className":262,"code":1620,"language":264,"meta":231,"style":231},"def round_trip_failures(frame: pd.DataFrame, source: str, parts: list[str], sep: str) -> pd.DataFrame:\n    rebuilt = frame[parts].astype(\"string\").fillna(\"\").agg(sep.join, axis=1)\n    normalised = frame[source].astype(\"string\").str.replace(r\"\\s*,\\s*\", sep, regex=True).str.strip()\n    return frame.loc[rebuilt != normalised, [source, *parts]]\n\nprint(round_trip_failures(df, \"Customer\", [\"LastName\", \"FirstName\"], \", \"))\nprint(round_trip_failures(df, \"Address\", [\"Street\", \"City\", \"Postcode\"], \", \"))\n",[14,1622,1623,1650,1680,1724,1743,1747,1772],{"__ignoreMap":231},[235,1624,1625,1628,1632,1635,1637,1640,1642,1645,1647],{"class":237,"line":238},[235,1626,1627],{"class":271},"def",[235,1629,1631],{"class":1630},"s_Opv"," round_trip_failures",[235,1633,1634],{"class":275},"(frame: pd.DataFrame, source: ",[235,1636,476],{"class":435},[235,1638,1639],{"class":275},", parts: list[",[235,1641,476],{"class":435},[235,1643,1644],{"class":275},"], sep: ",[235,1646,476],{"class":435},[235,1648,1649],{"class":275},") -> pd.DataFrame:\n",[235,1651,1652,1655,1657,1660,1663,1666,1668,1671,1674,1676,1678],{"class":237,"line":285},[235,1653,1654],{"class":275},"    rebuilt ",[235,1656,432],{"class":271},[235,1658,1659],{"class":275}," frame[parts].astype(",[235,1661,1662],{"class":245},"\"string\"",[235,1664,1665],{"class":275},").fillna(",[235,1667,412],{"class":245},[235,1669,1670],{"class":275},").agg(sep.join, ",[235,1672,1673],{"class":428},"axis",[235,1675,432],{"class":271},[235,1677,108],{"class":435},[235,1679,439],{"class":275},[235,1681,1682,1685,1687,1690,1692,1695,1697,1699,1701,1703,1706,1708,1710,1712,1715,1717,1719,1721],{"class":237,"line":292},[235,1683,1684],{"class":275},"    normalised ",[235,1686,432],{"class":271},[235,1688,1689],{"class":275}," frame[source].astype(",[235,1691,1662],{"class":245},[235,1693,1694],{"class":275},").str.replace(",[235,1696,905],{"class":271},[235,1698,908],{"class":245},[235,1700,1167],{"class":435},[235,1702,1170],{"class":271},[235,1704,1705],{"class":245},",",[235,1707,1167],{"class":435},[235,1709,1170],{"class":271},[235,1711,908],{"class":245},[235,1713,1714],{"class":275},", sep, ",[235,1716,1199],{"class":428},[235,1718,432],{"class":271},[235,1720,536],{"class":435},[235,1722,1723],{"class":275},").str.strip()\n",[235,1725,1726,1729,1732,1735,1738,1740],{"class":237,"line":298},[235,1727,1728],{"class":271},"    return",[235,1730,1731],{"class":275}," frame.loc[rebuilt ",[235,1733,1734],{"class":271},"!=",[235,1736,1737],{"class":275}," normalised, [source, ",[235,1739,1170],{"class":271},[235,1741,1742],{"class":275},"parts]]\n",[235,1744,1745],{"class":237,"line":329},[235,1746,289],{"emptyLinePlaceholder":288},[235,1748,1749,1751,1754,1756,1759,1761,1763,1765,1768,1770],{"class":237,"line":357},[235,1750,581],{"class":435},[235,1752,1753],{"class":275},"(round_trip_failures(df, ",[235,1755,520],{"class":245},[235,1757,1758],{"class":275},", [",[235,1760,546],{"class":245},[235,1762,310],{"class":275},[235,1764,566],{"class":245},[235,1766,1767],{"class":275},"], ",[235,1769,501],{"class":245},[235,1771,1320],{"class":275},[235,1773,1774,1776,1778,1780,1782,1784,1786,1788,1790,1792,1794,1796],{"class":237,"line":376},[235,1775,581],{"class":435},[235,1777,1753],{"class":275},[235,1779,662],{"class":245},[235,1781,1758],{"class":275},[235,1783,694],{"class":245},[235,1785,310],{"class":275},[235,1787,699],{"class":245},[235,1789,310],{"class":275},[235,1791,704],{"class":245},[235,1793,1767],{"class":275},[235,1795,501],{"class":245},[235,1797,1320],{"class":275},[10,1799,1800,1801,1803],{},"Both checks print empty frames for this data. Run the same check on every new file before trusting the columns: a non-empty result is a short, specific list of rows\nto look at, which is far easier to act on than discovering weeks later that a city column contains postcodes for a few hundred customers. For structured codes, the\nequivalent check is simply counting the missing values that ",[14,1802,881],{}," produced.",[221,1805,1807],{"id":1806},"common-pitfalls","Common pitfalls",[1809,1810,1811,1827],"table",{},[1812,1813,1814],"thead",{},[1815,1816,1817,1821,1824],"tr",{},[1818,1819,1820],"th",{},"Symptom",[1818,1822,1823],{},"Cause",[1818,1825,1826],{},"Fix",[1828,1829,1830,1850,1864,1884,1900,1916],"tbody",{},[1815,1831,1832,1838,1841],{},[1833,1834,1835],"td",{},[14,1836,1837],{},"ValueError: Columns must be same length as key",[1833,1839,1840],{},"Some rows produced extra pieces",[1833,1842,1843,1844,1847,1848],{},"Limit with ",[14,1845,1846],{},"n=",", or use ",[14,1849,640],{},[1815,1851,1852,1855,1858],{},[1833,1853,1854],{},"Leading spaces in split values",[1833,1856,1857],{},"Delimiter followed by inconsistent spacing",[1833,1859,1860,1861],{},"Split on the bare delimiter and ",[14,1862,1863],{},"str.strip()",[1815,1865,1866,1869,1874],{},[1833,1867,1868],{},"Numbers split out as text",[1833,1870,1871,1873],{},[14,1872,797],{}," always returns strings",[1833,1875,1876,1877,1880,1881],{},"Convert with ",[14,1878,1879],{},"astype(\"Int64\")"," or ",[14,1882,1883],{},"pd.to_numeric",[1815,1885,1886,1891,1894],{},[1833,1887,1888],{},[14,1889,1890],{},"AttributeError: Can only use .str accessor with string values",[1833,1892,1893],{},"Column contains numbers or NaN",[1833,1895,1896,1899],{},[14,1897,1898],{},"astype(\"string\")"," first",[1815,1901,1902,1907,1913],{},[1833,1903,1904,1905],{},"Empty strings become rows after ",[14,1906,1246],{},[1833,1908,1909,1910],{},"Blank cells split to ",[14,1911,1912],{},"['']",[1833,1914,1915],{},"Filter empty values after exploding",[1815,1917,1918,1921,1924],{},[1833,1919,1920],{},"Surnames with spaces broken",[1833,1922,1923],{},"Split on spaces instead of the comma",[1833,1925,1926],{},"Split on the true delimiter; use regex groups for names",[221,1928,1930],{"id":1929},"performance-and-scale-notes","Performance and scale notes",[10,1932,1394,1933,1936,1937,1939,1940,1097,1942,1944,1945,1947,1948,1951],{},[14,1934,1935],{},".str"," methods run in Python per element, which is fast enough for hundreds of thousands of rows but noticeably slower than numeric operations. ",[14,1938,1453],{}," with\n",[14,1941,1223],{},[14,1943,881],{}," are comparable; ",[14,1946,1246],{}," is efficient but multiplies the row count, so filter before exploding when you only need some records. For\nvery large string workloads, reading with pandas' Arrow-backed string dtype (",[14,1949,1950],{},"dtype_backend=\"pyarrow\"",") speeds up these operations considerably.",[221,1953,1955],{"id":1954},"conclusion","Conclusion",[10,1957,1958,1959,1962,1963,1965,1966,1968,1969,1971,1972,1974],{},"Replace Text to Columns with ",[14,1960,1961],{},"str.split(..., expand=True)"," and a strip, cap the pieces with ",[14,1964,672],{}," or split from the reliable end with ",[14,1967,640],{},", and describe structured codes\nwith ",[14,1970,881],{}," and named groups so mismatches show up as missing values. Use a regex separator for inconsistent lists, ",[14,1973,1246],{}," multi-value cells into rows, and write the\nparts back beside the original column so the rule can be checked.",[221,1976,1978],{"id":1977},"frequently-asked-questions","Frequently asked questions",[10,1980,1981,1984],{},[31,1982,1983],{},"What is the pandas equivalent of Excel Text to Columns?","\nSeries.str.split(delimiter, expand=True), which returns one column per piece. Assign the result to new column names and strip whitespace from each.",[10,1986,1987,1990],{},[31,1988,1989],{},"How do I split a column only on the first delimiter?","\nPass n=1 to str.split. Everything after the first delimiter stays together in the second column. Use rsplit with n=1 to split on the last delimiter instead.",[10,1992,1993,1996],{},[31,1994,1995],{},"How do I split full names into first and last names?","\nSplit on the delimiter the data actually uses. For Last, First formats split on the comma; for First Last formats, rsplit on a space with n=1 so multi-part first names stay together, and review names with particles by hand.",[10,1998,1999,2002],{},[31,2000,2001],{},"Can I split a column in place with openpyxl instead?","\nYou can, by reading each cell, splitting the string and writing parts into neighbouring cells, but pandas is simpler whenever the whole column follows one rule.",[221,2004,2006],{"id":2005},"related","Related",[2008,2009,2010,2017,2024,2031,2038],"ul",{},[2011,2012,2013,2014,2016],"li",{},"Up one level: ",[36,2015,39],{"href":38}," — the full cleaning workflow.",[2011,2018,2019,2023],{},[36,2020,2022],{"href":2021},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fexcel-text-functions-left-right-mid-and-concat-in-pandas\u002F","Excel Text Functions LEFT, RIGHT, MID and CONCAT in pandas"," — positional text extraction.",[2011,2025,2026,2030],{},[36,2027,2029],{"href":2028},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Funpivot-a-wide-excel-sheet-with-pandas-melt\u002F","Unpivot a Wide Excel Sheet with pandas melt"," — the column-wise cousin of explode.",[2011,2032,2033,2037],{},[36,2034,2036],{"href":2035},"\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"," — typing the pieces you split out.",[2011,2039,2040,2044],{},[36,2041,2043],{"href":2042},"\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"," — matching the names once they are split.",[2046,2047,2048],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sx1sP, html code.shiki .sx1sP{--shiki-default:#22863A;--shiki-dark:#72F088}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":231,"searchDepth":285,"depth":285,"links":2050},[2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063],{"id":223,"depth":285,"text":224},{"id":491,"depth":285,"text":492},{"id":621,"depth":285,"text":622},{"id":874,"depth":285,"text":875},{"id":1112,"depth":285,"text":1113},{"id":1233,"depth":285,"text":1234},{"id":1496,"depth":285,"text":1497},{"id":1613,"depth":285,"text":1614},{"id":1806,"depth":285,"text":1807},{"id":1929,"depth":285,"text":1930},{"id":1954,"depth":285,"text":1955},{"id":1977,"depth":285,"text":1978},{"id":2005,"depth":285,"text":2006},"2026-09-17","The pandas version of Excel's Text to Columns: split names, codes and addresses on a delimiter, cap the number of pieces, extract parts with a regex, and turn multi-value cells into rows.","md",[2068,2070,2072,2074],{"q":1983,"a":2069},"Series.str.split(delimiter, expand=True), which returns one column per piece. Assign the result to new column names and strip whitespace from each.",{"q":1989,"a":2071},"Pass n=1 to str.split. Everything after the first delimiter stays together in the second column. Use rsplit with n=1 to split on the last delimiter instead.",{"q":1995,"a":2073},"Split on the delimiter the data actually uses. For Last, First formats split on the comma; for First Last formats, rsplit on a space with n=1 so multi-part first names stay together, and review names with particles by hand.",{"q":2001,"a":2075},"You can, by reading each cell, splitting the string and writing parts into neighbouring cells, but pandas is simpler whenever the whole column follows one rule.","split a column into multiple columns with pandas",null,{"breadcrumb":2079},[2080,2083,2086],{"name":2081,"item":2082},"Home","\u002F",{"name":2084,"item":2085},"Advanced Data Transformation and Cleaning","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":39,"item":38},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-a-column-into-multiple-columns-with-pandas",{"title":2089,"description":2090},"Split a Column into Multiple Columns with pandas (Text to Columns)","Replace Excel Text to Columns with pandas: str.split with expand and n, rsplit, regex extract with named groups, inconsistent delimiters, multi-value cells with explode, and writing results back.","split-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",[2094,2095],"data-cleaning","pandas","how-to","ze1UxBMBTwx3asYbnNSnviFp-wJxzdSOoCb3TZeeO6g",[2099,2103],{"title":2100,"path":2101,"stem":2102,"children":-1},"Replace Values in an Excel Column with pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freplace-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",{"title":2104,"path":2105,"stem":2106,"children":-1},"Split an Address Column into Street, City and Postcode","\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-an-address-column-into-street-city-and-postcode","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-an-address-column-into-street-city-and-postcode\u002Findex",[2108,2111],{"path":2109,"title":2110},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas","Cleaning Excel Data With Pandas: A Production Workflow",{"path":2112,"title":2113},"\u002Fadvanced-data-transformation-and-cleaning","Advanced Data Transformation and Cleaning for Excel Automation",[],[2116,2119,2122,2125,2128,2131],{"path":2117,"title":2118,"kind":2096},"\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":2120,"title":2121,"kind":2096},"\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":2123,"title":2124,"kind":2096},"\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":2126,"title":2127,"kind":2096},"\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":2129,"title":2130,"kind":2096},"\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":2132,"title":2036,"kind":2096},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fconvert-excel-text-columns-to-numbers-with-pandas",1790972085874]