[{"data":1,"prerenderedAt":1354},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fremove-blank-rows-from-excel-with-pandas":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fremove-blank-rows-from-excel-with-pandas":1346},{"id":4,"title":5,"body":6,"description":1338,"extension":1339,"meta":1340,"navigation":100,"path":1341,"seo":1342,"stem":1344,"__hash__":1345},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fremove-blank-rows-from-excel-with-pandas\u002Findex.md","Remove Blank Rows From Excel With Pandas",{"type":7,"value":8,"toc":1323},"minimark",[9,32,37,65,68,72,292,306,310,329,386,394,398,418,513,519,523,533,623,638,642,652,745,753,757,766,862,868,872,1033,1040,1044,1153,1164,1168,1188,1192,1216,1238,1248,1264,1275,1279,1292,1296,1319],[10,11,12,13,17,18,21,22,25,26,31],"p",{},"To remove blank rows from an Excel file with pandas, load the workbook with ",[14,15,16],"code",{},"pd.read_excel()",", drop the empty rows with ",[14,19,20],{},"df.dropna(how=\"all\")",", reset the index, and write the result back with ",[14,23,24],{},"to_excel()",". The tricky part is defining \"blank\": a fully empty row, a row missing only the columns you care about, and a row full of whitespace strings each need a different call. This page covers all three. It is part of the ",[27,28,30],"a",{"href":29},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002F","Cleaning Excel Data with Pandas"," cluster.",[33,34,36],"h2",{"id":35},"prerequisites","Prerequisites",[38,39,44],"pre",{"className":40,"code":41,"language":42,"meta":43,"style":43},"language-bash shiki shiki-themes github-light github-dark","pip install pandas openpyxl\n","bash","",[14,45,46],{"__ignoreMap":43},[47,48,51,55,59,62],"span",{"class":49,"line":50},"line",1,[47,52,54],{"class":53},"sScJk","pip",[47,56,58],{"class":57},"sZZnC"," install",[47,60,61],{"class":57}," pandas",[47,63,64],{"class":57}," openpyxl\n",[10,66,67],{},"Every block below runs in order against a sample workbook built in the first step.",[33,69,71],{"id":70},"create-a-messy-sample-workbook","Create a messy sample workbook",[38,73,77],{"className":74,"code":75,"language":76,"meta":43,"style":43},"language-python shiki shiki-themes github-light github-dark","import pandas as pd\n\ndf = pd.DataFrame({\n    \"OrderID\": [\"A-100\", None, \"B-200\", \"  \", \"C-300\", None],\n    \"Customer\": [\"Acme\", None, \"Globex\", None, \"Initech\", None],\n    \"Amount\": [120.0, None, 80.0, None, None, None],\n})\ndf.to_excel(\"orders_input.xlsx\", index=False, engine=\"openpyxl\")\nprint(f\"Wrote {len(df)} rows (some blank)\")\n","python",[14,78,79,95,102,114,155,190,224,230,263],{"__ignoreMap":43},[47,80,81,85,89,92],{"class":49,"line":50},[47,82,84],{"class":83},"szBVR","import",[47,86,88],{"class":87},"sVt8B"," pandas ",[47,90,91],{"class":83},"as",[47,93,94],{"class":87}," pd\n",[47,96,98],{"class":49,"line":97},2,[47,99,101],{"emptyLinePlaceholder":100},true,"\n",[47,103,105,108,111],{"class":49,"line":104},3,[47,106,107],{"class":87},"df ",[47,109,110],{"class":83},"=",[47,112,113],{"class":87}," pd.DataFrame({\n",[47,115,117,120,123,126,129,133,135,138,140,143,145,148,150,152],{"class":49,"line":116},4,[47,118,119],{"class":57},"    \"OrderID\"",[47,121,122],{"class":87},": [",[47,124,125],{"class":57},"\"A-100\"",[47,127,128],{"class":87},", ",[47,130,132],{"class":131},"sj4cs","None",[47,134,128],{"class":87},[47,136,137],{"class":57},"\"B-200\"",[47,139,128],{"class":87},[47,141,142],{"class":57},"\"  \"",[47,144,128],{"class":87},[47,146,147],{"class":57},"\"C-300\"",[47,149,128],{"class":87},[47,151,132],{"class":131},[47,153,154],{"class":87},"],\n",[47,156,158,161,163,166,168,170,172,175,177,179,181,184,186,188],{"class":49,"line":157},5,[47,159,160],{"class":57},"    \"Customer\"",[47,162,122],{"class":87},[47,164,165],{"class":57},"\"Acme\"",[47,167,128],{"class":87},[47,169,132],{"class":131},[47,171,128],{"class":87},[47,173,174],{"class":57},"\"Globex\"",[47,176,128],{"class":87},[47,178,132],{"class":131},[47,180,128],{"class":87},[47,182,183],{"class":57},"\"Initech\"",[47,185,128],{"class":87},[47,187,132],{"class":131},[47,189,154],{"class":87},[47,191,193,196,198,201,203,205,207,210,212,214,216,218,220,222],{"class":49,"line":192},6,[47,194,195],{"class":57},"    \"Amount\"",[47,197,122],{"class":87},[47,199,200],{"class":131},"120.0",[47,202,128],{"class":87},[47,204,132],{"class":131},[47,206,128],{"class":87},[47,208,209],{"class":131},"80.0",[47,211,128],{"class":87},[47,213,132],{"class":131},[47,215,128],{"class":87},[47,217,132],{"class":131},[47,219,128],{"class":87},[47,221,132],{"class":131},[47,223,154],{"class":87},[47,225,227],{"class":49,"line":226},7,[47,228,229],{"class":87},"})\n",[47,231,233,236,239,241,245,247,250,252,255,257,260],{"class":49,"line":232},8,[47,234,235],{"class":87},"df.to_excel(",[47,237,238],{"class":57},"\"orders_input.xlsx\"",[47,240,128],{"class":87},[47,242,244],{"class":243},"s4XuR","index",[47,246,110],{"class":83},[47,248,249],{"class":131},"False",[47,251,128],{"class":87},[47,253,254],{"class":243},"engine",[47,256,110],{"class":83},[47,258,259],{"class":57},"\"openpyxl\"",[47,261,262],{"class":87},")\n",[47,264,266,269,272,275,278,281,284,287,290],{"class":49,"line":265},9,[47,267,268],{"class":131},"print",[47,270,271],{"class":87},"(",[47,273,274],{"class":83},"f",[47,276,277],{"class":57},"\"Wrote ",[47,279,280],{"class":131},"{len",[47,282,283],{"class":87},"(df)",[47,285,286],{"class":131},"}",[47,288,289],{"class":57}," rows (some blank)\"",[47,291,262],{"class":87},[10,293,294,295,298,299,301,302,305],{},"Rows 1 and 5 (zero-based) are fully empty. Row 3 has whitespace in ",[14,296,297],{},"OrderID"," but is otherwise empty. Row 4 has an ",[14,300,297],{}," but no ",[14,303,304],{},"Amount",".",[33,307,309],{"id":308},"drop-fully-empty-rows-with-howall","Drop fully empty rows with how=\"all\"",[10,311,312,315,316,320,321,324,325,328],{},[14,313,314],{},"how=\"all\""," removes only rows where ",[317,318,319],"strong",{},"every"," cell is ",[14,322,323],{},"NaN",". This is almost always what you want for blank rows — the default ",[14,326,327],{},"how=\"any\""," would delete any row with a single missing cell, which is far too aggressive.",[38,330,332],{"className":74,"code":331,"language":76,"meta":43,"style":43},"df = pd.read_excel(\"orders_input.xlsx\", engine=\"openpyxl\")\n\ncleaned = df.dropna(how=\"all\")\nprint(cleaned)\n",[14,333,334,355,359,379],{"__ignoreMap":43},[47,335,336,338,340,343,345,347,349,351,353],{"class":49,"line":50},[47,337,107],{"class":87},[47,339,110],{"class":83},[47,341,342],{"class":87}," pd.read_excel(",[47,344,238],{"class":57},[47,346,128],{"class":87},[47,348,254],{"class":243},[47,350,110],{"class":83},[47,352,259],{"class":57},[47,354,262],{"class":87},[47,356,357],{"class":49,"line":97},[47,358,101],{"emptyLinePlaceholder":100},[47,360,361,364,366,369,372,374,377],{"class":49,"line":104},[47,362,363],{"class":87},"cleaned ",[47,365,110],{"class":83},[47,367,368],{"class":87}," df.dropna(",[47,370,371],{"class":243},"how",[47,373,110],{"class":83},[47,375,376],{"class":57},"\"all\"",[47,378,262],{"class":87},[47,380,381,383],{"class":49,"line":116},[47,382,268],{"class":131},[47,384,385],{"class":87},"(cleaned)\n",[10,387,388,389,391,392,305],{},"That drops the two fully empty rows but keeps the whitespace row and the row missing ",[14,390,304],{},", because neither is entirely ",[14,393,323],{},[33,395,397],{"id":396},"convert-whitespace-only-cells-to-nan-first","Convert whitespace-only cells to NaN first",[10,399,400,403,404,406,407,409,410,413,414,417],{},[14,401,402],{},"pd.read_excel"," reads ",[14,405,142],{}," as a literal string, not ",[14,408,323],{},", so a visually blank row survives ",[14,411,412],{},"dropna",". Replace whitespace-only strings with ",[14,415,416],{},"pd.NA"," before dropping:",[38,419,421],{"className":74,"code":420,"language":76,"meta":43,"style":43},"df = pd.read_excel(\"orders_input.xlsx\", engine=\"openpyxl\")\n\ndf = df.replace(r\"^\\s*$\", pd.NA, regex=True)\ncleaned = df.dropna(how=\"all\")\nprint(cleaned)\n",[14,422,423,443,447,491,507],{"__ignoreMap":43},[47,424,425,427,429,431,433,435,437,439,441],{"class":49,"line":50},[47,426,107],{"class":87},[47,428,110],{"class":83},[47,430,342],{"class":87},[47,432,238],{"class":57},[47,434,128],{"class":87},[47,436,254],{"class":243},[47,438,110],{"class":83},[47,440,259],{"class":57},[47,442,262],{"class":87},[47,444,445],{"class":49,"line":97},[47,446,101],{"emptyLinePlaceholder":100},[47,448,449,451,453,456,459,462,465,468,471,473,476,479,481,484,486,489],{"class":49,"line":104},[47,450,107],{"class":87},[47,452,110],{"class":83},[47,454,455],{"class":87}," df.replace(",[47,457,458],{"class":83},"r",[47,460,461],{"class":57},"\"",[47,463,464],{"class":131},"^\\s",[47,466,467],{"class":83},"*",[47,469,470],{"class":131},"$",[47,472,461],{"class":57},[47,474,475],{"class":87},", pd.",[47,477,478],{"class":131},"NA",[47,480,128],{"class":87},[47,482,483],{"class":243},"regex",[47,485,110],{"class":83},[47,487,488],{"class":131},"True",[47,490,262],{"class":87},[47,492,493,495,497,499,501,503,505],{"class":49,"line":116},[47,494,363],{"class":87},[47,496,110],{"class":83},[47,498,368],{"class":87},[47,500,371],{"class":243},[47,502,110],{"class":83},[47,504,376],{"class":57},[47,506,262],{"class":87},[47,508,509,511],{"class":49,"line":157},[47,510,268],{"class":131},[47,512,385],{"class":87},[10,514,515,516,518],{},"Now the whitespace row collapses to all-",[14,517,323],{}," and gets removed. Run this normalization step first whenever data comes from manual entry or a CSV-to-Excel round trip.",[33,520,522],{"id":521},"drop-rows-missing-a-key-field-with-subset","Drop rows missing a key field with subset",[10,524,525,526,528,529,532],{},"To delete rows that lack a specific required column — say every row without an ",[14,527,297],{}," — pass ",[14,530,531],{},"subset",":",[38,534,536],{"className":74,"code":535,"language":76,"meta":43,"style":43},"df = pd.read_excel(\"orders_input.xlsx\", engine=\"openpyxl\")\ndf = df.replace(r\"^\\s*$\", pd.NA, regex=True)\n\ncleaned = df.dropna(subset=[\"OrderID\"])\nprint(cleaned)\n",[14,537,538,558,592,596,617],{"__ignoreMap":43},[47,539,540,542,544,546,548,550,552,554,556],{"class":49,"line":50},[47,541,107],{"class":87},[47,543,110],{"class":83},[47,545,342],{"class":87},[47,547,238],{"class":57},[47,549,128],{"class":87},[47,551,254],{"class":243},[47,553,110],{"class":83},[47,555,259],{"class":57},[47,557,262],{"class":87},[47,559,560,562,564,566,568,570,572,574,576,578,580,582,584,586,588,590],{"class":49,"line":97},[47,561,107],{"class":87},[47,563,110],{"class":83},[47,565,455],{"class":87},[47,567,458],{"class":83},[47,569,461],{"class":57},[47,571,464],{"class":131},[47,573,467],{"class":83},[47,575,470],{"class":131},[47,577,461],{"class":57},[47,579,475],{"class":87},[47,581,478],{"class":131},[47,583,128],{"class":87},[47,585,483],{"class":243},[47,587,110],{"class":83},[47,589,488],{"class":131},[47,591,262],{"class":87},[47,593,594],{"class":49,"line":104},[47,595,101],{"emptyLinePlaceholder":100},[47,597,598,600,602,604,606,608,611,614],{"class":49,"line":116},[47,599,363],{"class":87},[47,601,110],{"class":83},[47,603,368],{"class":87},[47,605,531],{"class":243},[47,607,110],{"class":83},[47,609,610],{"class":87},"[",[47,612,613],{"class":57},"\"OrderID\"",[47,615,616],{"class":87},"])\n",[47,618,619,621],{"class":49,"line":157},[47,620,268],{"class":131},[47,622,385],{"class":87},[10,624,625,626,628,629,631,632,634,635,637],{},"This keeps the row missing only ",[14,627,304],{}," (it still has an ",[14,630,297],{},") while removing every row with no identifier. Combine ",[14,633,531],{}," with ",[14,636,314],{}," by chaining calls when you need both rules.",[33,639,641],{"id":640},"keep-rows-with-at-least-n-real-values-using-thresh","Keep rows with at least N real values using thresh",[10,643,644,647,648,651],{},[14,645,646],{},"thresh=N"," keeps rows that have ",[317,649,650],{},"at least"," N non-null values. Use it when a row is only useful if most of its fields are populated:",[38,653,655],{"className":74,"code":654,"language":76,"meta":43,"style":43},"df = pd.read_excel(\"orders_input.xlsx\", engine=\"openpyxl\")\ndf = df.replace(r\"^\\s*$\", pd.NA, regex=True)\n\n# Keep rows with 2 or more populated cells\ncleaned = df.dropna(thresh=2)\nprint(cleaned)\n",[14,656,657,677,711,715,721,739],{"__ignoreMap":43},[47,658,659,661,663,665,667,669,671,673,675],{"class":49,"line":50},[47,660,107],{"class":87},[47,662,110],{"class":83},[47,664,342],{"class":87},[47,666,238],{"class":57},[47,668,128],{"class":87},[47,670,254],{"class":243},[47,672,110],{"class":83},[47,674,259],{"class":57},[47,676,262],{"class":87},[47,678,679,681,683,685,687,689,691,693,695,697,699,701,703,705,707,709],{"class":49,"line":97},[47,680,107],{"class":87},[47,682,110],{"class":83},[47,684,455],{"class":87},[47,686,458],{"class":83},[47,688,461],{"class":57},[47,690,464],{"class":131},[47,692,467],{"class":83},[47,694,470],{"class":131},[47,696,461],{"class":57},[47,698,475],{"class":87},[47,700,478],{"class":131},[47,702,128],{"class":87},[47,704,483],{"class":243},[47,706,110],{"class":83},[47,708,488],{"class":131},[47,710,262],{"class":87},[47,712,713],{"class":49,"line":104},[47,714,101],{"emptyLinePlaceholder":100},[47,716,717],{"class":49,"line":116},[47,718,720],{"class":719},"sJ8bj","# Keep rows with 2 or more populated cells\n",[47,722,723,725,727,729,732,734,737],{"class":49,"line":157},[47,724,363],{"class":87},[47,726,110],{"class":83},[47,728,368],{"class":87},[47,730,731],{"class":243},"thresh",[47,733,110],{"class":83},[47,735,736],{"class":131},"2",[47,738,262],{"class":87},[47,740,741,743],{"class":49,"line":192},[47,742,268],{"class":131},[47,744,385],{"class":87},[10,746,747,749,750,752],{},[14,748,731],{}," counts non-null cells, so it overrides ",[14,751,371],{}," if both are passed — pick one.",[33,754,756],{"id":755},"reset-the-index-after-dropping","Reset the index after dropping",[10,758,759,761,762,765],{},[14,760,412],{}," preserves the original index, leaving gaps like ",[14,763,764],{},"0, 2, 4",". Those gaps break positional logic and export an odd-looking index. Reset before writing:",[38,767,769],{"className":74,"code":768,"language":76,"meta":43,"style":43},"df = pd.read_excel(\"orders_input.xlsx\", engine=\"openpyxl\")\ndf = df.replace(r\"^\\s*$\", pd.NA, regex=True)\n\ncleaned = df.dropna(how=\"all\").reset_index(drop=True)\nprint(cleaned.index.tolist())\n",[14,770,771,791,825,829,855],{"__ignoreMap":43},[47,772,773,775,777,779,781,783,785,787,789],{"class":49,"line":50},[47,774,107],{"class":87},[47,776,110],{"class":83},[47,778,342],{"class":87},[47,780,238],{"class":57},[47,782,128],{"class":87},[47,784,254],{"class":243},[47,786,110],{"class":83},[47,788,259],{"class":57},[47,790,262],{"class":87},[47,792,793,795,797,799,801,803,805,807,809,811,813,815,817,819,821,823],{"class":49,"line":97},[47,794,107],{"class":87},[47,796,110],{"class":83},[47,798,455],{"class":87},[47,800,458],{"class":83},[47,802,461],{"class":57},[47,804,464],{"class":131},[47,806,467],{"class":83},[47,808,470],{"class":131},[47,810,461],{"class":57},[47,812,475],{"class":87},[47,814,478],{"class":131},[47,816,128],{"class":87},[47,818,483],{"class":243},[47,820,110],{"class":83},[47,822,488],{"class":131},[47,824,262],{"class":87},[47,826,827],{"class":49,"line":104},[47,828,101],{"emptyLinePlaceholder":100},[47,830,831,833,835,837,839,841,843,846,849,851,853],{"class":49,"line":116},[47,832,363],{"class":87},[47,834,110],{"class":83},[47,836,368],{"class":87},[47,838,371],{"class":243},[47,840,110],{"class":83},[47,842,376],{"class":57},[47,844,845],{"class":87},").reset_index(",[47,847,848],{"class":243},"drop",[47,850,110],{"class":83},[47,852,488],{"class":131},[47,854,262],{"class":87},[47,856,857,859],{"class":49,"line":157},[47,858,268],{"class":131},[47,860,861],{"class":87},"(cleaned.index.tolist())\n",[10,863,864,867],{},[14,865,866],{},"drop=True"," discards the old index instead of pushing it into a new column.",[33,869,871],{"id":870},"write-the-cleaned-file-back","Write the cleaned file back",[38,873,875],{"className":74,"code":874,"language":76,"meta":43,"style":43},"df = pd.read_excel(\"orders_input.xlsx\", engine=\"openpyxl\")\ndf = df.replace(r\"^\\s*$\", pd.NA, regex=True)\n\ncleaned = (df.dropna(how=\"all\")\n             .dropna(subset=[\"OrderID\"])\n             .reset_index(drop=True))\n\ncleaned.to_excel(\"orders_cleaned.xlsx\", index=False, engine=\"openpyxl\")\nprint(f\"Wrote {len(cleaned)} rows to orders_cleaned.xlsx\")\n",[14,876,877,897,931,935,952,967,981,985,1011],{"__ignoreMap":43},[47,878,879,881,883,885,887,889,891,893,895],{"class":49,"line":50},[47,880,107],{"class":87},[47,882,110],{"class":83},[47,884,342],{"class":87},[47,886,238],{"class":57},[47,888,128],{"class":87},[47,890,254],{"class":243},[47,892,110],{"class":83},[47,894,259],{"class":57},[47,896,262],{"class":87},[47,898,899,901,903,905,907,909,911,913,915,917,919,921,923,925,927,929],{"class":49,"line":97},[47,900,107],{"class":87},[47,902,110],{"class":83},[47,904,455],{"class":87},[47,906,458],{"class":83},[47,908,461],{"class":57},[47,910,464],{"class":131},[47,912,467],{"class":83},[47,914,470],{"class":131},[47,916,461],{"class":57},[47,918,475],{"class":87},[47,920,478],{"class":131},[47,922,128],{"class":87},[47,924,483],{"class":243},[47,926,110],{"class":83},[47,928,488],{"class":131},[47,930,262],{"class":87},[47,932,933],{"class":49,"line":104},[47,934,101],{"emptyLinePlaceholder":100},[47,936,937,939,941,944,946,948,950],{"class":49,"line":116},[47,938,363],{"class":87},[47,940,110],{"class":83},[47,942,943],{"class":87}," (df.dropna(",[47,945,371],{"class":243},[47,947,110],{"class":83},[47,949,376],{"class":57},[47,951,262],{"class":87},[47,953,954,957,959,961,963,965],{"class":49,"line":157},[47,955,956],{"class":87},"             .dropna(",[47,958,531],{"class":243},[47,960,110],{"class":83},[47,962,610],{"class":87},[47,964,613],{"class":57},[47,966,616],{"class":87},[47,968,969,972,974,976,978],{"class":49,"line":192},[47,970,971],{"class":87},"             .reset_index(",[47,973,848],{"class":243},[47,975,110],{"class":83},[47,977,488],{"class":131},[47,979,980],{"class":87},"))\n",[47,982,983],{"class":49,"line":226},[47,984,101],{"emptyLinePlaceholder":100},[47,986,987,990,993,995,997,999,1001,1003,1005,1007,1009],{"class":49,"line":232},[47,988,989],{"class":87},"cleaned.to_excel(",[47,991,992],{"class":57},"\"orders_cleaned.xlsx\"",[47,994,128],{"class":87},[47,996,244],{"class":243},[47,998,110],{"class":83},[47,1000,249],{"class":131},[47,1002,128],{"class":87},[47,1004,254],{"class":243},[47,1006,110],{"class":83},[47,1008,259],{"class":57},[47,1010,262],{"class":87},[47,1012,1013,1015,1017,1019,1021,1023,1026,1028,1031],{"class":49,"line":265},[47,1014,268],{"class":131},[47,1016,271],{"class":87},[47,1018,274],{"class":83},[47,1020,277],{"class":57},[47,1022,280],{"class":131},[47,1024,1025],{"class":87},"(cleaned)",[47,1027,286],{"class":131},[47,1029,1030],{"class":57}," rows to orders_cleaned.xlsx\"",[47,1032,262],{"class":87},[10,1034,1035,1036,1039],{},"Pass ",[14,1037,1038],{},"index=False"," so the reset index does not become a stray first column in the output.",[33,1041,1043],{"id":1042},"common-pitfalls","Common pitfalls",[1045,1046,1047,1063],"table",{},[1048,1049,1050],"thead",{},[1051,1052,1053,1057,1060],"tr",{},[1054,1055,1056],"th",{},"Symptom",[1054,1058,1059],{},"Cause",[1054,1061,1062],{},"Fix",[1064,1065,1066,1087,1105,1124,1137],"tbody",{},[1051,1067,1068,1072,1078],{},[1069,1070,1071],"td",{},"Real data rows disappear",[1069,1073,1074,1075,1077],{},"Default ",[14,1076,327],{}," drops any row with one missing cell",[1069,1079,1080,1081,1083,1084],{},"Use ",[14,1082,314],{}," or ",[14,1085,1086],{},"subset=[...]",[1051,1088,1089,1092,1099],{},[1069,1090,1091],{},"Visually blank rows survive",[1069,1093,1094,1096,1097],{},[14,1095,142],{}," is a string, not ",[14,1098,323],{},[1069,1100,1101,1104],{},[14,1102,1103],{},"df.replace(r\"^\\s*$\", pd.NA, regex=True)"," first",[1051,1106,1107,1114,1119],{},[1069,1108,1109,1110,1113],{},"Index reads ",[14,1111,1112],{},"0, 3, 7"," after drop",[1069,1115,1116,1118],{},[14,1117,412],{}," keeps the original index",[1069,1120,1121],{},[14,1122,1123],{},".reset_index(drop=True)",[1051,1125,1126,1129,1132],{},[1069,1127,1128],{},"Extra unnamed column in output",[1069,1130,1131],{},"Reset index written to file",[1069,1133,1134],{},[14,1135,1136],{},"to_excel(..., index=False)",[1051,1138,1139,1142,1145],{},[1069,1140,1141],{},"First data rows are blank\u002Fgarbled",[1069,1143,1144],{},"A multi-row header was read as data",[1069,1146,1147,1083,1150],{},[14,1148,1149],{},"pd.read_excel(..., header=[0, 1])",[14,1151,1152],{},"skiprows=N",[10,1154,1155,1156,1159,1160,1163],{},"The multi-row-header case is common with exported reports: a banner or merged title row above the real header makes pandas read junk rows. Use ",[14,1157,1158],{},"skiprows"," to skip the banner, or ",[14,1161,1162],{},"header=[0, 1]"," for a genuine two-level header, rather than dropping the rows afterward.",[33,1165,1167],{"id":1166},"performance-and-scale-note","Performance and scale note",[10,1169,1170,1172,1173,1176,1177,1179,1180,1183,1184,1187],{},[14,1171,412],{}," and ",[14,1174,1175],{},"replace"," run vectorized in C, so even files with hundreds of thousands of rows clean in well under a second. The regex ",[14,1178,1175],{}," is the slower of the two; if you only need to strip whitespace from one or two known string columns, target them directly with ",[14,1181,1182],{},"df[col] = df[col].str.strip().replace(\"\", pd.NA)"," instead of scanning the whole frame. For very large workbooks, read only the columns you need with ",[14,1185,1186],{},"usecols="," to cut memory before cleaning.",[33,1189,1191],{"id":1190},"frequently-asked-questions","Frequently asked questions",[10,1193,1194,1202,1203,1205,1206,1208,1209,1213,1214,305],{},[317,1195,1196,1197,1172,1199,1201],{},"What is the difference between ",[14,1198,314],{},[14,1200,327],{},"?"," ",[14,1204,314],{}," drops a row only when every cell is missing; ",[14,1207,327],{}," (the default) drops a row when ",[1210,1211,1212],"em",{},"any"," cell is missing. For removing blank rows you almost always want ",[14,1215,314],{},[10,1217,1218,1223,1224,1226,1227,1229,1230,1232,1233,1235,1236,305],{},[317,1219,1220,1221,1201],{},"Why do my whitespace-only rows survive ",[14,1222,412],{}," Because ",[14,1225,142],{}," is a non-null string. pandas only treats true ",[14,1228,323],{},"\u002F",[14,1231,132],{}," as missing. Run ",[14,1234,1103],{}," first to convert blank strings to ",[14,1237,323],{},[10,1239,1240,1243,1244,1247],{},[317,1241,1242],{},"How do I drop rows that are missing only certain columns?"," Use ",[14,1245,1246],{},"df.dropna(subset=[\"OrderID\", \"Customer\"])",". The row is dropped only if a value in one of the listed columns is missing.",[10,1249,1250,1256,1257,1260,1261,305],{},[317,1251,1252,1253,1255],{},"Does ",[14,1254,412],{}," modify the DataFrame in place?"," No, it returns a new DataFrame by default. Reassign the result (",[14,1258,1259],{},"df = df.dropna(...)",") or pass ",[14,1262,1263],{},"inplace=True",[10,1265,1266,1202,1269,1271,1272,1274],{},[317,1267,1268],{},"Why does my cleaned index have gaps?",[14,1270,412],{}," keeps original index labels. Call ",[14,1273,1123],{}," to renumber from zero.",[33,1276,1278],{"id":1277},"conclusion","Conclusion",[10,1280,1281,1282,1284,1285,1229,1287,1229,1289,1291],{},"Removing blank rows reliably is three steps: normalize whitespace to ",[14,1283,323],{},", drop with the right ",[14,1286,371],{},[14,1288,531],{},[14,1290,731],{}," rule, then reset the index before writing. Skipping the normalization step is the single most common reason \"empty\" rows survive.",[33,1293,1295],{"id":1294},"where-to-go-next","Where to go next",[1297,1298,1299,1305,1312],"ul",{},[1300,1301,1302,1304],"li",{},[27,1303,30],{"href":29}," — the parent cluster.",[1300,1306,1307,1311],{},[27,1308,1310],{"href":1309},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fpandas-drop-duplicates-from-excel-column\u002F","Pandas: Drop Duplicates From an Excel Column"," — remove repeated rows after dropping blanks.",[1300,1313,1314,1318],{},[27,1315,1317],{"href":1316},"\u002Fadvanced-data-transformation-and-cleaning\u002Fhandling-missing-data-in-excel-reports\u002F","Handling Missing Data in Excel Reports"," — fill, flag, or impute the gaps you keep.",[1320,1321,1322],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":43,"searchDepth":97,"depth":97,"links":1324},[1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337],{"id":35,"depth":97,"text":36},{"id":70,"depth":97,"text":71},{"id":308,"depth":97,"text":309},{"id":396,"depth":97,"text":397},{"id":521,"depth":97,"text":522},{"id":640,"depth":97,"text":641},{"id":755,"depth":97,"text":756},{"id":870,"depth":97,"text":871},{"id":1042,"depth":97,"text":1043},{"id":1166,"depth":97,"text":1167},{"id":1190,"depth":97,"text":1191},{"id":1277,"depth":97,"text":1278},{"id":1294,"depth":97,"text":1295},"Strip blank rows from an Excel file with pandas: dropna(how='all'), subset and thresh, whitespace-only cells, index resets, and writing the cleaned file back.","md",{},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fremove-blank-rows-from-excel-with-pandas",{"title":5,"description":1343},"Delete empty Excel rows with pandas dropna: how='all', subset, thresh, whitespace-only cells, reset_index, and a clean write-back. Runnable examples included.","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fremove-blank-rows-from-excel-with-pandas\u002Findex","dvewFxH2f5XDlB-SDyYLJ29Dzo0dnnZyx80yahlBsQs",[1347,1350],{"title":1310,"path":1348,"stem":1349,"children":-1},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fpandas-drop-duplicates-from-excel-column","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fpandas-drop-duplicates-from-excel-column\u002Findex",{"title":1351,"path":1352,"stem":1353,"children":-1},"Creating Pivot Tables from Excel Data with Pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data","advanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Findex",1781773160996]