You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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)

代码说明

  1. 空值统一处理:把原始数据中的空字符串替换为NaN,确保空值判断的一致性。
  2. 识别轮次块:遍历colA找到每一轮非NaN值的起始位置和长度x,这些块就是每轮填充的起点。
  3. 生成保留掩码:针对每个轮次块,按colA→colB→colC的顺序,计算每列需保留的行范围并标记到掩码中。
  4. 过滤数据:用掩码过滤原始DataFrame,得到只保留目标区域的结果。

这个方案支持任意轮次的循环,且每轮的x值可以不同,完美匹配你描述的填充模式。

内容的提问来源于stack exchange,提问作者A OP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 04:27:37