如何在Pandas中按DataFrame的NaN模式保留指定NaN值并删除其余值
解决方案
思路分析
你的DataFrame遵循循环分块填充模式:每轮从colA开始,先有x个非空值,随后colB的x行、colC的x行依次为需保留的填充区域(含NaN),完成一轮后回到colA开启下一轮。我们可以通过识别每轮的起始位置和x值,生成保留掩码来过滤目标行。
代码实现
import pandas as pd import numpy as np # 初始化原始DataFrame df = pd.DataFrame(data={ 'colA': ['A','B','C','','','','','','','W','X','Y','Z','','','','','','','',''], 'colB': ['','','',1,'',2,'','','','','','','',3,'','',4,'','','',''], 'colC': ['','','','','','','a','b','c','','','','','','','','','d','e','f',''] }) # 将空字符串统一替换为NaN,方便空值判断 df = df.replace('', np.nan) # 识别colA中连续非NaN的块(每轮的起始位置和长度x) colA_non_nan = df['colA'].notna() blocks = [] current_start = None for idx, is_non_nan in enumerate(colA_non_nan): if is_non_nan and current_start is None: current_start = idx elif not is_non_nan and current_start is not None: blocks.append((current_start, idx - current_start)) current_start = None # 处理最后一个未闭合的块 if current_start is not None: blocks.append((current_start, len(df) - current_start)) # 定义列的循环顺序 cols = ['colA', 'colB', 'colC'] n_cols = len(cols) # 生成保留行的掩码 keep_mask = pd.Series([False]*len(df), index=df.index) for start, x in blocks: for col_idx, col in enumerate(cols): # 计算当前列需保留的行范围 keep_start = start + col_idx * x keep_end = start + (col_idx + 1) * x keep_end = min(keep_end, len(df)) # 避免超出DataFrame行数 # 标记需保留的行 keep_mask.loc[keep_start:keep_end-1] = True # 过滤得到目标DataFrame result_df = df[keep_mask].reset_index(drop=True) print(result_df)
代码说明
- 空值统一处理:把原始数据中的空字符串替换为
NaN,确保空值判断的一致性。 - 识别轮次块:遍历
colA找到每一轮非NaN值的起始位置和长度x,这些块就是每轮填充的起点。 - 生成保留掩码:针对每个轮次块,按
colA→colB→colC的顺序,计算每列需保留的行范围并标记到掩码中。 - 过滤数据:用掩码过滤原始DataFrame,得到只保留目标区域的结果。
这个方案支持任意轮次的循环,且每轮的x值可以不同,完美匹配你描述的填充模式。
内容的提问来源于stack exchange,提问作者A OP
相关产品推荐
相关产品推荐

