为了账号安全,请及时绑定邮箱和手机立即绑定

平衡具有特定对的行数

平衡具有特定对的行数

拉丁的传说 2023-10-18 15:56:46
所以,我有一个 pandas 数据框,看起来像这样:  data  |  Flag  |  Set-----------------------------  0     |  True  |  A  30    |  True  |  A  -1    |  False |  A  20    |  True  |  B  5     |  False |  B  19    |  False |  B  7     |  False |  C  8     |  False |  c我怎样才能(优雅地)以这样的方式删除行,使得对于每组,都有相同数量的True和False Flags?输出看起来像这样  data  |  Flag  |  Set-----------------------------  0     |  True  |  A  -1    |  False |  A  20    |  True  |  B  5     |  False |  B对于A,有 1 个假标志,因为B有 1 个真标志,并且C有 0 个真标志。我知道如何暴力破解,但我觉得有一些我不知道的优雅方法。
查看完整描述

3 回答

?
慕村225694

TA贡献1880条经验 获得超4个赞

首先获取Flag每个Setby的计数crosstab,过滤掉行0- 它意味着唯一TrueFalse值,并获取字典的最小值d

df1 = pd.crosstab(df['Set'], df['Flag'])

d = df1[df1.ne(0).all(axis=1)].min(axis=1).to_dict()

print (d)

{'A': 1, 'B': 1}

然后按Set字典的列和键过滤行,然后DataFrame.head按组使用dict

df1 = (df[df['Set'].isin(d.keys())]

           .groupby(['Set', 'Flag'], group_keys=False)

           .apply(lambda x: x.head(d[x.name[0]])))

print (df1)

   data   Flag Set

2    -1  False   A

0     0   True   A

4     5  False   B

3    20   True   B

编辑:对于验证返回的解决方案,如果有 2 次True且False每组A:


print (df)

   data   Flag Set

0     0   True   A

1     8   True   A

2    30   True   A

3    -1  False   A

4   -14  False   A

5    20   True   B

6     5  False   B

7    19  False   B

8     7  False   C

9     8  False   c



df1 = pd.crosstab(df['Set'], df['Flag'])

d = df1[df1.ne(0).all(axis=1)].min(axis=1).to_dict()

print (d)

{'A': 2, 'B': 1}


df1 = (df[df['Set'].isin(d.keys())]

           .groupby(['Set', 'Flag'], group_keys=False)

           .apply(lambda x: x.head(d[x.name[0]])))

print (df1)

   data   Flag Set

3    -1  False   A

4   -14  False   A

0     0   True   A

1     8   True   A

6     5  False   B

5    20   True   B


查看完整回答
反对 回复 2023-10-18
?
叮当猫咪

TA贡献1776条经验 获得超12个赞

这可能是一个可能的解决方案,包含 3 个步骤:

  • 删除所有没有 true 和 false 标志的集合(此处为 C)

  • 计算每个设置标志组合所需的行数

  • 删除超过该计数行数的所有行

这会产生以下代码:

df = pd.DataFrame(data={"data":[0, 30, -1, 20, 5, 19, 7, 8],

                        "Flag":[True, True, False, True, False, False, False, False],

                        "Set":["A", "A", "A", "B", "B", "B", "C", "C"]})



# 1. removing sets with only one of both flags

reducer = df.groupby("Set")["Flag"].transform("nunique") > 1

df_reduced = df.loc[reducer]


# 2. counting the minimum number of rows per set

counts = df_reduced.groupby(["Set", "Flag"]).count().groupby("Set").min()


# 3. reducing each set and flag to the minumum number of rows

df_equal = df_reduced.groupby(["Set", "Flag"]) \

            .apply(lambda x: x.head(counts.loc[x["Set"].values[0]][0])) \

            .reset_index(drop=True)


查看完整回答
反对 回复 2023-10-18
?
ITMISS

TA贡献1871条经验 获得超8个赞

编辑:我想出了一个易于理解、简洁的解决方案:

  1. 只需获取.cumcount()分组依据setflag

  2. 检查一组setcumcount上面的结果(cc下面的代码)是否重复。如果一个组不包含重复项,则意味着需要将其删除。

In[1]: 

    data   Flag Set

0      0   True   A

1      8   True   A

2     30   True   A

3      0   True   A

4      8   True   A

5     30   True   A

6     -1  False   A

7    -14  False   A

8     -1  False   A

9    -14  False   A

10    20   True   B

11     5  False   B

12    19  False   B

13     7  False   C

14     8  False   c

编辑2:根据@Jezrael,我可以进一步简化以下三行代码:


df = (df[df.assign(cc = df.groupby(['Set', 'Flag'])

           .cumcount()).duplicated(['Set','cc'], keep=False)])

下面的代码进一步细分。


df['cc'] = df.groupby(['Set', 'Flag']).cumcount()

s = df.duplicated(['Set','cc'], keep=False)

df = df[s].drop('cc', axis=1)

df

Out[1]: 

    data   Flag Set

0      0   True   A

1      8   True   A

2     30   True   A

3      0   True   A

6     -1  False   A

7    -14  False   A

8     -1  False   A

9    -14  False   A

10    20   True   B

11     5  False   B

在删除之前,数据如下所示:


df['cc'] = df.groupby(['Set', 'Flag']).cumcount()

df['s'] = df.duplicated(['Set','cc'], keep=False)

# df = df[df['s']].drop('cc', axis=1)

df

Out[1]: 

    data   Flag Set  cc      s

0      0   True   A   0   True

1      8   True   A   1   True

2     30   True   A   2   True

3      0   True   A   3   True

4      8   True   A   4  False

5     30   True   A   5  False

6     -1  False   A   0   True

7    -14  False   A   1   True

8     -1  False   A   2   True

9    -14  False   A   3   True

10    20   True   B   0   True

11     5  False   B   0   True

12    19  False   B   1  False

13     7  False   C   0  False

14     8  False   c   0  False

然后,False列中的行s被删除df = df[df['s']]


查看完整回答
反对 回复 2023-10-18
  • 3 回答
  • 0 关注
  • 69 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信