代码之家  ›  专栏  ›  技术社区  ›  seaders

在pandas数据框中为每个组选择1 true和1 false

  •  1
  • seaders  · 技术社区  · 7 年前

    我有一个包含~1Mil行和~100k个唯一事件的数据帧。有一列 Won 每个事件中的哪一行被设置为true,并且事件中的每一行都被设置为false。

    即。,

    Event ID  Runner ID  Won
     E1        R1        True
     E1        R2        False
     E1        R3        False
     E2        R4        True
     E2        R5        False
     E2        R6        False
    

    我想得到的是一个平衡的数据帧,每个组只有一个赢家,只有一个非赢家。

    即。,

    Event ID  Runner ID  Won
     E1        R1        True
     E1        R3        False
     E2        R4        True
     E2        R5        False
    

    我不在乎每个项目选哪个非赢家,只要有一个赢家,一个非赢家。

    对于熊猫,我尝试了一些事情,选择胜利者和非胜利者,

    _won = df.Won
    winners = df[_won]
    
    non_winners = df[~_won]
    

    但我所看到的每一个过程,以及每一场比赛选出一名非冠军选手的过程都非常缓慢——每一个项目只有几秒钟的时间(如果你有10万个项目,这是不合理的)。

    一次射击 group apply 我是说,

    new_df = winners.append(
        non_winners
        .groupby('Event ID')
        .apply(lambda grp: grp.sample(1))
    

    在groupby上迭代,

    for event_id, grp in non_winners.groupby('Event ID'):
        winners.append(grp.sample(1))
    

    在Winners中遍历事件ID,

    event_ids = set(winners['Event ID'].drop_duplicates())
    for event_id in event_ids:
        winners.append(
            non_winners[non_winners['Event ID'] == event_id].sample(1))
    

    但在处理约1百万和约10万个事件时,每个选项似乎都非常缓慢。

    2 回复  |  直到 7 年前
        1
  •  5
  •   cs95 abhishek58g    7 年前

    使用 groupby head 是的。

    df.groupby(['Event ID', 'Won']).head(1)
    
      Event ID Runner ID    Won
    0       E1        R1   True
    1       E1        R2  False
    3       E2        R4   True
    4       E2        R5  False
    

    只要你不挑剔什么是保留在输出,因为输出是平衡的。


    还有 drop_duplicates 是的。

    df.drop_duplicates(subset=['Event ID', 'Won'], keep='last') 
    # or keep='first', it doesn't matter
    
      Event ID Runner ID    Won
    0       E1        R1   True
    2       E1        R3  False
    3       E2        R4   True
    5       E2        R6  False
    

    最后,如果要实现洗牌,请调用 sample 事先:

    (df.sample(frac=1)
       .sort_values(by=['Event ID'])
       .drop_duplicates(['Event ID', 'Won'])
    )
    
      Event ID Runner ID    Won
    2       E1        R3  False
    0       E1        R1   True
    4       E2        R5  False
    3       E2        R4   True
    
        2
  •  0
  •   seaders    7 年前

    我有一个选择,我很高兴能有这么快的速度,那就是在非赢家的队伍中使用洗牌和复制的组合,

    _won = df.Won
    winners = df[_won]
    _non_winners = shuffle(df[~_won])
    
    non_winners = _non_winners[~_non_winners.duplicated('Event ID')]
    
    new_df = winners.append(non_winners)
    

    在其他的选择中,每一组需要大约一秒钟的时间,这是不可持续的,因为它贯穿了那么多组,而这个解决方案,就我所见,给出了完全相同的结果,但在大约10秒钟内,相比之下,我不知道有多长时间。

    如果你想每一组超过一个,这是不可靠的,但可能的,你只是做了基本相同的一次,

    ...
    _non_winners = shuffle(df[~_won])
    
    dupeys = _non_winners.duplicated('Event ID')
    new_df = pandas.concat([
        winners,
        _non_winners[~dupeys]])
    
    _non_winners = _non_winners[dupeys]
    new_df = pandas.concat([
        new_df,
        _non_winners[~_non_winners.duplicated('race_event_id')]])