Python 将函数应用于元组数组

Python 将函数应用于元组数组,python,arrays,numpy,vector,Python,Arrays,Numpy,Vector,我有一个函数,我想应用于元组数组,我想知道是否有一种干净的方法来实现它 通常,我可以使用np.vectorize将函数应用于数组中的每个项,但是,在这种情况下,“每个项”是一个元组,因此numpy将数组解释为一个3d数组,并将函数应用于元组中的每个项 因此,我可以假设传入阵列是以下阵列之一: 元组 一维元组数组 二维元组数组 我可能可以编写一些循环逻辑,但它似乎最有可能具有更高效的功能,我不想重新发明轮子 这是一个例子。我试图将tuple\u converter函数应用于数组中的每个元组 arr

我有一个函数,我想应用于元组数组,我想知道是否有一种干净的方法来实现它

通常,我可以使用
np.vectorize
将函数应用于数组中的每个项,但是,在这种情况下,“每个项”是一个元组,因此numpy将数组解释为一个3d数组,并将函数应用于元组中的每个项

因此,我可以假设传入阵列是以下阵列之一:

  • 元组
  • 一维元组数组
  • 二维元组数组
  • 我可能可以编写一些循环逻辑,但它似乎最有可能具有更高效的功能,我不想重新发明轮子

    这是一个例子。我试图将
    tuple\u converter
    函数应用于数组中的每个元组

    array_of_tuples1 = np.array([
            [(1,2,3),(2,3,4),(5,6,7)],
            [(7,2,3),(2,6,4),(5,6,6)],
            [(8,2,3),(2,5,4),(7,6,7)],
        ])
    
    array_of_tuples2 = np.array([
            (1,2,3),(2,3,4),(5,6,7),
        ])
    
    plain_tuple = (1,2,3)
    
    
    
    # Convert each set of tuples
    def tuple_converter(tup):
        return tup[0]**2 + tup[1] + tup[2]
    
    # Vectorizing applies the formula to each integer rather than each tuple
    tuple_converter_vectorized = np.vectorize(tuple_converter)
    
    print(tuple_converter_vectorized(array_of_tuples1))
    print(tuple_converter_vectorized(array_of_tuples2))
    print(tuple_converter_vectorized(plain_tuple))
    
    元组1的数组的所需输出:

    [[ 6 11 38]
     [54 14 37]
     [69 13 62]]
    
    元组2的数组的所需输出:

    [ 6 11 38]
    
    普通元组的所需输出:

    6
    
    但是上面的代码会产生此错误(因为它试图将函数应用于整数而不是元组)

    in-tuple\u转换器(tup)
    10
    11 def元组转换器(tup):
    --->12返回tup[0]**2+tup[1]+tup[2]
    13
    14
    索引器错误:标量变量的索引无效。
    
    元组数组1和元组数组2实际上不是元组数组,而是三维和二维整数数组:

    In [1]: array_of_tuples1 = np.array([
       ...:         [(1,2,3),(2,3,4),(5,6,7)],
       ...:         [(7,2,3),(2,6,4),(5,6,6)],
       ...:         [(8,2,3),(2,5,4),(7,6,7)],
       ...:     ])
    
    In [2]: array_of_tuples1
    Out[2]: 
    array([[[1, 2, 3],
            [2, 3, 4],
            [5, 6, 7]],
    
           [[7, 2, 3],
            [2, 6, 4],
            [5, 6, 6]],
    
           [[8, 2, 3],
            [2, 5, 4],
            [7, 6, 7]]])
    
    因此,与其对函数进行矢量化,因为它将基本上通过数组的元素(整数)进行for循环,您应该(元组的轴)而不关心序列的类型:

    In [6]: np.apply_along_axis(tuple_converter, 2, array_of_tuples1)
    Out[6]: 
    array([[ 6, 11, 38],
           [54, 14, 37],
           [69, 13, 62]])
    
    In [9]: np.apply_along_axis(tuple_converter, 1, array_of_tuples2)
    Out[9]: array([ 6, 11, 38])
    
    _tuples1的数组_和_tuples2的数组_实际上不是元组数组,而是三维和二维整数数组:

    In [1]: array_of_tuples1 = np.array([
       ...:         [(1,2,3),(2,3,4),(5,6,7)],
       ...:         [(7,2,3),(2,6,4),(5,6,6)],
       ...:         [(8,2,3),(2,5,4),(7,6,7)],
       ...:     ])
    
    In [2]: array_of_tuples1
    Out[2]: 
    array([[[1, 2, 3],
            [2, 3, 4],
            [5, 6, 7]],
    
           [[7, 2, 3],
            [2, 6, 4],
            [5, 6, 6]],
    
           [[8, 2, 3],
            [2, 5, 4],
            [7, 6, 7]]])
    
    因此,与其对函数进行矢量化,因为它将基本上通过数组的元素(整数)进行for循环,您应该(元组的轴)而不关心序列的类型:

    In [6]: np.apply_along_axis(tuple_converter, 2, array_of_tuples1)
    Out[6]: 
    array([[ 6, 11, 38],
           [54, 14, 37],
           [69, 13, 62]])
    
    In [9]: np.apply_along_axis(tuple_converter, 1, array_of_tuples2)
    Out[9]: array([ 6, 11, 38])
    

    上面的另一个答案肯定是正确的,而且可能是您正在寻找的答案。但是我注意到你在你的问题中加入了“干净”这个词,所以我也想补充这个答案

    如果我们可以假设所有元组都是
    3
    元素元组(或者它们有一些固定数量的元素),那么有一个很好的小技巧可以让同一段代码在任何单个元组、1d元组数组或2d元组数组上工作,而对于1d/2d情况,没有If/else。我认为避免开关总是更干净的(尽管我认为这可能是有争议的)

    根据需要(分别)为您的输入输出以下内容:

    [[ 6 11 38]
     [54 14 37]
     [69 13 62]]
    
    [ 6 11 38]
    
    6
    

    上面的另一个答案肯定是正确的,而且可能是您正在寻找的答案。但是我注意到你在你的问题中加入了“干净”这个词,所以我也想补充这个答案

    如果我们可以假设所有元组都是
    3
    元素元组(或者它们有一些固定数量的元素),那么有一个很好的小技巧可以让同一段代码在任何单个元组、1d元组数组或2d元组数组上工作,而对于1d/2d情况,没有If/else。我认为避免开关总是更干净的(尽管我认为这可能是有争议的)

    根据需要(分别)为您的输入输出以下内容:

    [[ 6 11 38]
     [54 14 37]
     [69 13 62]]
    
    [ 6 11 38]
    
    6
    

    如果认真对待
    元组
    位,可以定义结构化数据类型

    In [535]: dt=np.dtype('int,int,int')
    
    In [536]: x1 = np.array([
            [(1,2,3),(2,3,4),(5,6,7)],
            [(7,2,3),(2,6,4),(5,6,6)],
            [(8,2,3),(2,5,4),(7,6,7)],
        ], dtype=dt)
    
    In [537]: x1
    Out[537]: 
    array([[(1, 2, 3), (2, 3, 4), (5, 6, 7)],
           [(7, 2, 3), (2, 6, 4), (5, 6, 6)],
           [(8, 2, 3), (2, 5, 4), (7, 6, 7)]], 
          dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
    
    它适用于
    x1

    In [539]: foo(x1)
    Out[539]: 
    array([[ 6, 11, 38],
           [54, 14, 37],
           [69, 13, 62]])
    
    它也适用于相同数据类型的1d数组

    In [540]: x2=np.array([(1,2,3),(2,3,4),(5,6,7) ],dtype=dt)
    
    In [541]: foo(x2)
    Out[541]: array([ 6, 11, 38])
    
    和匹配类型的0d数组:

    In [542]: foo(np.array(plain_tuple,dtype=dt))
    Out[542]: 6
    
    但是
    foo(plain\u tuple)
    不起作用,因为该函数是为使用命名字段而编写的,而不是索引字段

    如果需要,可以修改该函数以将输入转换为正确的数据类型:

    In [545]: def foo1(tup):
        temp = np.asarray(tup, dtype=dt)
       .....:     return temp['f0']**2 + temp['f1'] + temp['f2']
    
    In [548]: plain_tuple
    Out[548]: (1, 2, 3)
    
    In [549]: foo1(plain_tuple) 
    Out[549]: 6
    
    In [554]: foo1([(1,2,3),(2,3,4),(5,6,7)])  # list of tuples
    Out[554]: array([ 6, 11, 38])
    

    如果认真对待
    元组
    位,可以定义结构化数据类型

    In [535]: dt=np.dtype('int,int,int')
    
    In [536]: x1 = np.array([
            [(1,2,3),(2,3,4),(5,6,7)],
            [(7,2,3),(2,6,4),(5,6,6)],
            [(8,2,3),(2,5,4),(7,6,7)],
        ], dtype=dt)
    
    In [537]: x1
    Out[537]: 
    array([[(1, 2, 3), (2, 3, 4), (5, 6, 7)],
           [(7, 2, 3), (2, 6, 4), (5, 6, 6)],
           [(8, 2, 3), (2, 5, 4), (7, 6, 7)]], 
          dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
    
    它适用于
    x1

    In [539]: foo(x1)
    Out[539]: 
    array([[ 6, 11, 38],
           [54, 14, 37],
           [69, 13, 62]])
    
    它也适用于相同数据类型的1d数组

    In [540]: x2=np.array([(1,2,3),(2,3,4),(5,6,7) ],dtype=dt)
    
    In [541]: foo(x2)
    Out[541]: array([ 6, 11, 38])
    
    和匹配类型的0d数组:

    In [542]: foo(np.array(plain_tuple,dtype=dt))
    Out[542]: 6
    
    但是
    foo(plain\u tuple)
    不起作用,因为该函数是为使用命名字段而编写的,而不是索引字段

    如果需要,可以修改该函数以将输入转换为正确的数据类型:

    In [545]: def foo1(tup):
        temp = np.asarray(tup, dtype=dt)
       .....:     return temp['f0']**2 + temp['f1'] + temp['f2']
    
    In [548]: plain_tuple
    Out[548]: (1, 2, 3)
    
    In [549]: foo1(plain_tuple) 
    Out[549]: 6
    
    In [554]: foo1([(1,2,3),(2,3,4),(5,6,7)])  # list of tuples
    Out[554]: array([ 6, 11, 38])
    

    这里出现了一个小的“X-Y”问题-您能给出一个所需输出的示例吗?很好,我将把它添加到示例中,如果第一和第二种情况下所需输出的第一行是
    [6 11,38]
    (其他行也会不同)?您希望函数映射每个元组,对吗?不是跨元组的吗?是的,我把它搞糟了,我正在努力修复它。很抱歉搞混了:/没问题,慢慢来,只是想澄清一下:)。这里出现了一个小的“X-Y”问题-你能给出一个你想要的输出的例子吗?很好,我会把它添加到示例中。如果第一和第二种情况下想要的输出的第一行是
    [6 11,38]
    (其他行也会不同)?您希望函数映射每个元组,对吗?不是跨元组的吗?是的,我把它搞糟了,我正在努力修复它。抱歉搞混了:/没问题,慢慢来,我只是想说清楚:)。这太棒了。我甚至在文档中查看了这个函数,并认为它不是我所需要的。获得第二个意见总是很好;)这太棒了。我甚至在文档中查看了这个函数,并认为它不是我所需要的。获得第二个意见总是很好;)这是一个有趣的方法。我想也可以用同样的方式使用
    沿轴应用()。像你一样将输入包装在一个数组中,并沿最后一个轴应用(0表示普通元组输入)。哈哈!我会尽一切努力避免一个switch语句:p这是一个有趣的方法。可以使用
    沿轴应用()