我有以下数据框架:

    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文件中读取的。所有类型为1的行都在上面,然后是类型为2的行,然后是类型为3的行,等等。

我想打乱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
...

我怎样才能做到这一点呢?


当前回答

Pandas的惯用方法是使用数据帧的.sample方法对所有行进行采样而不进行替换:

df.sample(frac=1)

frac关键字参数指定在随机样本中返回的行数百分比,因此frac=1表示返回所有行(按随机顺序)。


注意: 如果你想洗牌你的数据帧的位置和重置索引,你可以做例如。

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

在这里,指定drop=True可以防止.reset_index创建包含旧索引项的列。

后续注意:虽然上面的操作看起来不到位,但python/pandas足够聪明,不会对打乱的对象执行另一个malloc。也就是说,即使引用对象改变了(我的意思是id(df_old)和id(df_new)不一样),底层的C对象仍然是相同的。为了证明事实确实如此,你可以运行一个简单的内存分析器:

$ python3 -m memory_profiler .\test.py
Filename: .\test.py

Line #    Mem usage    Increment   Line Contents
================================================
     5     68.5 MiB     68.5 MiB   @profile
     6                             def shuffle():
     7    847.8 MiB    779.3 MiB       df = pd.DataFrame(np.random.randn(100, 1000000))
     8    847.9 MiB      0.1 MiB       df = df.sample(frac=1).reset_index(drop=True)

其他回答

您可以通过使用洗牌索引进行索引来洗牌数据帧的行。为此,你可以使用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

如果你想保持索引从1、2、.., n和你的例子一样,你可以简单地重置索引:

Pandas的惯用方法是使用数据帧的.sample方法对所有行进行采样而不进行替换:

df.sample(frac=1)

frac关键字参数指定在随机样本中返回的行数百分比,因此frac=1表示返回所有行(按随机顺序)。


注意: 如果你想洗牌你的数据帧的位置和重置索引,你可以做例如。

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

在这里,指定drop=True可以防止.reset_index创建包含旧索引项的列。

后续注意:虽然上面的操作看起来不到位,但python/pandas足够聪明,不会对打乱的对象执行另一个malloc。也就是说,即使引用对象改变了(我的意思是id(df_old)和id(df_new)不一样),底层的C对象仍然是相同的。为了证明事实确实如此,你可以运行一个简单的内存分析器:

$ python3 -m memory_profiler .\test.py
Filename: .\test.py

Line #    Mem usage    Increment   Line Contents
================================================
     5     68.5 MiB     68.5 MiB   @profile
     6                             def shuffle():
     7    847.8 MiB    779.3 MiB       df = pd.DataFrame(np.random.randn(100, 1000000))
     8    847.9 MiB      0.1 MiB       df = df.sample(frac=1).reset_index(drop=True)

我建议:

for x in df.columns:
    np.random.seed(42);
    np.random.shuffle(df[x].values)

在我使用任意长度的字符串列(使用dtype: object)进行的测试中,它比@haku的回答快了30倍,大概是因为它避免了创建可能昂贵的副本。

我的变体大约比公认的@Kris'es的答案快3倍,这似乎也没有避免复制(基于Linux顶部的RES列)。

以下是其中一种方法:

dataframe = dataframe.sample(frac=1, random_state=42).reset_index(drop=True)

在哪里

Frac =1表示数据帧的所有行

Random_state =42表示每次执行时保持相同的顺序

reset_index(drop=True)表示随机化数据帧的重新初始化索引

通过传递frac参数,使用sample()洗牌数据帧。 将打乱的DataFrame保存到一个新变量。

new_variable = DataFrame.sample(frac=1)