Pandas 读取CSV时移除每行前导NaN,左移行且保留非前导位置NaN
你之前尝试的代码存在本质逻辑偏差:
df.first_valid_index()是针对整个DataFrame查找第一个非空行的索引位置做行切片,属于行维度的操作,完全没有涉及逐行扫描、移除每行左侧连续前导NaN、将剩余内容左移对齐的列维度处理,自然达不到预期效果。
需求实现方案
核心逻辑:逐行定位每行第一个非NaN值的位置,将该位置及后续所有元素整体左移对齐到行的最左侧,行末尾空出的位置自动补NaN,全程保留元素原有的相对位置,不会删除非前导位置的任何NaN值。
中小规模数据集:逐行apply实现(代码简洁易读)
定义逐行处理的函数,再批量应用到DataFrame上:
import pandas as pd import numpy as np def left_align_row(row): # 定位当前行第一个非NaN值的列名 first_valid_col = row.first_valid_index() # 整行都是NaN的场景直接返回 if first_valid_col is None: return row # 计算左移的偏移量:即当前行开头连续NaN的个数 offset = row.index.get_loc(first_valid_col) # 整体左移offset位,末尾自动补NaN return row.shift(-offset) # 逐行应用处理 df_processed = df.apply(left_align_row, axis=1)
用你提供的示例数据集测试,输出结果和你预期的对齐效果完全一致:
| c1 | c2 | c3 | c4 | c5 | c6 | |
|---|---|---|---|---|---|---|
| 0 | 20.0 | NaN | 250.0 | 250.0 | NaN | NaN |
| 1 | 30.0 | 74.0 | 290.0 | NaN | NaN | NaN |
| 2 | 65.0 | 340.0 | 340.0 | 340.0 | NaN | NaN |
| 3 | 325.0 | 325.0 | NaN | 325.0 | NaN | NaN |
| 4 | 345.0 | 345.0 | 345.0 | 345.0 | NaN | NaN |
| 5 | 17.0 | 74.0 | 315.0 | 315.0 | NaN | NaN |
| 6 | 82.0 | 248.0 | 248.0 | 248.0 | NaN | NaN |
大规模数据集:向量化实现(处理效率更高)
如果读取的CSV行数很多(十万级以上),逐行apply的Python循环效率较低,可以用NumPy的向量化操作批量计算每行的左移偏移量,整体处理速度能提升一个数量级:
# 生成非NaN的布尔掩码 is_not_nan = df.notna().to_numpy() # 逐行计算前导NaN的个数(即需要左移的偏移量) leading_nan_counts = (~is_not_nan).cumprod(axis=1).sum(axis=1) # 逐行执行左移操作 raw_values = df.to_numpy() processed_values = np.array([ np.roll(row, -cnt) if cnt > 0 else row for row, cnt in zip(raw_values, leading_nan_counts) ]) # 还原为带原列名的DataFrame df_processed = pd.DataFrame(processed_values, columns=df.columns)
对接原有CSV读取流程
不需要修改原有的读取代码,把处理逻辑直接接入即可:
response = pd.read_csv(r'MonthlyPermitReport.csv') df_processed = response.apply(left_align_row, axis=1)
内容的提问来源于stack exchange,提问作者Phil_in_Tx
相关产品推荐
相关产品推荐

