随机数据帧行

JNe*_*ens 345 python shuffle permutation dataframe pandas

我有以下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
...
Run Code Online (Sandbox Code Playgroud)

从csv文件中读取DataFrame.所有具有Type1的行都在顶部,其次是具有Type2 的行,然后是具有Type3 的行等.

我想改组DataFrame的行,以便所有的行Type都是混合的.可能的结果可能是:

    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
...
Run Code Online (Sandbox Code Playgroud)

从结果中可以看出,行的顺序是混洗的,但列保持不变.我不知道我是否清楚地解释了这一点.如果我不知道,请告诉我.

我怎样才能做到这一点?

Kri*_*ris 658

使用pandas执行此操作的更惯用方法是使用.sample数据框的方法,即

df.sample(frac=1)
Run Code Online (Sandbox Code Playgroud)

frac关键字参数指定的行的分数的随机样本中返回,所以frac=1装置返回所有行(随机顺序).

注意: 如果您希望就地对数据帧进行随机播放并重置索引,则可以执行以下操作:

df = df.sample(frac=1).reset_index(drop=True)
Run Code Online (Sandbox Code Playgroud)

这里,指定drop=True阻止.reset_index创建包含旧索引条目的列.

  • 是的,这正是我想在第一条评论中展示的内容,你必须两次分配必要的内存,这远远不能做到这一点. (5认同)
  • 不,它不会复制DataFrame,只需看看这一行:https://github.com/pandas-dev/pandas/blob/v0.23.0/pandas/core/generic.py#L4198 (3认同)
  • @m-dz 我在上面运行了内存分析器。请参阅更新答案中的“后续说明”。 (3认同)
  • 回覆.你的**note**,`sample()`方法没有`inplace`参数,所以看起来(目前)不能在不创建新对象的情况下做你建议的事情. (2认同)
  • @m-dz 如果我错了,请纠正我,但如果您不执行 `.copy()`,您仍然引用相同的底层对象。 (2认同)
  • 好的,有时间我会用内存分析器运行它。谢谢 (2认同)

tj8*_*j89 184

你可以简单地使用sklearn

from sklearn.utils import shuffle
df = shuffle(df)
Run Code Online (Sandbox Code Playgroud)

  • 很好,但是您可能需要在改组后重置索引:df.reset_index(inplace = True,drop = True) (2认同)
  • Pandas 已经是一个巨大的图书馆了。实际上没有必要仅仅为了洗牌一些行而导入另一个巨大的库。下一步是什么?导入 jquery 和 Apache Commons? (2认同)

jor*_*ris 52

您可以通过使用混洗索引进行索引来对数据帧的行进行随机播放.为此,您可以使用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
Run Code Online (Sandbox Code Playgroud)

如果要保持索引编号为1,2,..,n,如示例所示,则只需重置索引即可: df_shuffled.reset_index(drop=True)


hak*_*aku 34

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

np.random.shuffle(DataFrame.values)
Run Code Online (Sandbox Code Playgroud)

DataFrame引擎盖下,使用NumPy ndarray作为数据持有者.(您可以从DataFrame源代码中查看)

因此,如果您使用np.random.shuffle(),它将沿着多维数组的第一轴对阵列进行混洗.但DataFrame保持不变的指数.

但是,有一些要考虑的问题.

  • 函数返回none.如果要保留原始对象的副本,则必须在传递给函数之前执行此操作.
  • sklearn.utils.shuffle()用户tj89建议,可以指定random_state另一个选项来控制输出.您可能希望将其用于开发目的.
  • sklearn.utils.shuffle()是比较快的.但洗牌的轴信息(索引,列)DataFrame与沿ndarray它包含的内容.

基准测试结果

之间sklearn.utils.shuffle()np.random.shuffle().

ndarray

nd = sklearn.utils.shuffle(nd)
Run Code Online (Sandbox Code Playgroud)

0.10793248389381915秒 快了8倍

np.random.shuffle(nd)
Run Code Online (Sandbox Code Playgroud)

0.8897626010002568秒

数据帧

df = sklearn.utils.shuffle(df)
Run Code Online (Sandbox Code Playgroud)

0.3183923360193148秒 快3倍

np.random.shuffle(df.values)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

  • `df = df.sample(frac=1)` 和 `df = sklearn.utils.shuffle(df)` 做的事情不一样吗?根据我的测量,`df = df.sample(frac=1)` 速度更快,并且似乎执行完全相同的操作。他们也都分配了新的内存。`np.random.shuffle(df.values)` 是最慢的,但不会分配新内存。 (4认同)
  • 在将轴与数据一起洗牌方面,它似乎可以做到同样的事情。是的,使用上面相同的代码,似乎 `df.sample(frac=1)` 比 `sklearn.utils.shuffle(df)` 快 20%。或者你可以做`sklearn.utils.shuffle(ndarray)`来得到不同的结果。 (2认同)

PV8*_*PV8 14

还有什么有用的,如果您将它用于 Machine_learning 并希望始终分离相同的数据,您可以使用:

df.sample(n=len(df), random_state=42)
Run Code Online (Sandbox Code Playgroud)

这可以确保您的随机选择始终可复制

  • 当 frac=1 时,你不需要 n=len(df) (4认同)

小智 11

(我没有足够的声誉在最高职位发表评论,所以我希望其他人可以为我做这件事.)有人担心第一种方法:

df.sample(frac=1)
Run Code Online (Sandbox Code Playgroud)

做了一个深层副本或只是改变了数据帧.我运行了以下代码:

print(hex(id(df)))
print(hex(id(df.sample(frac=1))))
print(hex(id(df.sample(frac=1).reset_index(drop=True))))
Run Code Online (Sandbox Code Playgroud)

我的结果是:

0x1f8a784d400
0x1f8b9d65e10
0x1f8b9d65b70
Run Code Online (Sandbox Code Playgroud)

这意味着该方法不会返回相同的对象,如上一条评论中所建议的那样.所以这个方法确实可以制作一个混乱的副本.

  • 请查看原始答案的**后续说明**。在那里您将看到,即使引用已更改(不同的“id”),底层对象也不会被复制。换句话说,该操作实际上是在内存中进行的(尽管诚然这并不明显)。 (2认同)

ans*_*hul 8

以下可能是其中一种方式:

dataframe = dataframe.sample(frac=1, random_state=42).reset_index(drop=True)
Run Code Online (Sandbox Code Playgroud)

在哪里

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

random_state=42表示在每次执行中保持相同的顺序

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


Ido*_*ohn 6

AFAIK 最简单的解决方案是:

df_shuffled = df.reindex(np.random.permutation(df.index))
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这会更改原始 df 中的索引,并生成一个副本,您将其保存到 df_shuffled 中。但是,更令人担忧的是,任何不依赖于索引的东西,例如 `df_shuffled.iterrows()' 都会产生与 df 完全相同的顺序。总之,谨慎使用! (3认同)
  • @AndreasSchörgenhumer,感谢您指出这一点,您部分正确!我知道我已经尝试过了,所以我做了一些测试。不管 `np.random.permutation` 的文档怎么说,并且根据 numpy 的版本,你会得到我描述的或你提到的效果。使用 numpy > 1.15.0,创建一个数据框并执行简单的 `np.random.permutation(df.index)`,原始 df 中的索引会发生变化。对于 numpy == 1.14.6,情况并非如此。因此,我比以往任何时候都更重复我的警告:由于无法预见的副作用和版本依赖性,这种做事方式是危险的。 (3认同)