Pandas - 删除重复行,但保留另一列最高值的行

5
我有一个大型数据框(超过100列,数十万行),其中一些行包含重复的数据。我正在尝试删除重复行,保留具有不同列中最大值的行。
基本上,我正在根据时间段将数据分成单独的容器,因此在跨时间段时,预计会发现很多重复项,因为大多数实体存在于所有时间段中。然而,不能允许同一实体在给定时间段内出现超过一次。
我尝试了Python Pandas:按列A删除重复项,保留列B中具有最高值的行中的方法,使用数据子集,并计划重新组合原始数据框df。
数据子集示例:
              unique_id   period_id   liq
index                                   
19            CAN00CE0     199001  0.017610
1903          **USA07WG0** 199001  1.726374
12404         **USA07WG0** 199001  0.090525
13330         USA08DE0     199001  1.397143
14090         USA04U80     199001  2.000716
12404         USA07WG0     199002  0.090525
13330         USA08DE0     199002  1.397143
14090         USA04U80     199002  2.000716

在上面的例子中,我想保留第一个实例(因为liq高达1.72),并且舍弃第二个实例(liq较低,仅0.09)。请注意,在给定的period_id中可能有多个重复项。

我尝试过以下方法,但它对于我来说非常慢(5分钟后我停止了它):

def h(x):
    x = x.dropna() #idmax fails on nas, and happy to throw out where liq is na.
    return x.ix[x.liq.idmax()]

df.groupby([‘holt_unique_id’, ‘period_id’], group_keys = False).apply(lambda x: h(x))

我最终做了以下操作,这种方法更加冗长且难看,并且只保留一个重复的值,但是这也非常慢!考虑到其他类似复杂度的操作的速度,我想在这里寻求更好的解决方案。
因此,我的请求实际上是修复上述代码,使其更快。下面提供了一些指导,如果与下面的方法相同,也许我可以根据索引丢弃重复项,而不是采用我所采用的reset_index/set_index方法。
def do_remove_duplicates(df):
    sub_df = df[['period_id', 'unique_id']] 
    grp = sub_df.groupby(['period_id', 'unique_id'], as_index = False)
    cln = grp.apply(lambda x: x.drop_duplicates(cols = 'unique_id'))   #apply drop_duplicates.  This line is the slow bit!
    cln = cln.reset_index()   #remove the index stuff that has been added
    del(cln['level_0'])   #remove the index stuff that has been added
    cln.set_index('level_1', inplace = True)   #set the index back to the original (same as df).
    df_cln = cln.join(df, how = 'left', rsuffix = '_right')   # join the cleaned dataframe with the original, discarding the duplicate rows using a left join.
    return df_cln
1个回答

4
如何看待这个问题:
  • 使用最大值更新所有列。
  • 选择一行(比如第一行)。

由于此方法是矢量化的,因此速度应该会更快。

In [11]: g = df.groupby(["unique_id", "period_id"], as_index=False)

In [12]: g.transform("max")
Out[12]:
            liq
index
19     0.017610
1903   1.726374
12404  1.726374
13330  1.397143
14090  2.000716
12404  0.090525
13330  1.397143
14090  2.000716

In [13]: df.update(g.transform("max"))

In [14]: g.nth(0)
Out[14]:
          unique_id  period_id       liq
index
19         CAN00CE0     199001  0.017610
1903   **USA07WG0**     199001  1.726374
13330      USA08DE0     199001  1.397143
14090      USA04U80     199001  2.000716
12404      USA07WG0     199002  0.090525
13330      USA08DE0     199002  1.397143
14090      USA04U80     199002  2.000716

注意:我想在这里首先使用groupby first或last,但我认为它们会丢弃您的旧索引,我认为它们不应该... nth是可行的方法。
另一种选择是先切片出不等于liq max的那些。
(df[df["liq"] == g["liq"].transform("max")]  #  keep only max liq rows
 .groupby(["unique_id", "period_id"])
 .nth(0)

这听起来是正确的: (i)在存在重复字段的情况下:保留max(liq)字段,丢弃其他字段。 (ii)在不存在重复字段的情况下:保持最大值应该只保留已经存在的单行。 - Carl
@Carl在最后一行添加了另一个选择。如果这是你所需要的,那么速度会更快。 - Andy Hayden
这仍然似乎非常慢:g = df.groupby(["unique_id", "period_id"], as_index=False).g["liq"].transform("max")].groupby(["unique_id", "period_id"]).nth(0)。事实上,由于内存错误而失败!我想到了一个更快的方法,即使用计数来识别那些具有重复项的组。然后,我可以将最大转换应用于该分组,然后将两个分组重新组合成一个。确实,我可以使用max,或者只是按值(降序)排序,并使用g.nth(0)获取第一个元素? - Carl
我认为问题在于 g["liq"].transform("max") 重置了索引,导致丢失了原始索引?当然 df[df["liq"] == g["liq"].transform("max")] 导致内存错误...我仍在努力解决这个问题。使用 g.size() 可以产生重复数量的有效计数,并且非常快,因此我正在尝试使用它来获取其中 size >2 的 unique_id 和 period_id 对,然后应用上述 max 想法,这应该会更快,然后我需要重新组合原始数据帧。 - Carl
谢谢Andy,我还在苦恼pandas。你能给我一些代码吗? - Carl
显示剩余5条评论

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