多表头DataFrame行过滤与bit单位列删除实现问题求助
嗨,看起来你碰到了pandas多级表头的典型坑——单表头下的逻辑没法直接套用到多级表头上,这太正常了。咱们先搞清楚为啥步骤3和4没法兼容,然后把代码改好让它们都能正常工作。
首先说步骤3的问题:你原来写的data[(data.TMOD1 == 0) & (data.TMOD2 == 0) & ...]在单表头下没问题,但在多级表头里,data.TMOD1返回的是所有第一级列名为TMOD1的列组成的子DataFrame,不是单个列。这时候用==0会得到一个布尔值的DataFrame,直接用&拼接要么维度不匹配报错,要么逻辑根本不符合你要的「所有TMOD列值都为0」的需求。
那怎么正确实现步骤3呢?我们需要明确针对多级表头的第一级列名来筛选,然后检查这些列的每行是否全为0,这里有两种常用的写法:
写法1:用列表推导式筛选目标列
# 先找出所有第一级列名是TMOD1/TMOD2/TMOD3/TMOD4的列 tmod_cols = [col for col in data.columns if col[0] in ['TMOD1', 'TMOD2', 'TMOD3', 'TMOD4']] # 保留这些列全部为0的行(all(axis=1)表示每行的所有目标列都满足条件) data = data[data[tmod_cols].all(axis=1)]
写法2:用pd.IndexSlice更优雅地索引多级列
如果觉得列表推导式不够简洁,可以用pandas提供的IndexSlice来直接切片多级列:
import pandas as pd # 直接选取第一级为目标名称的所有列,然后检查每行是否全为0 data = data[data.loc[:, pd.IndexSlice[['TMOD1', 'TMOD2', 'TMOD3', 'TMOD4'], :]].all(axis=1)]
然后说步骤4:你原来的代码data.drop(labels='bit', axis=1, level=1, inplace=True)本身是对的,但要注意执行顺序。如果你的TMOD列里有单位是bit的,先执行步骤4会把这些列删掉,可能导致步骤3的筛选逻辑缺失数据。建议先执行步骤3筛选行,再执行步骤4删除bit单位的列,这样更符合你的需求逻辑。
最后把步骤2到6的完整代码整合一下,确保逻辑通顺:
# 步骤2:读取CSV为多级表头DataFrame # 注意:CSV行索引从0开始,第2行对应索引1,第3行对应索引2,所以header=[1,2] data = pd.read_csv('your_csv_file.csv', header=[1, 2]) # 步骤3:保留TMOD1-TMOD4列值均为0的行 tmod_cols = [col for col in data.columns if col[0] in ['TMOD1', 'TMOD2', 'TMOD3', 'TMOD4']] data = data[data[tmod_cols].all(axis=1)] # 步骤4:删除所有单位为bit的列(第二级表头为'bit') data.drop(labels='bit', axis=1, level=1, inplace=True) # 步骤5:删除含10个以上NaN值的行 data = data[data.isna().sum(axis=1) <= 10] # 步骤6:追加至result(注意result要先初始化,比如result = pd.DataFrame()) result = pd.concat([result, data], ignore_index=True)
额外提醒一下:
- 确保
pd.read_csv的header参数设置正确,这是生成多级表头的关键,如果你的CSV第一行是无关内容,第2行是参数名,第3行是单位,那header=[1,2]就对了。 - 如果某个TMOD参数对应多个不同单位的列,而你只需要其中某一个单位的列满足0,可以调整列筛选逻辑,比如
col[0] == 'TMOD1' and col[1] == '你的目标单位'。
内容的提问来源于stack exchange,提问作者C. Browne
相关产品推荐
相关产品推荐

