根据条件删除连续的重复行。

3

我目前有这个数据框:

id  date       outcome
3   03/05/2019  no
3   29/05/2019  no
3   04/09/2019  no
3   30/10/2019  yes
3   03/05/2020  no
5   03/12/2019  no
5   26/12/2019  no
5   27/01/2020  yes
5   03/06/2020  yes
6   04/05/2019  no
6   27/10/2019  no
6   26/11/2019  yes
6   28/11/2019  yes
6   29/11/2019  yes
6   13/04/2020  yes
6   14/04/2020  yes
6   24/04/2020  no
6   30/04/2020  no
6   05/05/2020  no

基于id分组,按日期升序排列。

如果一个当前行的结果与其后面的行相同,则需要将该行删除。但是,如果一行的结果为“yes”,则下一行必须是第一个“no”。这是上述数据框所需的结果:

id  date       outcome
3   04/09/2019  no
3   30/10/2019  yes
3   03/05/2020  no
5   26/12/2019  no
5   03/06/2020  yes
6   27/10/2019  no
6   14/04/2020  yes
6   24/04/2020  no

目前我正在做这件事:

m1 = (df['outcome'] != df['outcome'].shift()).cumsum()
updated_df = df.groupby([df['id'],m1]).tail(1)

然而,这只给我分组后yes/no计数的最后一个值。如何以最多使用Pandas的方式应用条件?


我不理解这个条件。对于 id=3,在“是”的后面(即日期为 03/05/2020 的行)不是具有结果“否”的组的第一行,但它仍然存在于预期输出中。 - Rodalm
2
@HarryPlotter 这有点棘手,我一开始也搞错了。基本上是删除连续的重复项,保留最后一个,除非在“yes”之后,保留第一个。每个组都要这样处理。 - mozway
1个回答

3

如果我理解正确,您需要进行两个步骤。首先计算一个掩码来检查结果是否与下一个不同(保留最后一个),或者是跟随“是”,所有的操作都要按组执行。这将导致您需要的筛选,除了在“是”之后,您会得到一个重复项(“是”之后保留,“最后一个”舍弃)。

第二步,再次检查连续结果的差异,但此时保留第一个结果。

# step 1
m1 = df['outcome']
m2 = m1.groupby(df['id']).shift(-1)
m3 = m1.groupby(df['id']).shift().eq('yes')&m1.eq('no')

df2 = df[~m1.eq(m2)|m3]

# step 2
m4 = df2['outcome']
m5 = m4.groupby(df['id']).shift()
df2[~m4.eq(m5)]

输出:

    id        date outcome
2    3  04/09/2019      no
3    3  30/10/2019     yes
4    3  03/05/2020      no
6    5  26/12/2019      no
8    5  03/06/2020     yes
10   6  27/10/2019      no
15   6  14/04/2020     yes
16   6  24/04/2020      no

谢谢你的回答,这个方法完美解决了我的问题。这不是必须的,只是出于好奇,假设你想在一个“是”之前保留一个“否”(基本上可能会有多个“否”,例如,在两个“是”之间有5个“否”,其中你选择第一个和最后一个“否”)。如何实现这一点?这需要大量的掩码吗? - Ze0ruso
1
@TSRAI 这取决于你的需求,如果你只想获取这些值,那很容易。更棘手的部分是将所有内容组合在一起。如果你有太多的条件,最好独立地根据各种条件提取行,然后将所有内容连接到单个数据框中。 - mozway

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