在Python中的列表中随机排列列表的有效方法

时间:2020-02-29 01:59:21

标签: python pandas list parallel-processing shuffle

似乎以前应该已经问过一个问题,但我找不到。这样就可以了。

数据:
-主list(长度为== 16,000,000)的str子列表(每个子列表最多可包含500个项目)

目标:
-有效地调整主列表中的每个子列表。

我尝试了直接的 for 循环,列表理解,熊猫Series.apply()pandaralleldask数据帧{{1} }和.apply()方法。

.map_partition()循环大约需要 15分钟
forpd.series.apply()dask.series.apply()都能做到这一点刚过 6分钟

我的问题是“我能否更快地完成改组”?产生新副本或改组都可以接受。

以下是我的尝试:

dask.series.map_partition()

现在,我尝试使用dask分布式来查看,如果我能以某种方式错开模型训练和数据混排,以使训练时间和混排时间重叠,并获得更好的总体时间效率。

非常感谢任何关于如何使改组操作更有效的反馈或建议。


更新

尝试了一些建议后,以下事实证明是我可以实现的最快的方法,而且也非常简单!

def normal_shuffle(series):
    output = series.tolist()
    length = len(output)
    for i in range(length):
        random.Random().shuffle(output[i])
    return output

def shuffle_returned(a_list):
    new_list = a_list
    random.shuffle(new_list)
    return new_list

def shuffle_partition(a_partition):
    return a_partition.apply(shuffle_returned)

%time shuffled_for = normal_shuffle(test_series)
%time shuffled_apply = test_series.apply(shuffle_returned)

pandarallel.initialize(progress_bar=False, nb_workers=8)
%time shuffled_parallel_apply = test_series.parallel_apply(shuffle_returned)

test_ddf = ddf.from_pandas(test_series, npartitions=16)
test_ddf = test_ddf.reset_index(drop=True)

shuffled_ddf = test_ddf.apply(shuffle_returned, meta="some_str")
%time shuffled_ddf.persist()

shuffled_by_parttion_ddf = test_ddf.map_partitions(shuffle_partition, meta="productId")
%time shuffled_by_parttion_ddf.persist()

单线程numpy似乎是要走的路!

1 个答案:

答案 0 :(得分:2)

@TerryH-您根本不需要 .shuffle() RAM存储器内容,它足以生成一个aListOfSTRINGs,所以创建临时文件,但每个列表的费用为 np.random.permutation( len( aListOfListsOfSTRINGs[ ith ] ) ) O(1) ,花费了ALAP,一个新的随机订单,大小可间接访问ith-260 [us]的{​​{1}}成员。
(为什么移动RAM-I / O昂贵的数据以便“读取”-以后在某个地方按顺序排序时,无需再触摸数据,直到ALAP使用组件的间接寻址从缓存服务的块“读取”?)

对于平行 的愿望的实际成本,您可能会喜欢this的帖子,并带有互动式图形工具。


正如下面的@user2357112 supports Monica所述,
改组的目的是在内部 str 而不是 aListOfSTRINGs上,Mea Culpa

Q 我可以实现改组更快”吗?

是的。很多。 ... aListOfSTRINGs -使用合适的工具可以在 aListOfListsOfSTRINGs下实现 < / em>

Q “ ... 如何 我可以使其改组操作更有效吗?”

在普通的Py2.7工具中,就位的 150 x 2.5 [s]上花费的少于 .shuffle() 超过16,000,000个项目< / p>

~ 23 [s]

在普通Py3.5工具中,就地{strong> list( L )from zmq import Stopwatch; aClk = Stopwatch() #_______________________ a [us] Stopwatch pass; import random #_____________L creation ~ 2.7 [s]___________________________________________ aClk.start(); L = [ strID for strID in xrange( int( 16E6 ) ) ]; aClk.stop() 2721084 print L[:5] #___________________________________________________________proof [0, 1, 2, 3, 4] #_____________random.shuffle( L )______________________________________+proof aClk.start(); random.shuffle( L ); aClk.stop(); print "0:5\t", L[:5] 21473261 0:5 [13868243, 13087869, 13207292, 9344202, 1853783] #_____________random.shuffle( L )______________________________________+proof aClk.start(); random.shuffle( L ); aClk.stop(); print "0:5\t", L[:5] 22573922 0:5 [837396, 15032889, 10942767, 14571341, 4867854] #_______________________________________________________________________proof >>> len( L ) 16000000 上的 .shuffle() 下,超过16,000,000个项目。 / p>

~ 48 [s]

让我们提高真实性能:

list( L )

如果确实要获得终极表现:

  • 按原样保留所有$ conda activate py3 $ python ... aClk.start(); L = [ strID for strID in range( int( 16E6 ) ) ]; aClk.stop() 1959052 #_____________random.shuffle( L )______________________________________+proof aClk.start(); random.shuffle( L ); aClk.stop(); print( "0:5\t", L[:5] ) 45104806 0:5 [15744525, 10635923, 14530509, 10535840, 1465987] #_____________random.shuffle( L )______________________________________+proof aClk.start(); random.shuffle( L ); aClk.stop(); print( "0:5\t", L[:5] ) 47139358 0:5 [884437, 15420153, 9957947, 8118734, 11960914] 数据,仅存储在import numpy as np #____________L_as_a32______________16E6________________________~ 74 [ms] >>> aClk.start(); a32 = np.arange( 16E6, dtype = np.int32 ); aClk.stop() 74054 #_____________np.random.shuffle( a32-bit )______________________________+proof aClk.start(); np.random.shuffle( a32 ); aClk.stop(); print "0:5\t", a32[:5] 2400786 0:5 [ 2487493 14646705 13717283 5602561 7934593] aClk.start(); np.random.shuffle( a32 ); aClk.stop(); print "0:5\t", a32[:5] 2368381 0:5 [ 4841042 12882529 12298351 2198866 7054284] aClk.start(); np.random.shuffle( a32 ); aClk.stop(); print "0:5\t", a32[:5] 2369011 0:5 [14595649 7239135 3339593 9517600 6506681] #_____________np.random.shuffle( a64-bit )______________________________+proof aClk.start(); np.random.shuffle( a64 ); aClk.stop(); print "0:5\t", a64[:5] 2424487 0:5 [ 3234133 9224551 971604 13027484 806393] aClk.start(); np.random.shuffle( a64 ); aClk.stop(); print "0:5\t", a64[:5] 2386873 0:5 [ 3212124 10644428 8192909 2234984 13103406] aClk.start(); np.random.shuffle( a64 ); aClk.stop(); print "0:5\t", a64[:5] 2376065 0:5 [ 5624301 7741070 8859092 12287465 11721315]
  • 每个新的str以不变的成本 aListOfSTRINGs 附加到非重新组合的,线性增长的恒定顺序存储-aListOfSTRINGs < / li>
  • 而不是为存储 {} {{1} (可以是普通的O(1)aListOfListsOfSTRINGs数组,只要有新成员aListOfListsOfSTRINGs进入,只需附加一个aListOfORDINALs即可) li>
  • 快速享受 非常 非常高效就地list在Py2.7的numpy 下或在Py3.5的len( aListOfListsOfSTRINGs )
  • 以超快时间访问所有aListOfSTRINGs-s,以aListOfORDINALs.shuffle()的代价23 [s],以获得实际的< 50 [s]-s