在DataFrame中按组打乱行,保持组的相对顺序不变

2 投票
1 回答
50 浏览
提问于 2025-04-13 21:23

给定以下的数据框(df):

data = {'Org': ['Tom', 'Kelly', 'Rick', 'Dave','Sara','Liz'], 
        'sum': [3, 4, 4, 4, 5, 5]}
df = pd.DataFrame(data)

#      Org  sum
# 0    Tom    3
# 1  Kelly    4
# 2   Rick    4
# 3   Dave    4
# 4   Sara    5
# 5    Liz    5

我想要只打乱那一列中的重复值,同时保持其他值的顺序不变。

输出结果应该像这样:

data = {'Org': ['Tom', 'Rick', 'Dave', 'Kelly','Liz','Sara'],
        'sum': [3, 4, 4, 4, 5, 5]}
df = pd.DataFrame(data)

#      Org  sum
# 0    Tom    3
# 1   Rick    4
# 2   Dave    4
# 3  Kelly    4
# 4    Liz    5
# 5   Sara    5

使用 df.sample(frac=1) 会把所有的行都打乱,但这不是我想要的效果。

1 个回答

1

排序的分组

如果你的分组是连续的,并且你想保持它们的相对顺序,可以使用 groupby.sample

out = df.groupby('sum', sort=False).sample(frac=1)

示例输出:

     Org  sum
0    Tom    3
3   Dave    4
1  Kelly    4
2   Rick    4
5    Liz    5
4   Sara    5

如果你想按照总和来排序输出,可以这样做:

out = df.groupby('sum', sort=False).sample(frac=1)
# or
out = df.sample(frac=1).sort_values(by='sum', kind='stable')

这样可以确保分组是排序的,即使输入时它们并不是排序的。

保持原样的分组

相反,如果你想完全保持分组的原始顺序,但仍然想在组内打乱顺序,比如这个例子:

     Org  sum
0    Tom    3
1  Kelly    4
2   Rick    4
3   Sara    5
4    Liz    5
5   Dave    4 # this is part of group "4" but we want the row to stay there

那么可以使用 groupby.transform 来在原地打乱索引,然后重新索引:

out = df.loc[df.groupby('sum', sort=False)['sum']
               .transform(lambda g: g.sample(frac=1).index)]

示例输出:

     Org  sum
0    Tom    3
2   Rick    4
5   Dave    4
4    Liz    5
3   Sara    5
1  Kelly    4 # the group was shuffled, not the absolute position

撰写回答