根据条件 pandas 删除 DataFrame 中的重复行

Posted

技术标签:

【中文标题】根据条件 pandas 删除 DataFrame 中的重复行【英文标题】:Delete repeating rows in a DataFrame based on a condition pandas 【发布时间】:2022-01-14 03:41:54 【问题描述】:

我正在尝试根据以下条件删除数据框中的重复行: 如果 pagePath 列的值与上一行相同且 SessionId 相同,我需要删除该行。如果 SessionId 不同,则不应删除重复的 pagePath。这是我尝试过的:

data = data.sort_values(['SessionId', 'Datum'], ascending=True, ignore_index=True)
i = 0
for i, _ in data.iterrows():  # i = index, _ = row
    if i != 0:
        try:
            while data.SessionId[i] == data.SessionId[i - 1] and data.pagePath[i] == data.pagePath[i - 1]:
                data = data.drop(i - 1)
                data = data.reset_index(drop=True)
        except KeyError:
            continue

如您所见,我得到了 KeyError 异常,但我认为这并不坏,因为代码对具有 1000 行的数据框执行了应有的操作。唯一的问题是它不适用于具有 6,5 Mio 行的更大数据集。它要么永远不会完成,要么我得到 SIGKILL。我很清楚我不应该对数据集使用 for 循环,但我找不到更好的解决方案,如果您能帮助我改进我的代码,我将不胜感激。

【问题讨论】:

对我来说,您似乎在迭代 df 时对其进行了修改。我对么?这可能会导致一些意外行为。通常更好的是在 for 循环期间收集要删除的行的位置,然后一次性删除所有选定的行。 你考虑过drop_duplicates的使用吗? @saiden 是的,但我也不确定如何告诉 python 也考虑 SessionId?仅删除一个 SessionId 内的 pagePath 列中的重复值 类似data.drop_duplicates(subset=['SessionId', 'pagePath'], keep='first')?只要它是你想要的。 @saiden 不是,在第一个答案下面回答了为什么 【参考方案1】:

groupby on SessionIdpagePath 并找到每对出现的累积计数;然后使用np.ediff1d找到连续元素的差异并将其分配给df['cumcount'],由于我们要过滤掉连续重复,我们过滤掉df['cumcount']!=1

cols = df.columns
df['cumcount'] = np.concatenate(([0], np.ediff1d(df.groupby(['SessionId','pagePath']).cumcount())))
out = df.loc[df['cumcount']!=1, cols]

【讨论】:

不,我不能,因为那样我会丢失数据。考虑一下:只查看相同的 SessionId 并删除所有重复的 pagePath 值(代表用户行为 = 用户访问了哪些页面)意味着如果用户返回他已经访问过的页面,我不会看到这个 @Kami 我编辑了我的答案以反映你想要的。我想我现在明白了。看看吧。 是的,它现在就可以了!虽然我不完全明白那里发生了什么,但结果似乎是正确的!非常感谢您提供比我的更优雅的解决方案:) 唯一可以添加的就是必须先对值进行排序,否则结果将不正确【参考方案2】:

无论如何,像往常一样,我必须自己解决这个问题,如果没有@np8 的评论,这是不可能的。对于任何可能感兴趣的人:

locations = []
data = data.sort_values(['SessionId', 'Datum'], ascending=True, ignore_index=True)
i = 0
for i, _ in data.iterrows():  # i = index, _ = row
    if i != 0:
        try:
            if data.SessionId[i] == data.SessionId[i - 1] and data.pagePath[i] == data.pagePath[i - 1]:
                locations.append(i)
        except KeyError as e:
            print(e)
            continue

data_cleaned = data.drop(index=locations)

6,5 行 Mio 数据帧需要 470 秒,考虑到代码之前根本没有完成执行,这没关系。

【讨论】:

以上是关于根据条件 pandas 删除 DataFrame 中的重复行的主要内容,如果未能解决你的问题,请参考以下文章

如何根据列表有条件地更新 Pandas 中的 DataFrame 列

根据条件在Pandas DataFrame中选择行

根据堆叠条件为具有层次索引的 pandas DataFrame 赋值

Pandas DataFrame:根据条件替换列中的所有值

根据多个条件将新列添加到 Python Pandas DataFrame [重复]

Pandas Dataframe - 根据正则表达式条件替换所有单元格值