保持每个组的最高单场比赛

时间:2019-05-21 12:52:10

标签: python pandas max pandas-groupby

我正在努力使用pandas来基于2个groupby条件进行过滤

假设我有以下数据:

  • 每行分别表示来自2个数据源(id1id2)的事物(src1src2)的比较
  • 得分表示事物之间的相似程度(越高越好)
data = [
    {'src1': 'A', 'id1': '111', 'src2': 'B', 'id2': '111', 'score': 10},
    {'src1': 'A', 'id1': '222', 'src2': 'B', 'id2': '222', 'score': 9},
    {'src1': 'A', 'id1': '111', 'src2': 'B', 'id2': '222', 'score': 2},
    {'src1': 'A', 'id1': '222', 'src2': 'B', 'id2': '111', 'score': 4},
    {'src1': 'A', 'id1': 'default', 'src2': 'B', 'id2': '111', 'score': 3},
    {'src1': 'A', 'id1': 'default', 'src2': 'B', 'id2': '222', 'score': 3},
]

我想做的是 groupby src1 + id1 + src2并仅保留得分最高且count = 1的行

这是我的代码:

df = pd.DataFrame(data)
df['count'] = 1
groups = df.groupby(['src1', 'id1', 'src2', 'score']).agg(
    {'id2': 'unique', 'count': 'sum'})
print(groups)

我得到以下信息:

                                id2  count
src1 id1     src2 score                   
A    111     B    2           [222]      1 # DISCARD because below has higher score (10>2)
                  10          [111]      1 # KEEP
     222     B    4           [111]      1 # DISCARD because below has higher score (9>4)
                  9           [222]      1 # KEEP
     default B    3      [111, 222]      2 # DISCARD because count=2

我遇到的问题:

  • WITHOUT reset_index():如果我不使用reset_index(),每当我尝试访问得分 count 进行过滤时,都会得到一个 KeyError
groups = df.groupby(['src1', 'id1', 'src2', 'score']).agg(
    {'id2': 'unique', 'count': 'sum'})
groups[groups['score'] == groups['score'].max()]

KeyError: 'score'
  • reset_index():如果我使用它,则会“丢失”我的分组依据(即,每行变成一个新的单独行,而我的过滤结果仅产生1行
reset = groups.reset_index()
reset[reset['score'] == reset['score'].max()]

  src1  id1 src2  score  count    id2
1    A  111    B     10      1  [111]

如何扩展表达式以下内容,以便EACH GROUPONLY KEEPMAX score count=1将行分组?

groups = df.groupby(['src1', 'id1', 'src2', 'score']).agg(
    {'id2': 'unique', 'count': 'sum'})

2 个答案:

答案 0 :(得分:2)

使用GroupBy.transform来获得计数,而无需使用GroupBy.size来创建新的帮助程序列,然后通过不同的分组列来获得相似的max值,使用boolean indexing进行比较并通过链接条件进行过滤&的{​​{1}}:

bitwise AND

您的解决方案应更改:

m1 = df.groupby(['src1', 'id1', 'src2', 'score'])['id1'].transform('size') <= 1
m2 = df.groupby(['src1', 'id1', 'src2'])['score'].transform('max') == df['score']


df = df[m1 & m2]
print (df)
   id1  id2  score src1 src2
0  111  111     10    A    B
1  222  222      9    A    B

答案 1 :(得分:1)

其中一种方法

df['count'] = 1
groups = df.groupby(['src1', 'id1', 'src2', 'score']).agg(
    {'id2': 'unique', 'count': 'sum'})

m1 = groups['count'] <= 1
df = groups.reset_index(level=3)
m2 = (df.groupby(level=[0,1,2])['score'].transform('max') == df['score']).values

groups = groups[m1 & m2]
print (groups)
                       id2  count
src1 id1 src2 score              
A    111 B    10     [111]      1
     222 B    9      [222]      1