除了使用'for-loops'之外,我如何将我的思维转移到“矢量化我的计算”?

时间:2017-11-12 22:08:27

标签: python arrays loops numpy vectorization

这绝对是一个概念问题,但我希望在SO上获得有关此主题的其他专业知识。我的大多数编程最近来自Numpy数组。我一直在匹配两个大小不同的数组中的项目。大多数时候我会进入for循环甚至最差,嵌套for循环。我最终试图避免使用for循环,因为我试图获得更多的数据科学经验,因为for循环执行速度较慢。

我很清楚Numpy和我可以研究的预定义cmds,但对于那些经验丰富的人来说,当你迭代某些东西时,你是否有一个一般的思想流派? < / p>

类似于以下内容:

small_array = np.array(["a", "b"])
big_array = np.array(["a", "b", "c", "d"])

for i in range(len(small_array)):
    for p in range(len(big_array)):
        if small_array[i] == big_array[p]:
            print "This item is matched: ", small_array[i]

我很清楚有一种方法可以用这种方法给猫做皮,但我对其他方法和思维方式感兴趣。

4 个答案:

答案 0 :(得分:3)

由于我已经使用数组语言几十年(APL,MATLAB,numpy),我无法帮助完成启动步骤。但我怀疑我的工作主要来自模式,过去我曾见过和使用过的东西。我在交互式会话中做了很多实验。

举个例子:

In [273]: small_array = np.array(["a", "b"])
     ...: big_array = np.array(["a", "b", "c", "d"])
     ...: 
     ...: for i in range(len(small_array)):
     ...:     for p in range(len(big_array)):
     ...:         if small_array[i] == big_array[p]:
     ...:             print( "This item is matched: ", small_array[i])
     ...:             
This item is matched:  a
This item is matched:  b

我经常运行迭代案例只是为了明确(呃)想要什么。

In [274]: small_array
Out[274]: 
array(['a', 'b'],
      dtype='<U1')
In [275]: big_array
Out[275]: 
array(['a', 'b', 'c', 'd'],
      dtype='<U1')

我以前见过这个 - 迭代两个数组,并使用配对值做一些事情。这是一种outer操作。有各种各样的工具,但我最喜欢的工具使用numpy广播。它将一个数组转换为(n,1)数组,并将其与另一个(m,)数组一起使用

In [276]: small_array[:,None]
Out[276]: 
array([['a'],
       ['b']],
      dtype='<U1')

(1,m)运算的结果(n,1)是(n,m)数组:

In [277]: small_array[:,None]==big_array
Out[277]: 
array([[ True, False, False, False],
       [False,  True, False, False]], dtype=bool)

现在,我可以在任一轴上进行anyall缩减:

In [278]: _.all(axis=0)
Out[278]: array([False, False, False, False], dtype=bool)

In [280]: __.all(axis=1)
Out[280]: array([False, False], dtype=bool)

我还可以使用np.where将该布尔值减少为索引。

糟糕,我应该使用any

In [284]: (small_array[:,None]==big_array).any(0)
Out[284]: array([ True,  True, False, False], dtype=bool)
In [285]: (small_array[:,None]==big_array).any(1)
Out[285]: array([ True,  True], dtype=bool)

玩过这个我记得那里有in1d做类似的事情

In [286]: np.in1d(big_array, small_array)
Out[286]: array([ True,  True, False, False], dtype=bool)

但是,当我查看in1d的代码时(请参阅文档中的[source]链接),我看到,在某些情况下,它实际上会迭代小数组:

In [288]: for x in small_array:
     ...:     print(x==big_array)
     ...:     
[ True False False False]
[False  True False False]

将其与Out[277]进行比较。 x==big_array将标量与数组进行比较。在numpy中,使用数组和标量执行==+*之类的操作很容易,并且应该成为第二天性。下一步是对2个匹配形状的数组做同样的事情。从那里开始使用可播放的形状。

在其他情况下,它使用np.uniquenp.argsort

这种通过相互广播输入来创建更高维数组的模式,然后将值与某种减少(任意,全部,总和,平均等)相结合是很常见的。

答案 1 :(得分:1)

我将以更具体的方式解释您的问题:

  1. 如何退出使用索引变量?

  2. 如何开始编写列表推导而不是正常循环“?

  3. 要退出使用索引变量,关键是要理解Python中的“for”不是其他语言的“for”。它应该被称为“为每个人”。

    for x in small_array:
        for y in big_array:
            if x == y:
                print "This item is matched: ", x
    

    那好多了。

    我也发现自己处于可以用普通循环编写代码的情况下(或者实际上这样做),然后开始想知道列表理解是否更清晰,更优雅。

    列表推导实际上是一种用于创建列表的特定于域的语言,因此第一步是学习它的基础知识。典型的陈述是:

    l = [f(x) for x in list_expression if g(x)]
    

    含义“给出一个f(x)列表,列出符合条件g的list_expression中的所有x”

    所以你可以这样写:

    matched = [x for x in small_array if x in big_array]
    

    Et voilà,你正在走向pythonic风格!

答案 2 :(得分:1)

正如你所说,你最好使用矢量化的东西加快速度。学习它是一条漫长的道路。如果你还没有,你必须使用矩阵乘法。一旦你,尝试将你的数据转换成矩阵,看看你可以做多少乘法。通常你不能用这个做你想做的事情并且有超级矩阵(超过二维尺寸)。这就是numpy变得有用的地方。

Numpy提供了一些功能,如n = 37886; cell_array=cell(n,1); a = 1:n; for T=1:n-84 M=a(T:T+84); tmpstruct=struct('M',transpose(M)); % Modified line to transpose windows! cell_array{T}=tmpstruct; end ,知道如何使用它们。了解np.where等快捷方式。尝试将numpy函数与nativ pythons结合起来(map,filter ...)。

要处理多维矩阵,没有秘密,练习和使用纸张来理解你在做什么。但超过4个维度,它开始变得非常棘手。

答案 3 :(得分:0)

For循环不一定慢。由于matlab自身的错误,这是一个matlab无意义的时间传播。矢量化 “用于”循环但在较低级别。您需要了解您正在使用哪种数据和体系结构以及您正在对数据执行哪种功能。