在Pandas数据框中删除非等价的Multiindex行

3

目标

如果子列min等于子列max,且minmax子列在任何一列(此例中为ao、his、cyp1a2s、cyp3a4s)中不相等,则删除该行。

示例

arrays = [np.array(['ao', 'ao', 'hia', 'hia', 'cyp1a2s', 'cyp1a2s', 'cyp3a4s', 'cyp3a4s']),
          np.array(['min', 'max', 'min', 'max', 'min', 'max', 'min', 'max'])]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['',''])
df = pd.DataFrame(np.array([[1, 1, 0, 0, float('nan'), float('nan'), 0, 0], 
                            [1, 1, 0, 0, float('nan'), 1, 0, 0],
                            [0, 2, 0, 0, float('nan'), float('nan'), 1, 1],]), index=['1', '2', '3'], columns=index)
df

    ao      hia     cyp1a2s cyp3a4s
    min max min max min max min max
1   1.0 1.0 0.0 0.0 NaN NaN 0.0 0.0
2   1.0 1.0 0.0 0.0 NaN 1.0 0.0 0.0
3   0.0 2.0 0.0 0.0 NaN NaN 1.0 1.0

想要

df = pd.DataFrame(np.array([[1, 1, 0, 0, float('nan'), float('nan'), 0, 0]]), index=['1'], columns=index)
df

    ao      hia     cyp1a2s cyp3a4s
    min max min max min max min max
1   1.0 1.0 0.0 0.0 NaN NaN 0.0 0.0

尝试

df.apply(lambda x: x['min'].map(str) == x['max'].map(str), axis=1)

KeyError: ('min', 'occurred at index 1')

注意

实际的数据框有50多个列。

2个回答

2

使用 DataFrame.xs 方法,针对 MultiIndex 的二级索引来处理 DataFrame,并替换掉其中的 NaN 值:

df1 = df.xs('min', axis=1, level=1).fillna('nan')
df2 = df.xs('max', axis=1, level=1).fillna('nan')

或将数据转换为字符串:

df1 = df.xs('min', axis=1, level=1).astype('str')
df2 = df.xs('max', axis=1, level=1).astype('str')

使用DataFrame.eq比较数据帧,并通过DataFrame.all测试是否全部为True,最后通过boolean indexing进行过滤。请注意保留HTML标记。
df = df[df1.eq(df2).all(axis=1)]
print (df)
    ao       hia      cyp1a2s     cyp3a4s     
   min  max  min  max     min max     min  max
1  1.0  1.0  0.0  0.0     NaN NaN     0.0  0.0

非常感谢您解释了代码(并提供有用的链接)!我想知道为什么 df.apply 在这种情况下不起作用。 - June

1

df.apply()无法工作的原因是您需要引用2个级别的列。

此外,.map(str)对于从float64映射无效...请使用.astype(str)

以下适用于>1列:

eqCols = ['cyp1a2s','hia']
neqCols = list(set(df.xs('min', level=1, axis=1).columns) - set(eqCols))
EQ = lambda r,c : r[c]['min'].astype(str) == r[c]['max'].astype(str)
df[df.apply(lambda r: ([EQ(r,c) for c in eqCols][0]) & ([(not EQ(r,c)) for c in neqCols][0]), axis=1)]

嗨,我有50多列。为每一列重复操作将耗费很多时间。 - June
1
查看最新更改... 分为相等列和不相等列; 最终进行相同数量的比较.. 不确定哪个更快,df.apply() 还是 df.eq()? - frankr6591

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接