dropna(how="all")仅删除全为NaN/None的行,不识别空字符串;需先replace({"": pd.NA, " ": pd.NA})统一缺失值,再dropna(how="all")并reset_index。

直接删全空行,用 df.dropna(how="all") 就够了,别碰 how="any" 或漏设参数。
为什么 dropna() 默认不删全空行
默认 dropna() 行为是 how="any":只要某行里有一个 NaN 或 None 就删。但全空行往往每个单元格都是 NaN、空字符串 ""、或空格字符串 " "——而 dropna() **只认 NaN 和 None,不识别空字符串**。所以如果数据里混着 "",光靠 how="all" 也不够。
- 先确认空值类型:
df.isna().sum()看NaN分布,再用df.eq("").sum()检查空字符串 - 若存在
"",得先转成NaN:df.replace("", pd.NA).dropna(how="all") -
how="all"是唯一能精准匹配“整行全为缺失值”的参数;how="any"会误删含部分有效数据的行
dropna(how="all") 的实际行为边界
它只检查参与运算的列。默认对所有列生效,但如果你传了 subset 参数,就只看指定列是否全空——容易误判整行状态。
- 删全空行必须不加
subset,或显式写subset=df.columns.tolist() - 如果 DataFrame 有非数值列(如时间戳、类别型),
dropna()仍能正常识别其NaN,无需额外处理 - 性能上无明显开销,但若 DataFrame 超过百万行,建议先用
df.isna().all(axis=1)测下全空行比例,避免无意义遍历
空格字符串、None、NaN 混合时怎么安全清理
真实数据里这三者常共存,dropna() 对后两者敏感,对前者完全无视——这是最常踩的坑。
- 统一转缺失值:
df = df.replace({"": pd.NA, " ": pd.NA})(注意空格也要单独列) - 再执行:
df.dropna(how="all").reset_index(drop=True)(reset_index避免后续索引跳号) - 别用
df.replace("", np.nan),因为np.nan != np.nan,某些 Pandas 版本下dropna()可能漏识别 - 如果列类型是
string(Pandas 1.0+ 的扩展字符串类型),""本身就算有效值,必须显式替换,不能依赖na_filter
真正麻烦的不是语法,而是搞不清数据里到底藏着多少种“空”:NaN、None、""、" "、" "(全角空格)、甚至 "null" 字符串。每种都得单独点名处理,how="all" 只是最后一道过滤闸门。

















