[{"data":1,"prerenderedAt":1950},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-sheet-where-records-run-across-columns":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-sheet-where-records-run-across-columns":1917,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-sheet-where-records-run-across-columns":1926,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-sheet-where-records-run-across-columns":1931,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-sheet-where-records-run-across-columns":1932},{"id":4,"title":5,"body":6,"dateModified":1882,"datePublished":1882,"description":1883,"extension":1884,"faq":1885,"keyword":1894,"kind":1895,"meta":1896,"navigation":380,"path":1905,"seo":1906,"slug":1909,"stem":1910,"topics":1911,"type":1915,"__hash__":1916},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-sheet-where-records-run-across-columns\u002Findex.md","Read an Excel Sheet Where Records Run Across Columns",{"type":7,"value":8,"toc":1867},"minimark",[9,24,310,315,342,348,352,423,433,437,443,529,546,550,556,691,710,806,810,813,1002,1021,1025,1028,1144,1152,1156,1159,1308,1314,1318,1321,1553,1556,1716,1720,1775,1779,1785,1789,1802,1806,1812,1818,1824,1830,1834,1863],[10,11,12,13,17,18,23],"p",{},"Most sheets put one record per row. Some turn it sideways: the field names run down column A — Supplier, Quote date, Unit price, Minimum order — and each record sits in its own column, so three quotes can be compared side by side. It is a perfectly readable layout for people and an awkward one for ",[14,15,16],"code",{},"read_excel",", which assumes the first row holds column names. Read it naively and you get a DataFrame whose \"columns\" are supplier names and whose \"rows\" are fields, with every column a jumble of types. This page, part of ",[19,20,22],"a",{"href":21},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002F","Extracting Data from Messy Excel Sheets",", reads such sheets properly, including two blocks of quotes on one sheet.",[25,26,34,35,34,39,34,43,34,51,34,60,34,64,34,71,34,75,34,79,34,83,34,87,34,91,34,95,34,99,34,104,34,109,34,113,34,115,34,119,34,121,34,124,34,126,34,129,34,132,34,136,34,138,34,141,34,143,34,146,34,148,34,151,34,153,34,156,34,159,34,163,34,165,34,168,34,170,34,173,34,175,34,178,34,180,34,183,34,186,34,190,34,193,34,197,34,200,34,203,34,206,34,208,34,211,34,213,34,215,34,217,34,219,34,221,34,223,34,225,34,227,34,229,34,231,34,233,34,235,34,237,34,239,34,241,34,243,34,245,34,247,34,249,34,251,34,253,34,255,34,258,34,262,34,264,34,266,34,268,34,270,34,272,34,274,34,280,34,284,34,291,34,296,34,304],"svg",{"viewBox":27,"role":28,"ariaLabelledBy":29,"xmlns":32,"style":33},"13 0 734 192","img",[30,31],"tr-swap-t","tr-swap-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:734px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[36,37,38],"title",{"id":30},"A sideways quote sheet turned into one row per supplier",[40,41,42],"desc",{"id":31},"Left: a sheet with field names down column A — supplier, quote date, unit price, minimum order — and one supplier per column: Acme, Globex, Initech. Right: the same data transposed, with one row per supplier and the field names as columns.",[44,45],"rect",{"x":46,"y":47,"width":48,"height":49,"fill":50},"13","0","734","192","#ffffff",[44,52],{"x":53,"y":54,"width":55,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"29.2","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[44,61],{"x":62,"y":54,"width":63,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"61.2","87.6",[65,66,70],"text",{"x":67,"y":68,"style":69},"105.0","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[44,72],{"x":73,"y":54,"width":74,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"148.9","59.8",[65,76,78],{"x":77,"y":68,"style":69},"178.8","B",[44,80],{"x":81,"y":54,"width":82,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"208.7","67.3",[65,84,86],{"x":85,"y":68,"style":69},"242.4","C",[44,88],{"x":89,"y":54,"width":90,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"276.0","66.2",[65,92,94],{"x":93,"y":68,"style":69},"309.1","D",[44,96],{"x":53,"y":97,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"64.0","28.0",[65,100,103],{"x":101,"y":102,"style":69},"45.2","83.0","1",[44,105],{"x":62,"y":97,"width":63,"height":98,"rx":47,"fill":106,"stroke":107,"style":108},"#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[65,110,112],{"x":67,"y":102,"style":111},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Supplier",[44,114],{"x":73,"y":97,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,116,118],{"x":77,"y":102,"style":117},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Acme",[44,120],{"x":81,"y":97,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,122,123],{"x":85,"y":102,"style":117},"Globex",[44,125],{"x":89,"y":97,"width":90,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,127,128],{"x":93,"y":102,"style":117},"Initech",[44,130],{"x":53,"y":131,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"92.0",[65,133,135],{"x":101,"y":134,"style":69},"111.0","2",[44,137],{"x":62,"y":131,"width":63,"height":98,"rx":47,"fill":106,"stroke":107,"style":108},[65,139,140],{"x":67,"y":134,"style":111},"Unit price",[44,142],{"x":73,"y":131,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,144,145],{"x":77,"y":134,"style":117},"2.45",[44,147],{"x":81,"y":131,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,149,150],{"x":85,"y":134,"style":117},"2.60",[44,152],{"x":89,"y":131,"width":90,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,154,155],{"x":93,"y":134,"style":117},"2.38",[44,157],{"x":53,"y":158,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"120.0",[65,160,162],{"x":101,"y":161,"style":69},"139.0","3",[44,164],{"x":62,"y":158,"width":63,"height":98,"rx":47,"fill":106,"stroke":107,"style":108},[65,166,167],{"x":67,"y":161,"style":111},"Min. order",[44,169],{"x":73,"y":158,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,171,172],{"x":77,"y":161,"style":117},"500",[44,174],{"x":81,"y":158,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,176,177],{"x":85,"y":161,"style":117},"250",[44,179],{"x":89,"y":158,"width":90,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,181,182],{"x":93,"y":161,"style":117},"1000",[44,184],{"x":185,"y":54,"width":55,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"452.2",[44,187],{"x":188,"y":54,"width":189,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"484.2","75.4",[65,191,70],{"x":192,"y":68,"style":69},"521.9",[44,194],{"x":195,"y":54,"width":196,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"559.7","83.5",[65,198,78],{"x":199,"y":68,"style":69},"601.4",[44,201],{"x":202,"y":54,"width":63,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"643.1",[65,204,86],{"x":205,"y":68,"style":69},"687.0",[44,207],{"x":185,"y":97,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},[65,209,103],{"x":210,"y":102,"style":69},"468.2",[44,212],{"x":188,"y":97,"width":189,"height":98,"rx":47,"fill":106,"stroke":107,"style":108},[65,214,112],{"x":192,"y":102,"style":111},[44,216],{"x":195,"y":97,"width":196,"height":98,"rx":47,"fill":106,"stroke":107,"style":108},[65,218,140],{"x":199,"y":102,"style":111},[44,220],{"x":202,"y":97,"width":63,"height":98,"rx":47,"fill":106,"stroke":107,"style":108},[65,222,167],{"x":205,"y":102,"style":111},[44,224],{"x":185,"y":131,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},[65,226,135],{"x":210,"y":134,"style":69},[44,228],{"x":188,"y":131,"width":189,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,230,118],{"x":192,"y":134,"style":117},[44,232],{"x":195,"y":131,"width":196,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,234,145],{"x":199,"y":134,"style":117},[44,236],{"x":202,"y":131,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,238,172],{"x":205,"y":134,"style":117},[44,240],{"x":185,"y":158,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},[65,242,162],{"x":210,"y":161,"style":69},[44,244],{"x":188,"y":158,"width":189,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,246,123],{"x":192,"y":161,"style":117},[44,248],{"x":195,"y":158,"width":196,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,250,150],{"x":199,"y":161,"style":117},[44,252],{"x":202,"y":158,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,254,177],{"x":205,"y":161,"style":117},[44,256],{"x":185,"y":257,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"148.0",[65,259,261],{"x":210,"y":260,"style":69},"167.0","4",[44,263],{"x":188,"y":257,"width":189,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,265,128],{"x":192,"y":260,"style":117},[44,267],{"x":195,"y":257,"width":196,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,269,155],{"x":199,"y":260,"style":117},[44,271],{"x":202,"y":257,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,273,182],{"x":205,"y":260,"style":117},[65,275,279],{"x":276,"y":277,"style":278},"185.7","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","as laid out",[65,281,283],{"x":282,"y":277,"style":278},"591.5","one row per record",[285,286],"line",{"x1":287,"y1":288,"x2":289,"y2":288,"stroke":107,"style":290},"352.2","94.0","438.2","stroke-width:2px",[292,293],"polygon",{"points":294,"fill":295},"442.2,94.0 433.2,99.0 433.2,89.0","#5b5cf0",[44,297],{"x":298,"y":299,"width":300,"height":301,"rx":302,"fill":50,"stroke":58,"style":303},"379.9","61.0","34.5","22.0","11","stroke-width:1.2px",[65,305,309],{"x":306,"y":307,"style":308},"397.2","76.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",".T",[311,312,314],"h2",{"id":313},"prerequisites","Prerequisites",[316,317,322],"pre",{"className":318,"code":319,"language":320,"meta":321,"style":321},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[14,323,324],{"__ignoreMap":321},[325,326,328,332,336,339],"span",{"class":285,"line":327},1,[325,329,331],{"class":330},"sMTad","pip",[325,333,335],{"class":334},"srMev"," install",[325,337,338],{"class":334}," pandas",[325,340,341],{"class":334}," openpyxl\n",[10,343,344,347],{},[14,345,346],{},"quotes.xlsx"," holds five supplier quotes in two blocks separated by a blank row: three suppliers in the first block, two in the second. Each block lists supplier, quote date, unit price, minimum order, lead time and certification down column A.",[311,349,351],{"id":350},"step-1-see-the-problem-with-a-normal-read","Step 1 — See the problem with a normal read",[316,353,357],{"className":354,"code":355,"language":356,"meta":321,"style":321},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nnaive = pd.read_excel(\"quotes.xlsx\")\nprint(naive.head(4))\nprint(naive.dtypes.to_dict())\n","python",[14,358,359,375,382,400,415],{"__ignoreMap":321},[325,360,361,365,369,372],{"class":285,"line":327},[325,362,364],{"class":363},"s-kum","import",[325,366,368],{"class":367},"skGVy"," pandas ",[325,370,371],{"class":363},"as",[325,373,374],{"class":367}," pd\n",[325,376,378],{"class":285,"line":377},2,[325,379,381],{"emptyLinePlaceholder":380},true,"\n",[325,383,385,388,391,394,397],{"class":285,"line":384},3,[325,386,387],{"class":367},"naive ",[325,389,390],{"class":363},"=",[325,392,393],{"class":367}," pd.read_excel(",[325,395,396],{"class":334},"\"quotes.xlsx\"",[325,398,399],{"class":367},")\n",[325,401,403,407,410,412],{"class":285,"line":402},4,[325,404,406],{"class":405},"sP0c6","print",[325,408,409],{"class":367},"(naive.head(",[325,411,261],{"class":405},[325,413,414],{"class":367},"))\n",[325,416,418,420],{"class":285,"line":417},5,[325,419,406],{"class":405},[325,421,422],{"class":367},"(naive.dtypes.to_dict())\n",[10,424,425,426,428,429,432],{},"The supplier names have become column headers, \"Quote date\" and \"Unit price\" are values in a column called ",[14,427,112],{},", and every data column is ",[14,430,431],{},"object"," because it mixes dates, prices, counts and yes\u002Fno text. None of the usual operations — filter by price, sort by lead time — can work on this shape.",[311,434,436],{"id":435},"step-2-read-with-the-field-names-as-the-index-then-transpose","Step 2 — Read with the field names as the index, then transpose",[10,438,439,440,442],{},"Tell ",[14,441,16],{}," there is no header row and that column A holds the row labels. Transposing then swaps the axes so each supplier becomes a row:",[316,444,446],{"className":354,"code":445,"language":356,"meta":321,"style":321},"raw = pd.read_excel(\"quotes.xlsx\", header=None, index_col=0, nrows=6)\nquotes = raw.T.reset_index(drop=True)\nquotes.columns.name = None\nprint(quotes)\n",[14,447,448,492,512,522],{"__ignoreMap":321},[325,449,450,453,455,457,459,462,466,468,471,473,476,478,480,482,485,487,490],{"class":285,"line":327},[325,451,452],{"class":367},"raw ",[325,454,390],{"class":363},[325,456,393],{"class":367},[325,458,396],{"class":334},[325,460,461],{"class":367},", ",[325,463,465],{"class":464},"sa561","header",[325,467,390],{"class":363},[325,469,470],{"class":405},"None",[325,472,461],{"class":367},[325,474,475],{"class":464},"index_col",[325,477,390],{"class":363},[325,479,47],{"class":405},[325,481,461],{"class":367},[325,483,484],{"class":464},"nrows",[325,486,390],{"class":363},[325,488,489],{"class":405},"6",[325,491,399],{"class":367},[325,493,494,497,499,502,505,507,510],{"class":285,"line":377},[325,495,496],{"class":367},"quotes ",[325,498,390],{"class":363},[325,500,501],{"class":367}," raw.T.reset_index(",[325,503,504],{"class":464},"drop",[325,506,390],{"class":363},[325,508,509],{"class":405},"True",[325,511,399],{"class":367},[325,513,514,517,519],{"class":285,"line":384},[325,515,516],{"class":367},"quotes.columns.name ",[325,518,390],{"class":363},[325,520,521],{"class":405}," None\n",[325,523,524,526],{"class":285,"line":402},[325,525,406],{"class":405},[325,527,528],{"class":367},"(quotes)\n",[10,530,531,534,535,537,538,541,542,545],{},[14,532,533],{},"nrows=6"," limits the read to the first block for now. After ",[14,536,309],{},", the field names are the columns and each supplier is one row — the tidy layout. ",[14,539,540],{},"reset_index(drop=True)"," replaces the leftover column positions with a clean 0, 1, 2 index, and clearing ",[14,543,544],{},"columns.name"," removes the stray label that transposing leaves behind.",[311,547,549],{"id":548},"step-3-fix-the-column-types","Step 3 — Fix the column types",[10,551,552,553,555],{},"The transposed frame still has the problem from Step 1, turned sideways: every column is ",[14,554,431],{},". Before the transpose, each sheet column mixed a date, a price, an integer and a string, so pandas stored them as Python objects, and those objects are what moved into the new columns:",[316,557,559],{"className":354,"code":558,"language":356,"meta":321,"style":321},"print(quotes.dtypes.to_dict())\n\nquotes = quotes.infer_objects()\nquotes[\"Quote date\"] = pd.to_datetime(quotes[\"Quote date\"])\nfor col in [\"Unit price\", \"Minimum order\", \"Lead time (days)\"]:\n    quotes[col] = pd.to_numeric(quotes[col])\nquotes[\"Certified\"] = quotes[\"Certified\"].map({\"Yes\": True, \"No\": False})\nprint(quotes.dtypes.to_dict())\n",[14,560,561,568,572,581,602,632,643,684],{"__ignoreMap":321},[325,562,563,565],{"class":285,"line":327},[325,564,406],{"class":405},[325,566,567],{"class":367},"(quotes.dtypes.to_dict())\n",[325,569,570],{"class":285,"line":377},[325,571,381],{"emptyLinePlaceholder":380},[325,573,574,576,578],{"class":285,"line":384},[325,575,496],{"class":367},[325,577,390],{"class":363},[325,579,580],{"class":367}," quotes.infer_objects()\n",[325,582,583,586,589,592,594,597,599],{"class":285,"line":402},[325,584,585],{"class":367},"quotes[",[325,587,588],{"class":334},"\"Quote date\"",[325,590,591],{"class":367},"] ",[325,593,390],{"class":363},[325,595,596],{"class":367}," pd.to_datetime(quotes[",[325,598,588],{"class":334},[325,600,601],{"class":367},"])\n",[325,603,604,607,610,613,616,619,621,624,626,629],{"class":285,"line":417},[325,605,606],{"class":363},"for",[325,608,609],{"class":367}," col ",[325,611,612],{"class":363},"in",[325,614,615],{"class":367}," [",[325,617,618],{"class":334},"\"Unit price\"",[325,620,461],{"class":367},[325,622,623],{"class":334},"\"Minimum order\"",[325,625,461],{"class":367},[325,627,628],{"class":334},"\"Lead time (days)\"",[325,630,631],{"class":367},"]:\n",[325,633,635,638,640],{"class":285,"line":634},6,[325,636,637],{"class":367},"    quotes[col] ",[325,639,390],{"class":363},[325,641,642],{"class":367}," pd.to_numeric(quotes[col])\n",[325,644,646,648,651,653,655,658,660,663,666,669,671,673,676,678,681],{"class":285,"line":645},7,[325,647,585],{"class":367},[325,649,650],{"class":334},"\"Certified\"",[325,652,591],{"class":367},[325,654,390],{"class":363},[325,656,657],{"class":367}," quotes[",[325,659,650],{"class":334},[325,661,662],{"class":367},"].map({",[325,664,665],{"class":334},"\"Yes\"",[325,667,668],{"class":367},": ",[325,670,509],{"class":405},[325,672,461],{"class":367},[325,674,675],{"class":334},"\"No\"",[325,677,668],{"class":367},[325,679,680],{"class":405},"False",[325,682,683],{"class":367},"})\n",[325,685,687,689],{"class":285,"line":686},8,[325,688,406],{"class":405},[325,690,567],{"class":367},[10,692,693,696,697,700,701,704,705,709],{},[14,694,695],{},"infer_objects()"," recovers the obvious types; explicit ",[14,698,699],{},"to_numeric"," and ",[14,702,703],{},"to_datetime"," calls make the intended type of each field part of the code rather than a guess, and fail loudly if a quote contains something unexpected. The yes\u002Fno field is mapped to real booleans. ",[19,706,708],{"href":707},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-boolean-columns-from-excel-with-pandas\u002F","Read Yes\u002FNo and TRUE\u002FFALSE Columns as Booleans with pandas"," covers messier flag columns.",[25,711,34,717,34,720,34,723,34,727,34,736,34,747,34,753,34,758,34,761,34,765,34,769,34,773,34,778,34,785,34,790,34,794,34,797,34,800,34,803],{"viewBox":712,"role":28,"ariaLabelledBy":713,"xmlns":32,"style":716},"4 0 752 233",[714,715],"tr-types-t","tr-types-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[36,718,719],{"id":714},"Column types before and after fixing",[40,721,722],{"id":715},"Two panels. Straight after transposing, every column is object, because each original column held a mix of dates, numbers and text. After infer_objects and explicit conversions, quote date is a datetime, unit price a float, minimum order and lead time integers, and certified a boolean.",[44,724],{"x":261,"y":47,"width":725,"height":726,"fill":50},"752","233",[44,728],{"x":729,"y":730,"width":731,"height":732,"rx":733,"fill":734,"stroke":735,"style":290},"20.0","16.0","351.0","201.0","14","#fdefd8","var(--gold,#b4740a)",[737,738,740],"g",{"transform":739},"translate(182.5,29.0) scale(1.083)",[741,742],"path",{"d":743,"fill":744,"stroke":745,"style":746},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","none","var(--gold-ink,#7a4e06)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[65,748,752],{"x":749,"y":750,"style":751},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","After .T",[285,754],{"x1":755,"y1":756,"x2":757,"y2":756,"stroke":735,"style":59},"36.0","91.0","355.0",[65,759,760],{"x":749,"y":134,"style":117},"Quote date: object",[65,762,764],{"x":749,"y":763,"style":117},"137.0","Unit price: object",[65,766,768],{"x":749,"y":767,"style":117},"163.0","Minimum order: object",[65,770,772],{"x":749,"y":771,"style":117},"189.0","Certified: object",[44,774],{"x":775,"y":730,"width":731,"height":732,"rx":733,"fill":776,"stroke":777,"style":290},"389.0","#d9f4f1","var(--teal,#0f9488)",[737,779,781],{"transform":780},"translate(551.5,29.0) scale(1.083)",[741,782],{"d":783,"fill":744,"stroke":784,"style":746},"M5 12.5l4.5 4.5L19 7","var(--teal-ink,#0b6157)",[65,786,789],{"x":787,"y":750,"style":788},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","After converting",[285,791],{"x1":792,"y1":756,"x2":793,"y2":756,"stroke":777,"style":59},"405.0","724.0",[65,795,796],{"x":787,"y":134,"style":117},"Quote date: datetime64",[65,798,799],{"x":787,"y":763,"style":117},"Unit price: float64",[65,801,802],{"x":787,"y":767,"style":117},"Minimum order: int64",[65,804,805],{"x":787,"y":771,"style":117},"Certified: bool",[311,807,809],{"id":808},"step-4-read-several-blocks-from-one-sheet","Step 4 — Read several blocks from one sheet",[10,811,812],{},"The sheet has a second block of quotes below a blank row. Read the whole sheet once without a header, split it at the blank rows, and apply the same transpose to each block:",[316,814,816],{"className":354,"code":815,"language":356,"meta":321,"style":321},"full = pd.read_excel(\"quotes.xlsx\", header=None)\nblank = full.isna().all(axis=1)\nblock_id = blank.cumsum()\n\nblocks = []\nfor _, block in full[~blank].groupby(block_id[~blank]):\n    t = block.set_index(0).T.dropna(how=\"all\").reset_index(drop=True)\n    t.columns.name = None\n    blocks.append(t)\n\nall_quotes = pd.concat(blocks, ignore_index=True).infer_objects()\nprint(all_quotes[[\"Supplier\", \"Unit price\", \"Lead time (days)\"]])\n",[14,817,818,839,858,868,872,882,905,939,948,954,959,980],{"__ignoreMap":321},[325,819,820,823,825,827,829,831,833,835,837],{"class":285,"line":327},[325,821,822],{"class":367},"full ",[325,824,390],{"class":363},[325,826,393],{"class":367},[325,828,396],{"class":334},[325,830,461],{"class":367},[325,832,465],{"class":464},[325,834,390],{"class":363},[325,836,470],{"class":405},[325,838,399],{"class":367},[325,840,841,844,846,849,852,854,856],{"class":285,"line":377},[325,842,843],{"class":367},"blank ",[325,845,390],{"class":363},[325,847,848],{"class":367}," full.isna().all(",[325,850,851],{"class":464},"axis",[325,853,390],{"class":363},[325,855,103],{"class":405},[325,857,399],{"class":367},[325,859,860,863,865],{"class":285,"line":384},[325,861,862],{"class":367},"block_id ",[325,864,390],{"class":363},[325,866,867],{"class":367}," blank.cumsum()\n",[325,869,870],{"class":285,"line":402},[325,871,381],{"emptyLinePlaceholder":380},[325,873,874,877,879],{"class":285,"line":417},[325,875,876],{"class":367},"blocks ",[325,878,390],{"class":363},[325,880,881],{"class":367}," []\n",[325,883,884,886,889,891,894,897,900,902],{"class":285,"line":634},[325,885,606],{"class":363},[325,887,888],{"class":367}," _, block ",[325,890,612],{"class":363},[325,892,893],{"class":367}," full[",[325,895,896],{"class":363},"~",[325,898,899],{"class":367},"blank].groupby(block_id[",[325,901,896],{"class":363},[325,903,904],{"class":367},"blank]):\n",[325,906,907,910,912,915,917,920,923,925,928,931,933,935,937],{"class":285,"line":645},[325,908,909],{"class":367},"    t ",[325,911,390],{"class":363},[325,913,914],{"class":367}," block.set_index(",[325,916,47],{"class":405},[325,918,919],{"class":367},").T.dropna(",[325,921,922],{"class":464},"how",[325,924,390],{"class":363},[325,926,927],{"class":334},"\"all\"",[325,929,930],{"class":367},").reset_index(",[325,932,504],{"class":464},[325,934,390],{"class":363},[325,936,509],{"class":405},[325,938,399],{"class":367},[325,940,941,944,946],{"class":285,"line":686},[325,942,943],{"class":367},"    t.columns.name ",[325,945,390],{"class":363},[325,947,521],{"class":405},[325,949,951],{"class":285,"line":950},9,[325,952,953],{"class":367},"    blocks.append(t)\n",[325,955,957],{"class":285,"line":956},10,[325,958,381],{"emptyLinePlaceholder":380},[325,960,962,965,967,970,973,975,977],{"class":285,"line":961},11,[325,963,964],{"class":367},"all_quotes ",[325,966,390],{"class":363},[325,968,969],{"class":367}," pd.concat(blocks, ",[325,971,972],{"class":464},"ignore_index",[325,974,390],{"class":363},[325,976,509],{"class":405},[325,978,979],{"class":367},").infer_objects()\n",[325,981,983,985,988,991,993,995,997,999],{"class":285,"line":982},12,[325,984,406],{"class":405},[325,986,987],{"class":367},"(all_quotes[[",[325,989,990],{"class":334},"\"Supplier\"",[325,992,461],{"class":367},[325,994,618],{"class":334},[325,996,461],{"class":367},[325,998,628],{"class":334},[325,1000,1001],{"class":367},"]])\n",[10,1003,1004,1007,1008,1011,1012,1015,1016,1020],{},[14,1005,1006],{},"cumsum"," over the blank-row flags numbers the blocks: every blank row starts a new block. ",[14,1009,1010],{},"dropna(how=\"all\")"," after transposing removes the empty columns the second block leaves behind — it only has two suppliers, so its third column is blank. When blocks are not separated by blank rows, split at each row whose first cell repeats the first field name (",[14,1013,1014],{},"full[0] == \"Supplier\"",") instead. ",[19,1017,1019],{"href":1018},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-multiple-tables-from-one-excel-sheet\u002F","Read Multiple Tables from One Excel Sheet"," covers block detection in more depth.",[311,1022,1024],{"id":1023},"step-5-check-the-field-names-are-consistent","Step 5 — Check the field names are consistent",[10,1026,1027],{},"Transposing relies on every block using the same field names in column A. A block with \"Unit Price\" instead of \"Unit price\", or an extra field, produces a new column full of blanks rather than an error. Compare the fields of each block before concatenating:",[316,1029,1031],{"className":354,"code":1030,"language":356,"meta":321,"style":321},"fields = [tuple(b.columns) for b in blocks]\nif len(set(fields)) != 1:\n    raise ValueError(f\"blocks use different fields: {set(fields)}\")\nprint(\"all blocks share\", len(fields[0]), \"fields\")\n",[14,1032,1033,1058,1084,1117],{"__ignoreMap":321},[325,1034,1035,1038,1040,1042,1045,1048,1050,1053,1055],{"class":285,"line":327},[325,1036,1037],{"class":367},"fields ",[325,1039,390],{"class":363},[325,1041,615],{"class":367},[325,1043,1044],{"class":405},"tuple",[325,1046,1047],{"class":367},"(b.columns) ",[325,1049,606],{"class":363},[325,1051,1052],{"class":367}," b ",[325,1054,612],{"class":363},[325,1056,1057],{"class":367}," blocks]\n",[325,1059,1060,1063,1066,1069,1072,1075,1078,1081],{"class":285,"line":377},[325,1061,1062],{"class":363},"if",[325,1064,1065],{"class":405}," len",[325,1067,1068],{"class":367},"(",[325,1070,1071],{"class":405},"set",[325,1073,1074],{"class":367},"(fields)) ",[325,1076,1077],{"class":363},"!=",[325,1079,1080],{"class":405}," 1",[325,1082,1083],{"class":367},":\n",[325,1085,1086,1089,1092,1094,1097,1100,1104,1106,1109,1112,1115],{"class":285,"line":384},[325,1087,1088],{"class":363},"    raise",[325,1090,1091],{"class":405}," ValueError",[325,1093,1068],{"class":367},[325,1095,1096],{"class":363},"f",[325,1098,1099],{"class":334},"\"blocks use different fields: ",[325,1101,1103],{"class":1102},"sSjpA","{",[325,1105,1071],{"class":405},[325,1107,1108],{"class":367},"(fields)",[325,1110,1111],{"class":1102},"}",[325,1113,1114],{"class":334},"\"",[325,1116,399],{"class":367},[325,1118,1119,1121,1123,1126,1128,1131,1134,1136,1139,1142],{"class":285,"line":402},[325,1120,406],{"class":405},[325,1122,1068],{"class":367},[325,1124,1125],{"class":334},"\"all blocks share\"",[325,1127,461],{"class":367},[325,1129,1130],{"class":405},"len",[325,1132,1133],{"class":367},"(fields[",[325,1135,47],{"class":405},[325,1137,1138],{"class":367},"]), ",[325,1140,1141],{"class":334},"\"fields\"",[325,1143,399],{"class":367},[10,1145,1146,1147,1151],{},"For sheets maintained by several people, normalising the field names first — stripping spaces and fixing case, as in ",[19,1148,1150],{"href":1149},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fstandardise-excel-column-names-with-pandas\u002F","Standardise Excel Column Names with pandas"," — removes most of these mismatches before the check.",[311,1153,1155],{"id":1154},"step-6-compare-and-write-the-tidy-table","Step 6 — Compare, and write the tidy table",[10,1157,1158],{},"With one row per quote, the comparison the sheet was built for becomes a sort and a filter — cheapest certified supplier that can deliver within two weeks:",[316,1160,1162],{"className":354,"code":1161,"language":356,"meta":321,"style":321},"all_quotes[\"Unit price\"] = pd.to_numeric(all_quotes[\"Unit price\"])\nall_quotes[\"Lead time (days)\"] = pd.to_numeric(all_quotes[\"Lead time (days)\"])\neligible = all_quotes[(all_quotes[\"Certified\"] == \"Yes\") & (all_quotes[\"Lead time (days)\"] \u003C= 14)]\nprint(eligible.sort_values(\"Unit price\")[[\"Supplier\", \"Unit price\", \"Lead time (days)\"]].to_string(index=False))\n\nall_quotes.to_excel(\"quotes_tidy.xlsx\", index=False)\nprint(pd.read_excel(\"quotes_tidy.xlsx\").shape)\n",[14,1163,1164,1182,1198,1240,1274,1278,1296],{"__ignoreMap":321},[325,1165,1166,1169,1171,1173,1175,1178,1180],{"class":285,"line":327},[325,1167,1168],{"class":367},"all_quotes[",[325,1170,618],{"class":334},[325,1172,591],{"class":367},[325,1174,390],{"class":363},[325,1176,1177],{"class":367}," pd.to_numeric(all_quotes[",[325,1179,618],{"class":334},[325,1181,601],{"class":367},[325,1183,1184,1186,1188,1190,1192,1194,1196],{"class":285,"line":377},[325,1185,1168],{"class":367},[325,1187,628],{"class":334},[325,1189,591],{"class":367},[325,1191,390],{"class":363},[325,1193,1177],{"class":367},[325,1195,628],{"class":334},[325,1197,601],{"class":367},[325,1199,1200,1203,1205,1208,1210,1212,1215,1218,1221,1224,1227,1229,1231,1234,1237],{"class":285,"line":384},[325,1201,1202],{"class":367},"eligible ",[325,1204,390],{"class":363},[325,1206,1207],{"class":367}," all_quotes[(all_quotes[",[325,1209,650],{"class":334},[325,1211,591],{"class":367},[325,1213,1214],{"class":363},"==",[325,1216,1217],{"class":334}," \"Yes\"",[325,1219,1220],{"class":367},") ",[325,1222,1223],{"class":363},"&",[325,1225,1226],{"class":367}," (all_quotes[",[325,1228,628],{"class":334},[325,1230,591],{"class":367},[325,1232,1233],{"class":363},"\u003C=",[325,1235,1236],{"class":405}," 14",[325,1238,1239],{"class":367},")]\n",[325,1241,1242,1244,1247,1249,1252,1254,1256,1258,1260,1262,1265,1268,1270,1272],{"class":285,"line":402},[325,1243,406],{"class":405},[325,1245,1246],{"class":367},"(eligible.sort_values(",[325,1248,618],{"class":334},[325,1250,1251],{"class":367},")[[",[325,1253,990],{"class":334},[325,1255,461],{"class":367},[325,1257,618],{"class":334},[325,1259,461],{"class":367},[325,1261,628],{"class":334},[325,1263,1264],{"class":367},"]].to_string(",[325,1266,1267],{"class":464},"index",[325,1269,390],{"class":363},[325,1271,680],{"class":405},[325,1273,414],{"class":367},[325,1275,1276],{"class":285,"line":417},[325,1277,381],{"emptyLinePlaceholder":380},[325,1279,1280,1283,1286,1288,1290,1292,1294],{"class":285,"line":634},[325,1281,1282],{"class":367},"all_quotes.to_excel(",[325,1284,1285],{"class":334},"\"quotes_tidy.xlsx\"",[325,1287,461],{"class":367},[325,1289,1267],{"class":464},[325,1291,390],{"class":363},[325,1293,680],{"class":405},[325,1295,399],{"class":367},[325,1297,1298,1300,1303,1305],{"class":285,"line":645},[325,1299,406],{"class":405},[325,1301,1302],{"class":367},"(pd.read_excel(",[325,1304,1285],{"class":334},[325,1306,1307],{"class":367},").shape)\n",[10,1309,1310,1311,1313],{},"Acme and Hooli qualify, with Acme the cheaper at 2.45. The tidy file has one row per supplier and one column per field, ready for pivots, merges or a database load; if people still prefer the side-by-side view, it is one ",[14,1312,309],{}," away when writing a presentation sheet.",[311,1315,1317],{"id":1316},"write-the-side-by-side-view-back-for-readers","Write the side-by-side view back for readers",[10,1319,1320],{},"The people who built the sideways layout usually want to keep seeing it. Keep the tidy table as the data, and produce the comparison view from it when writing a presentation sheet — transposing back, with the supplier names as the header row:",[316,1322,1324],{"className":354,"code":1323,"language":356,"meta":321,"style":321},"from openpyxl import load_workbook\nfrom openpyxl.styles import Font\n\nview = all_quotes.set_index(\"Supplier\").T\nview.index.name = \"Field\"\nwith pd.ExcelWriter(\"quotes_tidy.xlsx\", mode=\"a\", engine=\"openpyxl\", if_sheet_exists=\"replace\") as writer:\n    view.to_excel(writer, sheet_name=\"Comparison\")\nwb = load_workbook(\"quotes_tidy.xlsx\")\nws = wb[\"Comparison\"]\nfor cell in ws[1]:\n    cell.font = Font(bold=True)\nws.column_dimensions[\"A\"].width = 18\nwb.save(\"quotes_tidy.xlsx\")\nprint(wb.sheetnames, [c.value for c in ws[1]])\n",[14,1325,1326,1339,1351,1355,1370,1380,1427,1442,1456,1471,1487,1506,1522,1532],{"__ignoreMap":321},[325,1327,1328,1331,1334,1336],{"class":285,"line":327},[325,1329,1330],{"class":363},"from",[325,1332,1333],{"class":367}," openpyxl ",[325,1335,364],{"class":363},[325,1337,1338],{"class":367}," load_workbook\n",[325,1340,1341,1343,1346,1348],{"class":285,"line":377},[325,1342,1330],{"class":363},[325,1344,1345],{"class":367}," openpyxl.styles ",[325,1347,364],{"class":363},[325,1349,1350],{"class":367}," Font\n",[325,1352,1353],{"class":285,"line":384},[325,1354,381],{"emptyLinePlaceholder":380},[325,1356,1357,1360,1362,1365,1367],{"class":285,"line":402},[325,1358,1359],{"class":367},"view ",[325,1361,390],{"class":363},[325,1363,1364],{"class":367}," all_quotes.set_index(",[325,1366,990],{"class":334},[325,1368,1369],{"class":367},").T\n",[325,1371,1372,1375,1377],{"class":285,"line":417},[325,1373,1374],{"class":367},"view.index.name ",[325,1376,390],{"class":363},[325,1378,1379],{"class":334}," \"Field\"\n",[325,1381,1382,1385,1388,1390,1392,1395,1397,1400,1402,1405,1407,1410,1412,1415,1417,1420,1422,1424],{"class":285,"line":634},[325,1383,1384],{"class":363},"with",[325,1386,1387],{"class":367}," pd.ExcelWriter(",[325,1389,1285],{"class":334},[325,1391,461],{"class":367},[325,1393,1394],{"class":464},"mode",[325,1396,390],{"class":363},[325,1398,1399],{"class":334},"\"a\"",[325,1401,461],{"class":367},[325,1403,1404],{"class":464},"engine",[325,1406,390],{"class":363},[325,1408,1409],{"class":334},"\"openpyxl\"",[325,1411,461],{"class":367},[325,1413,1414],{"class":464},"if_sheet_exists",[325,1416,390],{"class":363},[325,1418,1419],{"class":334},"\"replace\"",[325,1421,1220],{"class":367},[325,1423,371],{"class":363},[325,1425,1426],{"class":367}," writer:\n",[325,1428,1429,1432,1435,1437,1440],{"class":285,"line":645},[325,1430,1431],{"class":367},"    view.to_excel(writer, ",[325,1433,1434],{"class":464},"sheet_name",[325,1436,390],{"class":363},[325,1438,1439],{"class":334},"\"Comparison\"",[325,1441,399],{"class":367},[325,1443,1444,1447,1449,1452,1454],{"class":285,"line":686},[325,1445,1446],{"class":367},"wb ",[325,1448,390],{"class":363},[325,1450,1451],{"class":367}," load_workbook(",[325,1453,1285],{"class":334},[325,1455,399],{"class":367},[325,1457,1458,1461,1463,1466,1468],{"class":285,"line":950},[325,1459,1460],{"class":367},"ws ",[325,1462,390],{"class":363},[325,1464,1465],{"class":367}," wb[",[325,1467,1439],{"class":334},[325,1469,1470],{"class":367},"]\n",[325,1472,1473,1475,1478,1480,1483,1485],{"class":285,"line":956},[325,1474,606],{"class":363},[325,1476,1477],{"class":367}," cell ",[325,1479,612],{"class":363},[325,1481,1482],{"class":367}," ws[",[325,1484,103],{"class":405},[325,1486,631],{"class":367},[325,1488,1489,1492,1494,1497,1500,1502,1504],{"class":285,"line":961},[325,1490,1491],{"class":367},"    cell.font ",[325,1493,390],{"class":363},[325,1495,1496],{"class":367}," Font(",[325,1498,1499],{"class":464},"bold",[325,1501,390],{"class":363},[325,1503,509],{"class":405},[325,1505,399],{"class":367},[325,1507,1508,1511,1514,1517,1519],{"class":285,"line":982},[325,1509,1510],{"class":367},"ws.column_dimensions[",[325,1512,1513],{"class":334},"\"A\"",[325,1515,1516],{"class":367},"].width ",[325,1518,390],{"class":363},[325,1520,1521],{"class":405}," 18\n",[325,1523,1525,1528,1530],{"class":285,"line":1524},13,[325,1526,1527],{"class":367},"wb.save(",[325,1529,1285],{"class":334},[325,1531,399],{"class":367},[325,1533,1535,1537,1540,1542,1545,1547,1549,1551],{"class":285,"line":1534},14,[325,1536,406],{"class":405},[325,1538,1539],{"class":367},"(wb.sheetnames, [c.value ",[325,1541,606],{"class":363},[325,1543,1544],{"class":367}," c ",[325,1546,612],{"class":363},[325,1548,1482],{"class":367},[325,1550,103],{"class":405},[325,1552,1001],{"class":367},[10,1554,1555],{},"One source of truth — the tidy sheet — and a view derived from it, so the two can never disagree. Adding a sixth supplier means adding one row to the data; the comparison gains a column automatically on the next run.",[25,1557,34,1562,34,1565,34,1568,34,1571,34,1576,34,1584,34,1590,34,1593,34,1598,34,1603,34,1606,34,1609,34,1615,34,1619,34,1622,34,1625,34,1629,34,1632,34,1635,34,1642,34,1647,34,1650,34,1653,34,1657,34,1660,34,1663,34,1669,34,1675,34,1679,34,1683,34,1687,34,1691,34,1694,34,1697,34,1702,34,1707,34,1710,34,1713],{"viewBox":1558,"role":28,"ariaLabelledBy":1559,"xmlns":32,"style":716},"4 0 752 160",[1560,1561],"tr-pipeline-t","tr-pipeline-d",[36,1563,1564],{"id":1560},"From a sideways sheet to a tidy table",[40,1566,1567],{"id":1561},"Five steps: read the sheet without a header; split into blocks at blank rows; set column A as the index and transpose each block; check that all blocks share the same fields; convert each column to its proper type and concatenate.",[44,1569],{"x":261,"y":47,"width":725,"height":1570,"fill":50},"160",[44,1572],{"x":729,"y":730,"width":1573,"height":1574,"rx":1575,"fill":57,"stroke":58,"style":290},"115.2","128.0","12",[737,1577,1579],{"transform":1578},"translate(65.6,37.8) scale(1.000)",[741,1580],{"d":1581,"fill":744,"stroke":1582,"style":1583},"M6 3h9l4 4v14H6z M15 3v4h4","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[65,1585,1589],{"x":1586,"y":1587,"style":1588},"77.6","84.2","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Read without",[65,1591,465],{"x":1586,"y":1592,"style":1588},"101.8",[65,1594,1597],{"x":1586,"y":1595,"style":1596},"121.2","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","header=None",[285,1599],{"x1":1600,"y1":1601,"x2":1602,"y2":1601,"stroke":107,"style":290},"140.2","80.0","162.2",[292,1604],{"points":1605,"fill":295},"166.2,80.0 157.2,85.0 157.2,75.0",[44,1607],{"x":1608,"y":730,"width":1573,"height":1574,"rx":1575,"fill":57,"stroke":58,"style":290},"171.2",[737,1610,1612],{"transform":1611},"translate(216.8,37.8) scale(1.000)",[741,1613],{"d":1614,"fill":744,"stroke":1582,"style":1583},"M4 12h6 M10 12l6-6h4 M10 12l6 6h4 M17 3l3 3-3 3 M17 15l3 3-3 3",[65,1616,1618],{"x":1617,"y":1587,"style":1588},"228.8","Split into",[65,1620,1621],{"x":1617,"y":1592,"style":1588},"blocks",[65,1623,1624],{"x":1617,"y":1595,"style":1596},"at blank rows",[285,1626],{"x1":1627,"y1":1601,"x2":1628,"y2":1601,"stroke":107,"style":290},"291.4","313.4",[292,1630],{"points":1631,"fill":295},"317.4,80.0 308.4,85.0 308.4,75.0",[44,1633],{"x":1634,"y":730,"width":1573,"height":1574,"rx":1575,"fill":106,"stroke":107,"style":290},"322.4",[737,1636,1638],{"transform":1637},"translate(368.0,37.8) scale(1.000)",[741,1639],{"d":1640,"fill":744,"stroke":1641,"style":1583},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7","var(--brand-strong,#4338ca)",[65,1643,1646],{"x":1644,"y":1587,"style":1645},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Index and",[65,1648,1649],{"x":1644,"y":1592,"style":1645},"transpose",[65,1651,1652],{"x":1644,"y":1595,"style":1596},"set_index(0).T",[285,1654],{"x1":1655,"y1":1601,"x2":1656,"y2":1601,"stroke":107,"style":290},"442.6","464.6",[292,1658],{"points":1659,"fill":295},"468.6,80.0 459.6,85.0 459.6,75.0",[44,1661],{"x":1662,"y":730,"width":1573,"height":1574,"rx":1575,"fill":734,"stroke":735,"style":290},"473.6",[737,1664,1666],{"transform":1665},"translate(519.2,29.0) scale(1.000)",[741,1667],{"d":1668,"fill":744,"stroke":745,"style":1583},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5",[65,1670,1674],{"x":1671,"y":1672,"style":1673},"531.2","75.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Check the",[65,1676,1678],{"x":1671,"y":1677,"style":1673},"93.0","fields",[65,1680,1682],{"x":1671,"y":1681,"style":1596},"112.5","same in every",[65,1684,1686],{"x":1671,"y":1685,"style":1596},"130.0","block",[285,1688],{"x1":1689,"y1":1601,"x2":1690,"y2":1601,"stroke":107,"style":290},"593.8","615.8",[292,1692],{"points":1693,"fill":295},"619.8,80.0 610.8,85.0 610.8,75.0",[44,1695],{"x":1696,"y":730,"width":1573,"height":1574,"rx":1575,"fill":776,"stroke":777,"style":290},"624.8",[737,1698,1700],{"transform":1699},"translate(670.4,29.0) scale(1.000)",[741,1701],{"d":783,"fill":744,"stroke":784,"style":1583},[65,1703,1706],{"x":1704,"y":1672,"style":1705},"682.4","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Fix types and",[65,1708,1709],{"x":1704,"y":1677,"style":1705},"stack",[65,1711,1712],{"x":1704,"y":1681,"style":1596},"to_numeric,",[65,1714,1715],{"x":1704,"y":1685,"style":1596},"concat",[311,1717,1719],{"id":1718},"common-pitfalls","Common pitfalls",[1721,1722,1723,1734,1745,1751,1757,1763,1769],"ul",{},[1724,1725,1726,1730,1731,1733],"li",{},[1727,1728,1729],"strong",{},"Reading with the default header."," The first record's values become column names; use ",[14,1732,1597],{},".",[1724,1735,1736,1741,1742,1744],{},[1727,1737,1738,1739,1733],{},"Trusting types after ",[14,1740,309],{}," Every column is ",[14,1743,431],{},"; convert explicitly.",[1724,1746,1747,1750],{},[1727,1748,1749],{},"Blank columns in short blocks."," Drop all-empty rows after transposing.",[1724,1752,1753,1756],{},[1727,1754,1755],{},"Inconsistent field labels."," Check that blocks share fields before stacking.",[1724,1758,1759,1762],{},[1727,1760,1761],{},"Confusing transpose with melt."," Transpose swaps records and fields; melt turns repeated measures into rows.",[1724,1764,1765,1768],{},[1727,1766,1767],{},"Merged cells in column A."," A field label merged across two rows leaves the second row without a label, and the transpose produces an unnamed column; unmerge and fill the labels first.",[1724,1770,1771,1774],{},[1727,1772,1773],{},"Units in the labels."," Keep \"Lead time (days)\" as the column name, or move the unit into documentation — dropping it leaves a number with no stated unit.",[311,1776,1778],{"id":1777},"performance-notes","Performance notes",[10,1780,1781,1782,1784],{},"Transposing is cheap for sheets of this shape, which are small by nature — dozens of fields, hundreds of records at most. For a very wide sheet with thousands of record columns, read it once with ",[14,1783,1597],{}," and transpose the whole frame before any type conversion, since converting columns is faster than converting rows.",[311,1786,1788],{"id":1787},"conclusion","Conclusion",[10,1790,1791,1792,1795,1796,1798,1799,1801],{},"A sheet with fields down column A and one record per column reads correctly with ",[14,1793,1794],{},"header=None, index_col=0"," followed by ",[14,1797,309],{},". Convert every column to its intended type afterwards, because transposing leaves them all as ",[14,1800,431],{},"; split multi-block sheets at blank rows and transpose each block; check that all blocks use the same fields; and write the tidy one-row-per-record table for everything downstream.",[311,1803,1805],{"id":1804},"frequently-asked-questions","Frequently asked questions",[10,1807,1808,1811],{},[1727,1809,1810],{},"How do I read a sheet where each column is a record?","\nRead it with header=None and index_col=0 so the first column becomes the row labels, then transpose with .T. The field names become columns and each original column becomes a row.",[10,1813,1814,1817],{},[1727,1815,1816],{},"Why are all my columns object dtype after transposing?","\nBefore transposing, each original column mixed values of different fields — a date, a price, a count. pandas stores such a column as object, and the objects survive the transpose. Call infer_objects() and convert specific columns with to_numeric and to_datetime.",[10,1819,1820,1823],{},[1727,1821,1822],{},"What if the sheet has several blocks of records?","\nSplit the sheet at the blank rows between blocks, or at each repetition of the first field name, read each block the same way, and concatenate the results.",[10,1825,1826,1829],{},[1727,1827,1828],{},"Is this the same as unpivoting with melt?","\nNo. melt turns wide columns of the same measure (months, say) into rows. A transposed sheet has records in columns and fields in rows; transposing swaps the two axes so each record becomes one row.",[311,1831,1833],{"id":1832},"related","Related",[1721,1835,1836,1842,1849,1856],{},[1724,1837,1838,1839,1841],{},"Up one level: ",[19,1840,22],{"href":21}," — reading sheets built for people.",[1724,1843,1844,1848],{},[19,1845,1847],{"href":1846},"\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 other kind of \"wide\" sheet.",[1724,1850,1851,1855],{},[19,1852,1854],{"href":1853},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fextract-report-header-fields-from-an-excel-sheet\u002F","Extract Report Header Fields from an Excel Sheet with Python"," — label-and-value pairs at the top of a sheet.",[1724,1857,1858,1862],{},[19,1859,1861],{"href":1860},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fcheck-excel-data-types-with-pandas\u002F","Check Excel Data Types with pandas"," — verifying types after conversion.",[1864,1865,1866],"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 .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":321,"searchDepth":377,"depth":377,"links":1868},[1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881],{"id":313,"depth":377,"text":314},{"id":350,"depth":377,"text":351},{"id":435,"depth":377,"text":436},{"id":548,"depth":377,"text":549},{"id":808,"depth":377,"text":809},{"id":1023,"depth":377,"text":1024},{"id":1154,"depth":377,"text":1155},{"id":1316,"depth":377,"text":1317},{"id":1718,"depth":377,"text":1719},{"id":1777,"depth":377,"text":1778},{"id":1787,"depth":377,"text":1788},{"id":1804,"depth":377,"text":1805},{"id":1832,"depth":377,"text":1833},"2026-09-25","Some sheets are laid out sideways: field names down column A and one record per column — supplier comparisons, product spec sheets, quotes side by side. Read them with header=None and index_col=0, transpose, fix the column types that transposing mixes up, handle several blocks on one sheet, and write the tidy table back.","md",[1886,1888,1890,1892],{"q":1810,"a":1887},"Read it with header=None and index_col=0 so the first column becomes the row labels, then transpose with .T. The field names become columns and each original column becomes a row.",{"q":1816,"a":1889},"Before transposing, each original column mixed values of different fields — a date, a price, a count. pandas stores such a column as object, and the objects survive the transpose. Call infer_objects() and convert specific columns with to_numeric and to_datetime.",{"q":1822,"a":1891},"Split the sheet at the blank rows between blocks, or at each repetition of the first field name, read each block the same way, and concatenate the results.",{"q":1828,"a":1893},"No. melt turns wide columns of the same measure (months, say) into rows. A transposed sheet has records in columns and fields in rows; transposing swaps the two axes so each record becomes one row.","read an excel sheet where records run across columns transposed",null,{"breadcrumb":1897},[1898,1901,1904],{"name":1899,"item":1900},"Home","\u002F",{"name":1902,"item":1903},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":22,"item":21},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-sheet-where-records-run-across-columns",{"title":1907,"description":1908},"Read a Transposed Excel Sheet (Records in Columns) with pandas","Read Excel sheets where each record is a column and field names run down the first column: header=None, index_col=0, transpose with .T, fix object dtypes with infer_objects and to_numeric, dates, blank rows and multiple blocks.","read-a-sheet-where-records-run-across-columns","advanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-sheet-where-records-run-across-columns\u002Findex",[1912,1913,1914],"messy-sheets","reading-excel","pandas","how-to","Cf4RV7Bj82riD5-b9HYJNHJ4Me3TFs-N-Us172G99BU",[1918,1922],{"title":1919,"path":1920,"stem":1921,"children":-1},"Read a Calendar-Style Sheet into a Table","\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-calendar-style-sheet-into-a-table","advanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-a-calendar-style-sheet-into-a-table\u002Findex",{"title":1923,"path":1924,"stem":1925,"children":-1},"Read Cell Colours and Font Styles as Data with openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-cell-colours-and-font-styles-as-data-with-openpyxl","advanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-cell-colours-and-font-styles-as-data-with-openpyxl\u002Findex",[1927,1929],{"path":1928,"title":22},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets",{"path":1930,"title":1902},"\u002Fadvanced-data-transformation-and-cleaning",[],[1933,1936,1939,1942,1945,1948],{"path":1934,"title":1935,"kind":1915},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Ffreeze-header-row-in-excel-with-openpyxl","Freeze the Header Row in Excel with openpyxl",{"path":1937,"title":1938,"kind":1915},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fhandle-merged-cells-when-reading-excel-with-pandas","Handle Merged Cells When Reading Excel with pandas",{"path":1940,"title":1941,"kind":1915},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Funmerge-cells-and-fill-values-with-openpyxl","Unmerge Cells and Fill the Values with openpyxl",{"path":1943,"title":1944,"kind":1915},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fcombine-sheets-with-different-layouts-into-one-table","Combine Sheets with Different Layouts into One Table",{"path":1946,"title":1947,"kind":1915},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fextract-hyperlink-urls-from-excel-cells","Extract Hyperlink URLs from Excel Cells with openpyxl",{"path":1949,"title":1854,"kind":1915},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fextract-report-header-fields-from-an-excel-sheet",1790972090982]