我有以下数据框架:

    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
...

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


当前回答

(我没有足够的声誉来评论这篇文章,所以我希望别人能帮我。)有人担心第一种方法:

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

这意味着该方法没有返回相同的对象,就像在上一个注释中建议的那样。所以这个方法确实会产生一个打乱的拷贝。

其他回答

您可以通过使用洗牌索引进行索引来洗牌数据帧的行。为此,你可以使用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和你的例子一样,你可以简单地重置索引:

TL;DR: np.random.shuffle(ndarray)可以完成这项工作。 所以,在你的情况下

np.random.shuffle(DataFrame.values)

DataFrame在底层使用NumPy ndarray作为数据持有者。(你可以从DataFrame源代码检查)

因此,如果使用np.random.shuffle(),它将沿着多维数组的第一个轴对数组进行洗牌。但是DataFrame的索引仍然没有被打乱。

不过,还是有几点需要考虑的。

函数返回none。如果您希望保留原始对象的副本,则必须在传递给函数之前这样做。 Sklearn.utils.shuffle(),正如用户tj89建议的那样,可以指定random_state和另一个选项来控制输出。您可能需要它用于开发目的。 Sklearn.utils.shuffle()更快。但是会将DataFrame的轴信息(索引,列)与它包含的ndarray一起SHUFFLE。

基准测试结果

在sklearn.utils.shuffle()和np.random.shuffle()之间。

ndarray

nd = sklearn.utils.shuffle(nd)

0.10793248389381915秒,快8倍

np.random.shuffle(nd)

0.8897626010002568秒

DataFrame

df = sklearn.utils.shuffle(df)

0.3183923360193148秒,快3倍

np.random.shuffle(df.values)

0.9357550159329548秒

结论:如果可以将轴信息(索引,列)与ndarray一起洗牌,请使用sklearn.utils.shuffle()。否则,使用np.random.shuffle()

使用代码

import timeit
setup = '''
import numpy as np
import pandas as pd
import sklearn
nd = np.random.random((1000, 100))
df = pd.DataFrame(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)

pythonbenchmarking

Shuffle pandas数据帧,在这种情况下,取一个样本数组索引,随机排序,然后将数组设置为数据帧的索引。现在根据索引对数据帧进行排序。这是你的洗牌数据帧

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

在上面的代码中插入你的数据帧在我的地方。

这里有另一种方法:

df['rnd'] = np.random.rand(len(df))
df = df.sort_values(by='rnd', inplace=True).drop('rnd', axis=1)

同样有用的是,如果你将它用于Machine_learning,并且想要始终分离相同的数据,你可以使用:

df.sample(n=len(df), random_state=42)

这确保了你的随机选择总是可复制的