DataFrame行をシャッフルする

以下のDataFrameがあります。

    Col1  Col2  Col3  Type
0      1     2     3     1
1      4     5     6     1
...
20     7     8     9     2
21    10    11    12     2
...
45    13    14    15     3
46    16    17    18     3
...

DataFrameはcsvファイルから読み込まれます。 Type 1を持つすべての行が一番上にあり、その後に Type 2を持つ行が続き、その後に Type 3を持つ行な​​どが続きます。

すべての Type が混在するように、DataFrameの行を入れ替えます。考えられる結果は次のとおりです。

    Col1  Col2  Col3  Type
0      7     8     9     2
1     13    14    15     3
...
20     1     2     3     1
21    10    11    12     2
...
45     4     5     6     1
46    16    17    18     3
...

結果からわかるように、行の順序はシャッフルされていますが、列は変わりません。これを明確に説明しているかどうかはわかりません。私がしていないかどうか私に知らせてください。

どうすればこれを達成できますか?

161

7 答え

パンダでこれを行うためのもっと慣用的な方法は、データフレームの .sample メソッドを使うことです。

df.sample(frac=1)

frac キーワード引数は、ランダムサンプルで返す行の割合を指定するので、 frac = 1 はすべての行を(ランダムな順序で)返すことを意味します。

Note: If you wish to shuffle your dataframe in-place and reset the index, you could do e.g.

df = df.sample(frac=1).reset_index(drop=True)

ここで drop = True を指定すると、 .reset_index は古いインデックスエントリを含む列を作成できなくなります。

329
追加された
reset_indexはシャッフルを機能させるためのものです。
追加された 著者 0709_,
notesample()メソッドには inplace パラメータがないため、(現在は)自分でできることはできないようです。新しいオブジェクトを作成せずに提案する。
追加された 著者 m-dz,
上からの引用 "注:データフレームをその場でシャッフルする場合[...]"。
追加された 著者 m-dz,
確かに、 df.sample(frac = 1).reset_index(drop = True)df インプレースをシャッフルする方法を説明してください。
追加された 著者 m-dz,
はい、これは私が最初のコメントで示したとおりです。必要なメモリを2回割り当てる必要があります。
追加された 著者 m-dz,
私の知る限りでは、新しいオブジェクトを返す sample()を使用した後ではありません。 print(hex(id(df)))print(hex(id(df.sample(frac = 1).reset_index(drop = True))))を試してください。 。しかし、私は間違っているかもしれません、基本的にここで確認または否定を求めたかったです。
追加された 著者 m-dz,
あなたが結果を持っているならば、ここでpingをいただければ幸いです。
追加された 著者 m-dz,
@ m-dzあなたは私が提案したものを実際に読みましたか?
追加された 著者 Kris,
@ m-dzはい...その文章の残りを読みましたか?
追加された 著者 Kris,
そうではありません。その行は df オブジェクトを再割り当てするだけで、それによってオブジェクトをその場で効果的に変更します。回避策としてそれを参照してください。
追加された 著者 Kris,
@ m-dz間違っていれば訂正してください。しかし、 .copy()を実行していなくても、同じ基本オブジェクトを参照していることになります。
追加された 著者 Kris,
さて、私は時間があるときに私はそれをメモリプロファイラで実行します。ありがとう
追加された 著者 Kris,
いいえ、それはDataFrameをコピーしません、ただこの行を見てください: github.com/pandas-dev/pandas/blob/v0.23.0/pandas/core/…
追加された 著者 ngọcminh.oss,

あなたは単にこれのためにsklearnを使うことができます

from sklearn.utils import shuffle
df = shuffle(df)
97
追加された

シャッフルインデックスを使ってインデックスを付けることで、データフレームの行をシャッフルすることができます。これには、たとえば np.random.permutation を使用できます(ただし np.random.choice も可能です)。

In [12]: df = pd.read_csv(StringIO(s), sep="\s+")

In [13]: df
Out[13]: 
    Col1  Col2  Col3  Type
0      1     2     3     1
1      4     5     6     1
20     7     8     9     2
21    10    11    12     2
45    13    14    15     3
46    16    17    18     3

In [14]: df.iloc[np.random.permutation(len(df))]
Out[14]: 
    Col1  Col2  Col3  Type
46    16    17    18     3
45    13    14    15     3
20     7     8     9     2
0      1     2     3     1
1      4     5     6     1
21    10    11    12     2

If you want to keep the index numbered from 1, 2, .., n as in your example, you can simply reset the index: df_shuffled.reset_index(drop=True)

44
追加された

TL;DR: np.random.shuffle(ndarray) can do the job.
So, in your case

np.random.shuffle(データフレーム.values)

私の理解によれば、データフレームは内部的にはデータホルダーとしてNumPy ndarrayを使用しています。 データフレームソースコードから確認できます。 。 そのため、 np.random.shuffle()を使用すると、 ) 、多次元配列の最初の軸に沿って配列をシャッフルします。しかし、列方向は変わりません。

いくつかの制限があります。

  • function returns none. In case you want to keep a copy of the original object, you have to do so before you pass to the function.
  • sklearn.utils.shuffle() user tj89 suggested, can designate random_state along with another option to control output. You may want that for dev purpose.

ベンチマーク結果

sklearn.utils.shuffle()の間および np.random.shuffle ()

ndarray

nd = sklearn.utils.shuffle(nd)

0.10793248389381915 sec. 8x faster

np.random.shuffle(nd)

0.8897626010002568秒

データフレーム

df = sklearn.utils.shuffle(df)

0.3183923360193148 sec. 3x faster

np.random.shuffle(df.values)', setup=setup, number=1000)

0.9357550159329548秒

結論: sklearn.utils.shuffle()を使用してください。可能であれば)

使用コード

setup = '''
import numpy as np
import pandas as pd
from sklearn.utils import shuffle
nd = np.random.random((1000, 100))
df = pd.データフレーム(nd)
'''

timeit.timeit('nd = sklearn.utils.shuffle(nd)', setup=setup, number=1000)
timeit.timeit('np.random.shuffle(nd)', setup=setup, number=1000)
timeit.timeit('df = sklearn.utils.shuffle(df)', setup=setup, number=1000)
timeit.timeit('np.random.shuffle(df.values)', setup=setup, number=1000)

13
追加された

(I don't have enough reputation to comment this on the top post, so I hope someone else can do that for me.) There was a concern raised that the first method:

df.sample(frac=1)

ディープコピーを作成するか、データフレームを変更しただけです。私は次のコードを実行しました:

print(hex(id(df)))
print(hex(id(df.sample(frac=1))))
print(hex(id(df.sample(frac=1).reset_index(drop=True))))

そして私の結果は次のとおりです。

0x1f8a784d400
0x1f8b9d65e10
0x1f8b9d65b70

これは、最後のコメントで示したように、メソッドが同じオブジェクトを返さないことを意味します。だからこの方法は確かにシャッフルコピーを行います。

2
追加された

最も簡単な解決策は次のとおりです。

df_shuffled = df.reindex(np.random.permutation(df.index))
1
追加された

この場合はインデックスのサンプル配列を取得してパンダデータフレームをシャッフルし、その順序をランダムにしてから配列をデータフレームのインデックスとして設定します。次にインデックスに従ってデータフレームをソートします。これがシャッフルされたデータフレームです

import random
df = pd.DataFrame({"a":[1,2,3,4],"b":[5,6,7,8]})
index = [i for i in range(df.shape[0])]
random.shuffle(index)
df.set_index([index]).sort_index()

出力

    a   b
0   2   6
1   1   5
2   3   7
3   4   8

上記のコードであなたの代わりにあなたのデータフレームを挿入してください。

0
追加された