【问题标题】:在保持最大值的同时删除连续的重复项
【发布时间】:2022-01-23 15:26:40
【问题描述】:

我正在尝试从 X 列中删除连续的重复项,同时根据 Y 列将条目保持为最大值,但遗憾的是没有成功。 数据框如下:

idx X Y
0 A 3
1 B 2
2 A 7
3 A 10
4 B 1
5 C 4
6 A 3
7 A 3

我想要实现的是:

idx X Y
0 A 3
1 B 2
3 A 10
4 B 1
5 C 4
7 A 3

我发现的大多数解决方案只是删除重复的吹捧场,而不考虑任何重复模式。

请注意,重复项可能具有相同的值。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    您需要先申请itertools-style-groupby,然后再申请keep the rows where Y is maximal

    >>> df 
       idx  X   Y
    0    0  A   3
    1    1  B   2
    2    2  A   7
    3    3  A  10
    4    4  B   1
    5    5  C   4
    6    6  A   3
    7    7  A   5
    >>> y_max = df.groupby(df['X'].ne(df['X'].shift()).cumsum())['Y'].transform('max')
    >>> df[df['Y'] == y_max] 
       idx  X   Y
    0    0  A   3
    1    1  B   2
    3    3  A  10
    4    4  B   1
    5    5  C   4
    7    7  A   5
    

    编辑:

    最初的解决方案有一个错误,只是偶然产生了正确的 idx 列。

    编辑 2:

    如果你只想每组保留一行,你可以使用

    >>> y_idxmax = df.groupby(df['X'].ne(df['X'].shift()).cumsum())['Y'].idxmax()
    >>> df.loc[y_idxmax] 
       idx  X   Y
    0    0  A   3
    1    1  B   2
    3    3  A  10
    4    4  B   1
    5    5  C   4
    7    7  A   5
    

    这个归功于Ch3steR

    【讨论】:

    • 嗨,我忘了补充一点,重复项可能具有相同的值。您的第一个解决方案是在我的完整数据集上生成适量的值。
    • @massigarg 是的,但第一个解决方案可能会产生错误的 idx 列。为了澄清,您只想保留 Y 最大的每组的第一行?
    • 是的,正确的。类似 max(Yi, Yi+1)
    • @timgeb 或者你可以在这里使用GroupBy.idxmax。也许像这样idx = df.groupby(itertools-style-grouping)['Y'].idxmax(); df.loc[idx, :] # or df.reindex(idx)
    • @massigarg 查看 Ch3steR 的评论
    【解决方案2】:

    我无法立即找出已经给出的答案,所以我编写了一个简单的脚本来做同样的事情。它采用具有重复值的索引并通过一次比较两个来删除它们。

    检查下面的代码-

    import pandas as pd
    
    data = {'X':['A', 'B', 'A', 'A', 'A', 'B', 'C', 'A', 'A'], 
            'Y': [3, 2, 12, 7, 10, 1, 4, 3, 5]}
    data = pd.DataFrame(data)
    
    mask = data['X'] == data['X'].shift()
    
    to_check = data.loc[mask].index.tolist()
    
    for i, _ in enumerate(to_check):
        index = to_check[i]
        if data.iloc[index]['Y'] > data.iloc[index - 1]['Y']:
            data.drop(index - 1, axis=0, inplace=True)
            data.reset_index(inplace=True, drop=True)
        else:
            data.drop(index, axis=0, inplace=True)
            data.reset_index(inplace=True, drop=True)
    
        to_check = [value - 1 for value in to_check]
    
    print(data)
    
    # OUTPUT
    
       X   Y
    0  A   3
    1  B   2
    2  A  12
    3  B   1
    4  C   4
    5  A   5
    

    【讨论】:

      【解决方案3】:

      创建一个将连续的列堆成一个组的列

         df['temp']=(~(df['X']==df['X'].shift())|(df['X'].shift(-1)==df['X'])).cumsum()
      

      groupby 连续的组并过滤掉 Y 的值等于每个组中的最大值。删除 temp 列

      df[df.groupby('temp')['Y'].transform(lambda x:(x==x.max()))].drop(columns=['temp'])
      

      一种更简洁的方法不是创建列,而是将连续组保存到一个变量中,然后按如下方式分组

      s=(~(df['X']==df['X'].shift())|(df['X'].shift(-1)==df['X'])).cumsum()
      print(df[df.groupby(s)['Y'].transform(lambda x:(x==x.max()))])
      
          idx  X   Y
      0    0  A   3
      1    1  B   2
      3    3  A  10
      4    4  B   1
      5    5  C   4
      7    7  A   5
      

      【讨论】:

        【解决方案4】:

        或者我更喜欢只在 groupby 参数中指定组:

        df.groupby(df['X'].ne(df['X'].shift()).cumsum(), as_index=False).max()
        

        或者:

        df.groupby(df['X'].ne(df['X'].shift()).cumsum()).max().reset_index(drop=True)
        

        两个输出:

           idx  X   Y
        0    0  A   3
        1    1  B   2
        2    3  A  10
        3    4  B   1
        4    5  C   4
        5    7  A   5
        

        【讨论】:

        • 这会“意外”生成正确的 idx 列,因为巧合的是,最大 Y 值始终位于最高 idx 值(每组)。如果在原始数据框中切换 7 和 10,结果将是错误的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-12-01
        • 2014-02-03
        • 2021-12-29
        • 1970-01-01
        • 1970-01-01
        • 2010-11-29
        • 2022-01-12
        相关资源
        最近更新 更多