给定以下数据帧:
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
:
- 行按标签
排序- 对于每个标签,行被洗牌
- 但是根据
的值维持秩序
例如,这是一个可能的结果:
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'