【问题标题】:Pandas - group by id and drop duplicate with thresholdPandas - 按 id 分组并删除带有阈值的重复项
【发布时间】:2017-09-28 13:13:56
【问题描述】:

我有以下数据:

userid itemid
  1       1
  1       1
  1       3
  1       4
  2       1
  2       2
  2       3

我想删除查看相同 itemID 超过或等于两次的用户 ID。 例如,userid=1 已经查看了 itemid=1 两次,因此我想删除 userid=1 的整个记录​​。但是,由于 userid=2 没有两次查看相同的项目,所以我将保留 userid=2 的原样。

所以我希望我的数据如下所示:

userid itemid
  2       1
  2       2
  2       3

有人可以帮我吗?

import pandas as pd    
df = pd.DataFrame({'userid':[1,1,1,1, 2,2,2],
                   'itemid':[1,1,3,4, 1,2,3] })

【问题讨论】:

  • 请发布创建该数据的可重现代码。

标签: python pandas group-by duplicates threshold


【解决方案1】:

按用户和项目对数据框进行分组:

views = df.groupby(['userid','itemid'])['itemid'].count()
#userid  itemid
#1       1         2 <=== The offending row
#        3         1
#        4         1
#2       1         1
#        2         1
#        3         1
#Name: dummy, dtype: int64

找出谁只看过任何物品一次:

THRESHOLD = 2
viewed = ~(views.unstack() >= THRESHOLD).any(axis=1)
#userid
#1    False
#2     True
#dtype: bool

合并结果并保留“好”行:

combined = df.merge(pd.DataFrame(viewed).reset_index())
combined[combined[0]][['userid','itemid']]
#   userid  itemid
#4       2       1
#5       2       2
#6       2       3

【讨论】:

    【解决方案2】:

    您可以使用duplicated 来确定行级别的重复项,然后对'userid' 执行groupby 来确定'userid' 级别的重复项,然后相应地删除。

    无门槛下降:

    df = df[~df.duplicated(['userid', 'itemid']).groupby(df['userid']).transform('any')]
    

    要使用阈值下降,请在duplicated 中使用keep=False,然后对布尔列求和并与您的阈值进行比较。例如,阈值为 3:

    df = df[~df.duplicated(['userid', 'itemid'], keep=False).groupby(df['userid']).transform('sum').ge(3)]
    

    没有阈值的结果输出:

       userid  itemid
    4       2       1
    5       2       2
    6       2       3
    

    【讨论】:

    • 如果我想放弃阈值怎么办?也就是说,如果我想删除重复次数超过 3 个的用户 ID,该怎么办?
    • 这是 THRESHOLD = 2 的特例技巧。对于更大的 THRESHOLD,您需要@DYZ 的更通用的代码。
    【解决方案3】:
    # group userid and itemid and get a count
    df2 = df.groupby(by=['userid','itemid']).apply(lambda x: len(x)).reset_index()
    #Extract rows where the max userid-itemid count is less than 2.
    df2 = df2[~df2.userid.isin(df2[df2.ix[:,-1]>1]['userid'])][df.columns]
    print(df2)
       itemid  userid
    3       1       2
    4       2       2
    5       3       2
    

    如果你想在某个阈值下降,只需设置

    df2.ix[:,-1]>threshold]
    

    【讨论】:

      【解决方案4】:

      我不知道Pandas 中是否有可用的功能来执行此任务。但是,我尝试了一种解决方法来解决您的问题。

      这是完整的代码。

      import pandas as pd
      dictionary = {'userid':[1,1,1,1,2,2,2],
                    'itemid':[1,1,3,4,1,2,3]}
      
      df = pd.DataFrame(dictionary, columns=['userid', 'itemid'])
      
      selected_user = []
      
      for user in df['userid'].drop_duplicates().tolist():
      
          items = df.loc[df['userid']==user]['itemid'].tolist()
          if len(items) != len(set(items)): continue
          else: selected_user.append(user)
      
      result = df.loc[(df['userid'].isin(selected_user))]
      

      此代码将产生以下结果。

          userid  itemid
      4   2       1
      5   2       2
      6   2       3
      

      希望对你有帮助。

      【讨论】:

      • for user in df['userid'].drop_duplicates().tolist() 始终可以替换为 df.groupby('userid')
      【解决方案5】:

      filter

      为此而生。您可以传递一个函数,该函数返回一个布尔值,用于确定组是否通过了过滤器。

      filtervalue_counts
      最通用和直观的

      df.groupby('userid').filter(lambda x: x.itemid.value_counts().max() < 2)
      

      filteris_unique
      寻找n &lt; 2时的特殊情况

      df.groupby('userid').filter(lambda x: x.itemid.is_unique)
      
         userid  itemid
      4       2       1
      5       2       2
      6       2       3
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-13
        • 2021-12-11
        • 2010-12-25
        相关资源
        最近更新 更多