在Python中,有效地将一个列表的每个元素与另一个列表的每个元素相乘/相加/相除的方法

3
我想要将一个列表的每个元素与另一个列表的每个元素相乘。
lst1 = [1, 2, 1, 2]
lst2 = [2, 2, 2]

lst3 = []

for item in lst1:
    for i in lst2:
        rs = i * item
        lst3.append(rs)

这种方法是可行的,但在大型数据集中效率非常低下,循环可能需要很长时间才能完成。请注意,这两个列表的长度可能会有所不同。
我可以使用非内置数据结构。我查看了numpy,似乎有一种叫做广播的方法在ndarray中。我不确定是否应该采用这种方法。到目前为止,将数组与标量相乘的结果符合预期。
arr = np.arange(3)
arr * 2

这将返回:

array([0, 2, 4])

但是它与另一个数组的工作方式有些不同,我似乎无法实现上述功能。 我想这一定是一些简单的东西,但我目前似乎找不到需要的确切解决方案。 任何输入都将高度赞赏。 谢谢。
顺便说一下,有一个类似的Scheme问题,不考虑效率,在这里
编辑:感谢您的答案。 乘法有效,请参见Dval的答案。 然而,我也需要以完全相同的方式进行加法和可能的除法。 因此,我稍微更新了一下问题。
编辑:我可以直接使用numpy数组,因此不需要将列表转换为数组再转回来。

NumPy非常适合在数据上执行多个操作。将列表转换为ndarray并返回,会消耗大量的CPU资源。 - John La Rooy
无论你试图通过这样做来实现什么,都要尝试找到更好的方法来实现它。NumPy 最多只能产生一个常数因子的加速和常数因子的空间节省。通常有比取外积更好的方法。 - user2357112
我觉得说“使用外积不是最好的方法”并不是一个好建议,因为你并不知道用户的应用场景。有时候,没有比外积更好的方法,因为你需要的就是外积。 - Dval
@Dval: 外积的信息量非常低。它们往往相当乏味,就像矩形中所有坐标的巨大列表一样无聊。除非你正在编写库的外积函数,否则通常希望计算外积的某些函数,并且可以经常在不经过显式外积的情况下进行计算。至少,惰性表示可以节省大量存储空间。 - user2357112
3个回答

3
Numpy是一个好的选择,特别是numpy.outer,它返回每个元素的乘积作为矩阵。使用.flatten()将其压缩为一维。
import numpy
lst1 = numpy.array([1, 2, 1, 2])
lst2 = numpy.array([2, 2, 2])
numpy.outer(lst1, lst2).flatten()

针对更新后的问题,添加功能似乎以类似的方式工作:

numpy.add.outer(lst1, lst2).flatten()

谢谢。确实聪明,我会查看文档的。它如何处理其他操作,如除法、加法等? - chhantyal
外部特别是乘法。NumPy通常非常快(相对于其他Python选项,不涉及其他语言)。 - Dval

2

对于像这样的数组进行线性运算是 numpy 中非常重要的部分。一旦您定义了数组,对它们进行矩阵式的操作就变得容易而且相对快速。这包括外积和内(矩阵)积,以及逐个元素的操作。

例如:

In [133]: a=np.array([1,2,1,2])
In [134]: b=np.array([2,2,2])

您可以使用列表推导式来实现双重循环的功能:

In [135]: [i*j for i in a for j in b]
Out[135]: [2, 2, 2, 4, 4, 4, 2, 2, 2, 4, 4, 4]

使用广播的numpy乘积。可以将a[:,None]视为将a转换为列向量。
In [136]: a[:,None]*b
Out[136]: 
array([[2, 2, 2],
       [4, 4, 4],
       [2, 2, 2],
       [4, 4, 4]])

逐个元素的除法也可以实现

In [137]: a[:,None]/b
Out[137]: 
array([[ 0.5,  0.5,  0.5],
       [ 1. ,  1. ,  1. ],
       [ 0.5,  0.5,  0.5],
       [ 1. ,  1. ,  1. ]])

但是在组合操作时,这将更加有用。

将列表转换为数组会增加开销,因此我不建议将其用于小规模的偶发计算。


谢谢。我认为这是完整的答案 :) - chhantyal
还有numpy.ufunc.outer,有时可能被认为更易读。 - user2357112

1

使用numpy - 它是一个为复杂矩阵运算设计的库。

import numpy
lst1 = numpy.array([1, 2, 1, 2])
lst2 = numpy.array([2, 2, 2]]
numpy.outer(lst1, lst2)

1
是的,那看起来几乎就是 OP 想要的——我认为唯一剩下的事情就是将其(按正确顺序)展平以获得 OP 想要的精确结果。你可以通过 .ravel().flat 来完成这个操作,如果我没记错的话。 - mgilson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接