按“标签”列对数据框进行排序,按每个“标签”随机播放,按“组”保留顺序
Sort a dataframe by a `label` column, shuffle per each `label`, preserve order per `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
:
- Rows are sorted by label
- Per each label, rows are shuffled
- But maintaining order based on the value
例如,这是一个可能的结果:
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'
给定以下数据框:
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
:
- Rows are sorted by label
- Per each label, rows are shuffled
- But maintaining order based on the value
例如,这是一个可能的结果:
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'