【问题标题】:How to shuffle groups of rows of a Pandas dataframe?如何打乱 Pandas 数据框的行组?
【发布时间】:2017-05-24 13:11:54
【问题描述】:

假设我有一个数据框 df:

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.rand(12,4))

print(df)

     0   1   2   3
0   71  64  84  20
1   48  60  83  61
2   48  78  71  46
3   65  88  66  77
4   71  22  42  58
5   66  76  64  80
6   67  28  74  87
7   32  90  55  78
8   80  42  52  14
9   54  76  73  17
10  32  89  42  36
11  85  78  61  12

如何将 df 的行随机打乱三乘三,即如何随机打乱前三行 (0, 1, 2) 与第二行 (3, 4, 5)、第三行 (6 , 7, 8) 还是第四 (9, 10, 11) 组?这可能是一个可能的结果:

print(df)

     0   1   2   3
3   65  88  66  77
4   71  22  42  58
5   66  76  64  80
9   54  76  73  17
10  32  89  42  36
11  85  78  61  12
6   67  28  74  87
7   32  90  55  78
8   80  42  52  14
0   71  64  84  20
1   48  60  83  61
2   48  78  71  46

因此,新订单具有来自原始数据帧的第二组 3 行,然后是最后一行,然后是第三组,最后是第一组。

【问题讨论】:

  • 随机播放是指将031425等交换?
  • 不,将 (0,1,2) 与 (3,4,5)、(6,7,8) 或 (9,10,11) 随机交换。
  • 3 rows的所有包都这样做?
  • 是的,所以随机将第 1 组与第 2、3 或 4 组随机混洗,每个组包含 3 行。我将进行编辑以使其更清晰。
  • 仍然不能 100% 确定您的确切意思 - 您是否想要以 3 人一组的方式随机排列行(每组保留顺序但会四处移动 - 或者只是两组交换位置等......)。你能提供示例输出吗?这将有助于澄清您的问题。

标签: python pandas numpy shuffle


【解决方案1】:

您可以重塑为3D 数组,将第一个轴分成两个,后一个轴的长度为3,对应于组长度,然后使用np.random.shuffle 进行沿第一个轴的分组就地洗牌, 它的长度与组的数量一样持有这些组, 从而达到我们想要的结果, 就像这样 -

np.random.shuffle(df.values.reshape(-1,3,df.shape[1]))

说明

为了解释一下,让我们使用np.random.permutation 沿第一个轴生成这些随机索引,然后索引到3D 数组版本。

1] 输入 df :

In [199]: df
Out[199]: 
     0   1   2   3
0   71  64  84  20
1   48  60  83  61
2   48  78  71  46
3   65  88  66  77
4   71  22  42  58
5   66  76  64  80
6   67  28  74  87
7   32  90  55  78
8   80  42  52  14
9   54  76  73  17
10  32  89  42  36
11  85  78  61  12

2] 获取3D 数组版本:

In [200]: arr_3D = df.values.reshape(-1,3,df.shape[1])

In [201]: arr_3D
Out[201]: 
array([[[71, 64, 84, 20],
        [48, 60, 83, 61],
        [48, 78, 71, 46]],

       [[65, 88, 66, 77],
        [71, 22, 42, 58],
        [66, 76, 64, 80]],

       [[67, 28, 74, 87],
        [32, 90, 55, 78],
        [80, 42, 52, 14]],

       [[54, 76, 73, 17],
        [32, 89, 42, 36],
        [85, 78, 61, 12]]])

3] 获取洗牌索引和索引到3D 版本的第一轴:

In [202]: shuffle_idx = np.random.permutation(arr_3D.shape[0])

In [203]: shuffle_idx
Out[203]: array([0, 3, 1, 2])

In [204]: arr_3D[shuffle_idx]
Out[204]: 
array([[[71, 64, 84, 20],
        [48, 60, 83, 61],
        [48, 78, 71, 46]],

       [[54, 76, 73, 17],
        [32, 89, 42, 36],
        [85, 78, 61, 12]],

       [[65, 88, 66, 77],
        [71, 22, 42, 58],
        [66, 76, 64, 80]],

       [[67, 28, 74, 87],
        [32, 90, 55, 78],
        [80, 42, 52, 14]]])

然后,我们将这些值分配回输入数据帧。

使用np.random.shuffle,我们只是在原地完成所有工作,并隐藏了显式生成洗牌索引和分配回所需的工作。

示例运行 -

In [181]: df = pd.DataFrame(np.random.randint(11,99,(12,4)))

In [182]: df
Out[182]: 
     0   1   2   3
0   82  49  80  20
1   19  97  74  81
2   62  20  97  19
3   36  31  14  41
4   27  86  28  58
5   38  68  24  83
6   85  11  25  88
7   21  31  53  19
8   38  45  14  72
9   74  63  40  94
10  69  85  53  81
11  97  96  28  29

In [183]: np.random.shuffle(df.values.reshape(-1,3,df.shape[1]))

In [184]: df
Out[184]: 
     0   1   2   3
0   85  11  25  88
1   21  31  53  19
2   38  45  14  72
3   82  49  80  20
4   19  97  74  81
5   62  20  97  19
6   36  31  14  41
7   27  86  28  58
8   38  68  24  83
9   74  63  40  94
10  69  85  53  81
11  97  96  28  29

【讨论】:

    【解决方案2】:

    @Divakar 的类似解决方案,可能更简单,因为我直接打乱数据帧的索引:

    import numpy as np
    import pandas as pd
    
    df = pd.DataFrame([np.arange(0, 12)]*4).T
    len_group = 3
    
    index_list = np.array(df.index)
    np.random.shuffle(np.reshape(index_list, (-1, len_group)))
    
    shuffled_df = df.loc[index_list, :]
    

    样本输出:

    shuffled_df
        Out[82]: 
         0   1   2   3
    9    9   9   9   9
    10  10  10  10  10
    11  11  11  11  11
    3    3   3   3   3
    4    4   4   4   4
    5    5   5   5   5
    0    0   0   0   0
    1    1   1   1   1
    2    2   2   2   2
    6    6   6   6   6
    7    7   7   7   7
    8    8   8   8   8
    

    【讨论】:

    • 不错的一个!我猜不同之处在于使用.loc 进行索引,与NumPy 的就地编辑相比,它可能不是性能最高的,而且loc 正在那里制作副本。
    • 我尝试了这种方法,但由于某种原因,您代码中的最后一行似乎不起作用,只有索引被打乱,值仍然存在......任何想法可能是什么原因?
    • 不是真的...我已经更新了我的示例,以便更容易看到值也被交换了。你确定你是某种特殊情况(例如所有值都相同或循环重复?)
    • 你能重现我回答中的例子吗?
    • 已修复,让我们循环使用它,在第二步它只更改了索引,不再更改值。必须在循环中包含index_list = np.array(df.index)
    【解决方案3】:

    这与其他两个答案相同,但使用整数除法创建组列。

    nrows_df = len(df)
    nrows_group = 3
    
    shuffled = (
        df
        .assign(group_var=df.index // nrows_group)
        .set_index("group_var")
        .loc[np.random.permutation(nrows_df / nrows_group)]
    )
    

    【讨论】:

      猜你喜欢
      • 2017-09-24
      • 2019-05-03
      • 1970-01-01
      • 2021-10-28
      • 2012-11-25
      • 2018-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多