按' label '列对数据框进行排序,对每个' label '进行洗牌,对每个' group '保持顺序



给定以下数据帧:

df = pd.DataFrame(data={'value': ['all', 'moon', 'less', 'cat', 'pen' , 'dark', 'pile'],
'label': [0, 1, 1, 0, 1, 0, 0],
'group': ['A', 'B', 'B', 'B', 'A', 'B', 'A']})

输出:

value      label  group
0   'all'      0      'A'
1   'moon'     1      'B'
2   'less'     1      'B'
3   'cat'      0      'B'
4   'pen'      1      'A'
5   'dark'     0      'B'
6   'pile'     0      'A'

我想用以下条件生成一个新的dataframe:

  1. 行按标签
  2. 排序
  3. 对于每个标签,行被洗牌
  4. 但是根据
  5. 的值维持秩序

例如,这是一个可能的结果:

value      label  group
0   'all'      0      'A'
3   'cat'      0      'B'
5   'dark'     0      'B'
6   'pile'     0      'A'
2   'less'     1      'B'
4   'pen'      1      'A'
1   'moon'     1      'B'

因此在条件3中,'pile''all'之后,并且具有相同的标签,并且来自同一组。任何其他的洗牌和排序,都不应该让'pile'出现在'all'之前。

或另一个不同的洗牌:

value      label  group
3   'cat'      0      'B'
0   'all'      0      'A'
6   'pile'     0      'A'
5   'dark'     0      'B'
4   'pen'      1      'A'
2   'less'     1      'B'
1   'moon'     1      'B'

有什么干净的方法可以做到这一点吗?

这实际上是相当复杂的实现。

首先使用sample(frac=1):

完全打乱数据帧
# np.random.seed(0) # for reproducibility
df2 = df.sample(frac=1).sort_values(by='label', ignore_index=True)

输出:

value  label group
0  'pile'      0   'A'
1   'cat'      0   'B'
2   'all'      0   'A'
3  'dark'      0   'B'
4  'less'      1   'B'
5  'moon'      1   'B'
6   'pen'      1   'A'

然后按标签对值进行排序,并确定每组的排序顺序:

idx = (df2.reset_index()                  # save index as column
.sort_values(by='value')           # sort values
.groupby(['label', 'group'])['index']  # reorder the index per value
.transform(sorted).sort_values()       # using sorted
.index
)
# Int64Index([2, 1, 0, 3, 4, 5, 6], dtype='int64')

最后用这个来重新索引你的df2:

df2.loc[idx]

输出:

value  label group
2   'all'      0   'A'
1   'cat'      0   'B'
0  'pile'      0   'A'
3  'dark'      0   'B'
4  'less'      1   'B'
5  'moon'      1   'B'
6   'pen'      1   'A'

最新更新