python展平数组的数组,为什么funtools较慢?

时间:2019-07-08 03:45:47

标签: python numpy flatten functools

基于此问题Async/await

我想要一种比双循环解决方案更快的方法。所以我写了一个基于functools的函数,但是看起来慢很多。

orders2.shape
(9966, 1)

import time

t0 = time.time()
[x for i in orders2.values.tolist() for x in i[0].tolist()]
t1 = time.time()

t1-t0
0.009984493255615234
import time

t0 = time.time()
functools.reduce(lambda a,b: a+b[0].tolist() , orders2.values.tolist(), [])
t1 = time.time()

t1-t0
1.4101920127868652

我的问题是1.这怎么可能发生? 2.使用大数据时,functools算法会比双循环更快吗? 3.还有其他比双循环更快的算法吗?

3 个答案:

答案 0 :(得分:2)

这与给list comprehension vs map的答案密切相关,因为您在lambda语句中使用reduce时,您将发送要在每次迭代中运行的python代码,从而减慢了速度减少下来。列表理解被认为是更加有效和可读的,因此它们是首选的选择方法。

那说明了为什么不使用itertools.chain.from_iterable以及map ping operator.itemgetter。这将产生相同的输出,同时还利用一些出色的内置方法。 没有经过速度测试

>>> from itertools import chain
>>> from operator import itemgetter
>>> arr = array([[array([33120, 28985,  9327, 45918, 30035, 17794, 40141,  1819, 43668],
      dtype='int64')],
       [array([33754, 24838, 17704, 21903, 17668, 46667, 17461, 32665],
      dtype='int64')],
       [array([46842, 26434, 39758, 27761, 10054, 21351, 22598, 34862, 40285,
       17616, 25146, 32645, 41276], dtype='int64')],
       [array([24534,  8230, 14267,  9352,  3543, 29397,   900, 32398, 34262,
       37646, 11930, 37173], dtype='int64')],
       [array([25157], dtype='int64')],
       [array([ 8859, 20850, 19322,  8075], dtype='int64')]], dtype=object)
>>> array(list(chain.from_iterable(map(itemgetter(0),arr.tolist()))))
[33120 28985  9327 45918 30035 17794 40141  1819 43668 33754 24838 17704
 21903 17668 46667 17461 32665 46842 26434 39758 27761 10054 21351 22598
 34862 40285 17616 25146 32645 41276 24534  8230 14267  9352  3543 29397
 900 32398 34262 37646 11930 37173 25157  8859 20850 19322  8075]

答案 1 :(得分:2)

简而言之,分开进行函数调用和列表重新分配开销,您的嵌套循环算法为O(N),而使用reduce的算法为O(N²)。

即使算法没有不同,调用函数的成本为“ 0”的想法还是来自数学,因为函数是很好的理论构造。

在计算机程序中运行时,调用函数需要初始化上下文-如果是Python,则创建带有局部变量的Frame对象。当您传递参数时,这意味着在一个元组中,参数将在函数调用之前进行构造,并在函数主体中进行解构(尽管这些步骤可能会通过实现进行优化)。

在2嵌套循环方法中,您所要做的就是在本机代码中迭代一个迭代器-尽管理论上,按照Python的规范,这也意味着要调用一个函数(对象的__iter__方法) ,在本机代码迭代器的实际实现中通常要快得多。

但是,这并不能说明您在此处看到的差异。主要问题在于,对于每次迭代,执行a + b[0].tolist()时都会在内存中创建一个新列表“ c”,将“ a”的值复制到那里,然后将b [0]中的值附加到该列表中。这个新的清单+已经拼合的元素的副本将在每个步骤中进行。在list-comphrehension的情况下,不会发生多余的复制-在父2D结构展开时会放置一个新元素,并且对Python进行了很好的优化以预先分配空间,以便在创建列表时以这种形式建造。

答案 2 :(得分:0)

我认为至少存在两个问题:

  1. 与第一个一样,您正在创建一个列表并在其中添加元素。但是,对于第二个列表,您将继续用functools.reduce连接两个列表,这将产生一个新列表。

  2. @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = LayoutInflater.from(getContext()); View view = convertView; if (convertView == null) { view = inflater.inflate(R.layout.griditem_ig_post, null); ImageView ThisViewIMG = view.findViewById(R.id.GridImageView); //Calculating Image Height (Square Image) ThisViewIMG.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { v.removeOnLayoutChangeListener(this); v.getLayoutParams().height = v.getWidth(); v.requestLayout(); } }); } GridImage ThisImg = getItem(position); ImageView ThumbnailImage = view.findViewById(R.id.GridImageView); //THIS IS THE CUSTOM CHECKBOX! CustomCheckBox scb = (CustomCheckBox) view.findViewById(R.id.MyCheckBox); scb.setChecked(ThisImg.IsChecked); scb.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { CustomCheckBox cb = (CustomCheckBox)view; int position = (int)cb.getTag(); GridImage ThisImg = getItem(position); Log.d("CustomCheckBox", String.valueOf(!ThisImg.IsChecked)); ThisImg.setChecked(!ThisImg.IsChecked); cb.setChecked(ThisImg.IsChecked); } }); Glide.with(context).load(Post.IMG_ThumbnailURL).fitCenter().into(ThumbnailImage); scb.setTag(position); return view; } 返回一个生成器,这是主要目的。简而言之,这不是为了速度。