基于str.contains删除行时如何保留空白单元格所在行?
解决方法
问题根源
你的代码误删空白行,是因为Pandas字符串方法(比如str.endswith/str.contains)碰到空白(NaN)时会返回NaN,布尔索引里NaN会被当成False直接过滤;而你用的na=False参数,会把NaN行直接标记为False,同样会被删掉,完全违背了你要保留空白行的需求。
正确代码实现
核心逻辑:只删那些明确匹配到目标文本的行,空白行全部留着。我们可以把「不匹配目标文本」和「值为NaN」这两个条件用|(或)组合,再把所有过滤条件用&(且)连起来,保证只有所有条件都满足的行才会被保留。
# 逐个定义过滤条件:要么不匹配目标文本,要么是空白行 cond1 = ~DF['CONTRACT TERM SET NAME'].str.endswith("Tier 2", na=False) | DF['CONTRACT TERM SET NAME'].isna() cond2 = ~DF['REBATE TERM SET NAME'].str.endswith("Tier 2", na=False) | DF['REBATE TERM SET NAME'].isna() cond3 = ~DF['REBATE TERM SET NAME'].str.contains(" FOP", na=False) | DF['REBATE TERM SET NAME'].isna() cond4 = ~DF['REBATE TERM SET NAME'].str.contains("Tier 3", na=False) | DF['REBATE TERM SET NAME'].isna() cond5 = ~DF['CONTRACT TERM SET NAME'].str.contains("Healthcare Only", na=False) | DF['CONTRACT TERM SET NAME'].isna() cond6 = ~DF['CONTRACT TERM SET NAME'].str.contains("COCA COLA NORTH AMERICA", na=False) | DF['CONTRACT TERM SET NAME'].isna() # 处理DISTRIBUTOR DIN列: # 如果你是要删单元格内容为"NaN"字符串的行,用下面这行 cond7 = ~DF['DISTRIBUTOR DIN'].str.contains("NaN", na=False) | DF['DISTRIBUTOR DIN'].isna() # 如果你是要删值为NaN的空白行(和你原代码逻辑一致),换成这行 # cond7 = DF['DISTRIBUTOR DIN'].notna() # 把所有条件组合起来,保留符合要求的行 DF = DF[cond1 & cond2 & cond3 & cond4 & cond5 & cond6 & cond7]
更简洁的写法
如果规则多,不想重复写代码,可以把规则打包循环处理:
# 定义所有要检查的列和对应的匹配规则 filter_rules = [ ('CONTRACT TERM SET NAME', lambda x: x.str.endswith("Tier 2")), ('CONTRACT TERM SET NAME', lambda x: x.str.contains("Healthcare Only")), ('CONTRACT TERM SET NAME', lambda x: x.str.contains("COCA COLA NORTH AMERICA")), ('REBATE TERM SET NAME', lambda x: x.str.endswith("Tier 2")), ('REBATE TERM SET NAME', lambda x: x.str.contains(" FOP")), ('REBATE TERM SET NAME', lambda x: x.str.contains("Tier 3")), ] # 初始化总条件为全True total_cond = pd.Series(True, index=DF.index) for col, func in filter_rules: # 每一条规则:要么不匹配,要么是空白行 cond = ~func(DF[col], na=False) | DF[col].isna() total_cond &= cond # 处理DISTRIBUTOR DIN列 total_cond &= ~DF['DISTRIBUTOR DIN'].str.contains("NaN", na=False) | DF['DISTRIBUTOR DIN'].isna() # 要是删的是值为NaN的行,换成:total_cond &= DF['DISTRIBUTOR DIN'].notna() # 应用过滤 DF = DF[total_cond]
关键细节
na=False让字符串方法碰到NaN时返回False,这样~func(...)就变成True,再和isna()的True用|组合,确保空白行不会被过滤。- 所有条件用
&连接,意思是只要有一条规则匹配上(比如某列有"Tier 2"),这行就会被删掉,完全符合你的需求。 - 注意区分「单元格内容是字符串"NaN"」和「单元格值是NaN空白」两种情况,根据你的实际需求选对应的
cond7写法。
内容的提问来源于stack exchange,提问作者BShaifer
相关产品推荐
相关产品推荐

