使用 "or" 条件过滤数据帧组
FIltering dataframe groups with "or" condition
我正在处理这样一个数据框:
id Xp_1 Xp_2 Xp_4 Xt_1 Xt_2 Xt_3 Mp_1 Mp_2 Mp_3 Mt_1 Mt_2 Mt_6
0 i24 Nan 0.27 Nan 0.45 0.20 0.25 0.27 Nan Nan Nan Nan Nan
1 i25 0.45 0.47 0.46 0.22 0.42 Nan 0.42 0.05 0.43 0.12 0.01 0.04
2 i11 Nan Nan 0.32 0.14 0.32 0.35 0.29 0.33 Nan Nan 0.02 0.44
3 i47 Nan 0.56 0.59 0.92 Nan 0.56 0.51 0.12 Nan 0.1 0.1 Nan
如您所见,我有两个宏组(X 和 M),每个宏组有两个子集(p 和 t)。我想实现的是两个宏组之间的“或”条件和宏组的每个子集之间的“与”条件。
基本上,我想将每个子集至少有两个值的行保留在至少一个组中。
例如:
i24应该舍弃,实际上我们对Xps只有一个值,而且我们对M组没有任何值。
应该保留i11这样的条目,其实X组不满足条件,M组满足。i25也是一样,两组都满足
我试过这个:
keep_r = (df.groupby(lambda col: col.split("_", maxsplit=1)[0], axis=1)
.count()
.ge(2)
.all(axis=1))
df = df.loc[keep_r]
但它会检查所有子集(Xp、Xt、Mp、Mt)中是否至少有两个值。相反,我想独立对待 X 和 M。
谢谢!
我们可以对两件事进行分组:X
、M
和 p
、t
,它们是列名的第一个和第二个字符。然后我们可以在 p
和 t
的级别上调用您的 .count().ge(2).all(axis=1)
逻辑。然后我们通过 any
:
放置 or 条件
# to keep the `id` column aside
df = df.set_index("id")
# groups
c = df.columns
g = df.groupby([c.str[0], c.str[1]], axis=1)
# boolean mask
mask = (g.count()
.ge(2)
.all(axis=1, level=0) # micros: and
.any(axis=1)) # macros: or
# new df
ndf = df[mask]
得到
>>> ndf
Xp_1 Xp_2 Xp_4 Xt_1 Xt_2 Xt_3 Mp_1 Mp_2 Mp_3 Mt_1 Mt_2 Mt_6
id
i25 0.45 0.47 0.46 0.22 0.42 NaN 0.42 0.05 0.43 0.12 0.01 0.04
i11 NaN NaN 0.32 0.14 0.32 0.35 0.29 0.33 NaN NaN 0.02 0.44
i47 NaN 0.56 0.59 0.92 NaN 0.56 0.51 0.12 NaN 0.1 0.1 NaN
为了说明,在调用 all
和 any
之前,我们有:
>>> g.count().ge(2)
M X
p t p t
id
i24 False False False True
i25 True True True True
i11 True True False True
i47 True True True True
然后 all
超过 0 级,即超过 p, t
使用 和 逻辑减少了这一步:
>>> g.count().ge(2).all(axis=1, level=0)
M X
id
i24 False False
i25 True True
i11 True False
i47 True True
最后 any
对剩余的 M, X
将其简化为具有 或 逻辑的布尔系列,这说明要保留哪些行:
>>> g.count().ge(2).all(axis=1, level=0).any(axis=1)
id
i24 False
i25 True
i11 True
i47 True
dtype: bool
IIUC 尝试创建一个 MultiIndex
from pattern str.extract
:
df = df.set_index('id')
df.columns = pd.MultiIndex.from_frame(df.columns.str.extract('(.)(.)_(.+)'))
0 X M
1 p t p t
2 1 2 4 1 2 3 1 2 3 1 2 6
id
i24 NaN 0.27 NaN 0.45 0.20 0.25 0.27 NaN NaN NaN NaN NaN
i25 0.45 0.47 0.46 0.22 0.42 NaN 0.42 0.05 0.43 0.12 0.01 0.04
i11 NaN NaN 0.32 0.14 0.32 0.35 0.29 0.33 NaN NaN 0.02 0.44
i47 NaN 0.56 0.59 0.92 NaN 0.56 0.51 0.12 NaN 0.10 0.10 NaN
然后按级别 0
和 1
分组进行计数,然后对每个级别应用单独的逻辑。:
keep = (
df.groupby(axis=1, level=[0, 1]).count()
.ge(2).all(axis=1, level=0).any(axis=1)
)
id
i24 False
i25 True
i11 True
i47 True
dtype: bool
然后向下过滤并折叠 MultiIndex:
df = df.loc[keep]
df.columns = df.columns.map(lambda c: f'{"".join(c[:-1])}_{c[-1]}')
df = df.reset_index()
id Xp_1 Xp_2 Xp_4 Xt_1 Xt_2 Xt_3 Mp_1 Mp_2 Mp_3 Mt_1 Mt_2 Mt_6
0 i25 0.45 0.47 0.46 0.22 0.42 NaN 0.42 0.05 0.43 0.12 0.01 0.04
1 i11 NaN NaN 0.32 0.14 0.32 0.35 0.29 0.33 NaN NaN 0.02 0.44
2 i47 NaN 0.56 0.59 0.92 NaN 0.56 0.51 0.12 NaN 0.10 0.10 NaN
我正在处理这样一个数据框:
id Xp_1 Xp_2 Xp_4 Xt_1 Xt_2 Xt_3 Mp_1 Mp_2 Mp_3 Mt_1 Mt_2 Mt_6
0 i24 Nan 0.27 Nan 0.45 0.20 0.25 0.27 Nan Nan Nan Nan Nan
1 i25 0.45 0.47 0.46 0.22 0.42 Nan 0.42 0.05 0.43 0.12 0.01 0.04
2 i11 Nan Nan 0.32 0.14 0.32 0.35 0.29 0.33 Nan Nan 0.02 0.44
3 i47 Nan 0.56 0.59 0.92 Nan 0.56 0.51 0.12 Nan 0.1 0.1 Nan
如您所见,我有两个宏组(X 和 M),每个宏组有两个子集(p 和 t)。我想实现的是两个宏组之间的“或”条件和宏组的每个子集之间的“与”条件。
基本上,我想将每个子集至少有两个值的行保留在至少一个组中。 例如: i24应该舍弃,实际上我们对Xps只有一个值,而且我们对M组没有任何值。 应该保留i11这样的条目,其实X组不满足条件,M组满足。i25也是一样,两组都满足
我试过这个:
keep_r = (df.groupby(lambda col: col.split("_", maxsplit=1)[0], axis=1)
.count()
.ge(2)
.all(axis=1))
df = df.loc[keep_r]
但它会检查所有子集(Xp、Xt、Mp、Mt)中是否至少有两个值。相反,我想独立对待 X 和 M。
谢谢!
我们可以对两件事进行分组:X
、M
和 p
、t
,它们是列名的第一个和第二个字符。然后我们可以在 p
和 t
的级别上调用您的 .count().ge(2).all(axis=1)
逻辑。然后我们通过 any
:
# to keep the `id` column aside
df = df.set_index("id")
# groups
c = df.columns
g = df.groupby([c.str[0], c.str[1]], axis=1)
# boolean mask
mask = (g.count()
.ge(2)
.all(axis=1, level=0) # micros: and
.any(axis=1)) # macros: or
# new df
ndf = df[mask]
得到
>>> ndf
Xp_1 Xp_2 Xp_4 Xt_1 Xt_2 Xt_3 Mp_1 Mp_2 Mp_3 Mt_1 Mt_2 Mt_6
id
i25 0.45 0.47 0.46 0.22 0.42 NaN 0.42 0.05 0.43 0.12 0.01 0.04
i11 NaN NaN 0.32 0.14 0.32 0.35 0.29 0.33 NaN NaN 0.02 0.44
i47 NaN 0.56 0.59 0.92 NaN 0.56 0.51 0.12 NaN 0.1 0.1 NaN
为了说明,在调用 all
和 any
之前,我们有:
>>> g.count().ge(2)
M X
p t p t
id
i24 False False False True
i25 True True True True
i11 True True False True
i47 True True True True
然后 all
超过 0 级,即超过 p, t
使用 和 逻辑减少了这一步:
>>> g.count().ge(2).all(axis=1, level=0)
M X
id
i24 False False
i25 True True
i11 True False
i47 True True
最后 any
对剩余的 M, X
将其简化为具有 或 逻辑的布尔系列,这说明要保留哪些行:
>>> g.count().ge(2).all(axis=1, level=0).any(axis=1)
id
i24 False
i25 True
i11 True
i47 True
dtype: bool
IIUC 尝试创建一个 MultiIndex
from pattern str.extract
:
df = df.set_index('id')
df.columns = pd.MultiIndex.from_frame(df.columns.str.extract('(.)(.)_(.+)'))
0 X M
1 p t p t
2 1 2 4 1 2 3 1 2 3 1 2 6
id
i24 NaN 0.27 NaN 0.45 0.20 0.25 0.27 NaN NaN NaN NaN NaN
i25 0.45 0.47 0.46 0.22 0.42 NaN 0.42 0.05 0.43 0.12 0.01 0.04
i11 NaN NaN 0.32 0.14 0.32 0.35 0.29 0.33 NaN NaN 0.02 0.44
i47 NaN 0.56 0.59 0.92 NaN 0.56 0.51 0.12 NaN 0.10 0.10 NaN
然后按级别 0
和 1
分组进行计数,然后对每个级别应用单独的逻辑。:
keep = (
df.groupby(axis=1, level=[0, 1]).count()
.ge(2).all(axis=1, level=0).any(axis=1)
)
id
i24 False
i25 True
i11 True
i47 True
dtype: bool
然后向下过滤并折叠 MultiIndex:
df = df.loc[keep]
df.columns = df.columns.map(lambda c: f'{"".join(c[:-1])}_{c[-1]}')
df = df.reset_index()
id Xp_1 Xp_2 Xp_4 Xt_1 Xt_2 Xt_3 Mp_1 Mp_2 Mp_3 Mt_1 Mt_2 Mt_6
0 i25 0.45 0.47 0.46 0.22 0.42 NaN 0.42 0.05 0.43 0.12 0.01 0.04
1 i11 NaN NaN 0.32 0.14 0.32 0.35 0.29 0.33 NaN NaN 0.02 0.44
2 i47 NaN 0.56 0.59 0.92 NaN 0.56 0.51 0.12 NaN 0.10 0.10 NaN