54939


**\- 環境**  
Mac  
Python 3.7.3  
Jupyter Notebook 5.7.8

**\- やりたいこと**  
親ID列・子ID列を持ったデータフレームがあります。  
このとき、全行を単純にランダムソートするのではなく、同じ親IDを持つ行をグループ化した上で、そのグループをランダムソートできるでしょうか。

**\- やったこと**  
一部の抽出対象のparent-idが格納された配列を用意。  
isinメソッドでマッチしたデータを出力しようとしましたが、parent-
idをひとかたまりにランダム出力されるのではなく、単純なランダムソートで出力されてしまいます。

Python Code

[code]

    lis = [2, 3, 1] #parent-idが1~3までのものが出力対象
    test_df = pd.DataFrame({"parent-id": [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4],
                            "child-id": [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]})
    
    f = lambda x: x[(x["parent-id"].isin(lis))]
    test_df.groupby(["parent-id"]).apply(f).sample(frac=1, random_state=0)
    
[/code]

[![出力結果](https://i.stack.imgur.com/BW0g0.png)](https://i.stack.imgur.com/BW0g0.png)


CC BY-SA 4.0
2019-05-13T04:05:31.440
54924
2019-05-15T08:23:16.470
2019-05-15T08:23:16.470
10685
26841
question
python pandas
Python-pandasの階層型インデックスにおいて、親子関係を保ったまま親をシャッフルすることはできるのでしょうか。


`apply`した段階で`DataFrameGroupBy`オブジェクトではなく`DataFrame`になり、小グループ単位での操作はできなくなります。ですので

[code]

    lis = [2, 3, 1] #parent-idが1~3までのものが出力対象
    test_df = pd.DataFrame({"parent-id": [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4],
                            "child-d": [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]})
    
    f = lambda x: x[(x["parent-id"].isin(lis))].sample(frac=1, random_state=0)
    test_df.groupby(["parent-id"]).apply(f)
    
[/code]

のようにするとよいかと。

ref:  
\- [pd.DataFrame.groupby](https://pandas.pydata.org/pandas-
docs/stable/reference/api/pandas.DataFrame.groupby.html)  
\- [pd.core.groupby.GroupBy.apply](https://pandas.pydata.org/pandas-
docs/stable/reference/api/pandas.core.groupby.GroupBy.apply.html)


CC BY-SA 4.0
2019-05-13T13:42:00.027
54931
2019-05-13T13:42:00.027
10685
54924
answer


結論、user10685さんに記載いただいた内容を参考にして、groupbyを意識したことにより、以下のtipsで解決いたしました。  
[Shuffle a pandas dataframe by
groups](https://stackoverflow.com/questions/45585860/shuffle-a-pandas-
dataframe-by-groups)

fixしたコードは以下です。

[code]

    lis = [2, 3, 1]
    test_df = pd.DataFrame({"parent-id": [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4],
                            "child-id": [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]})
    groups = [test_df for _, test_df in test_df[(test_df["parent-id"].isin(lis))].groupby('parent-id')]
    random.shuffle(groups)
    pd.concat(groups).reset_index(drop=True)
    
[/code]

[![親単位でのグループシャッフル](https://i.stack.imgur.com/HyXD2.png)](https://i.stack.imgur.com/HyXD2.png)


CC BY-SA 4.0
2019-05-14T01:34:22.670
54939
2019-05-14T07:06:02.610
2019-05-14T07:06:02.610
26841
26841
54924
answer