如何用一个

时间:2016-09-08 11:29:14

标签: python arrays numpy

是否有一个简单的解决方案用两个NumPy子阵列替换单个子阵列,而entires是在两个前阵列的条目上调用函数的结果。

例如:

[1, a, b][1, c, d] -> [1, f_add, f_sub] 

使用:

f_add(a, b, c, d):
    return a + b + c + d

f_sub(b, d):
    return b-d

具体:

 [1, 0, 50], [1, 3, 1] -> [1, 54, 49]

作为补充,行[1, 0, 50], [1, 3, 1]是更大数组的一部分(示例中为第一行),因此应该就地替换

([[1, 0, 50], [2, 0, 50], [1, 3.0, 1.0]],
 [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]])


([[1, 54, 49], [2, 0, 50]],
 [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]])

谢谢!

修改

函数f_addf_sub只是示例,用于说明我想要做什么,以及条目的更改是调用函数的结果。 实际上,我使用稍微复杂的函数来执行(更有意义的)计算。

第二件事是,这种替换只应在第一个条目相同的元素上进行。 因此,在第一行中只有[1, 0. 50.][1, 3.0, 1.0]合并,而在第二行中,它将是[2, 0., 50.][2, 30, 1.0)

在这个例子中,我首先想要通过比较索引来分离确定哪些子数组要合并的问题,但我想它应该尽可能地包括在内。

上面的一个更完整的示例结果如下:

 ([[1, 0., 50.], [2, 0., 50], [1, 3.0, 1.0]],
 [[1, 0., 50.], [2, 0., 50.], [2, 3.0, 1.0]])

导致:

([[1, 54., 49.], [2, 0., 50.]],
 [[1, 0., 50.], [2, 54., 49.]])

3 个答案:

答案 0 :(得分:0)

您可以使用生成器表达式来获得此结果(假设数组的每个元素有三个子元素):

ar = ([[1, 0, 50], [2, 0, 50], [1, 3.0, 1.0]],
      [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]])
ar = tuple([[[x[0][0], sum(x[0][1:]) + sum(x[-1][1:]), x[0][-1]-x[-1][-1]], x[1]] for x in ar])
print ar
  

([[1,54.0,49.0],[2,0,50]],[[1,54.0,49.0],[2,0,50]]

编辑:也许对于更通用的解决方案,您可以定义一个函数f(x),它对数组的元素执行所需的计算,并将该函数映射到数组的每一行。例如,

def f(x):
    if (x[0][0] == x[1][0]):
        return [[x[0][0], x[0][1]+x[0][2]+x[1][1]+x[1][2], x[0][2]-x[1][2]], x[2]]
    elif (x[0][0] == x[2][0]):
        return [[x[0][0], x[0][1]+x[0][2]+x[2][1]+x[2][2], x[0][2]-x[2][2]], x[1]]
    elif (x[1][0] == x[2][0]):
        return [x[0], [x[1][0], x[1][1]+x[1][2]+x[2][1]+x[2][2], x[1][2]-x[2][2]]]
    else:
        return x

ar = ([[1, 0, 50], [2, 0, 50], [1, 3.0, 1.0]],
      [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]])

print tuple(map(f, ar))
  

([[1,54.0,49.0],[2,0,00]],[[1,0,50],[2,54.0,49.0]]

答案 1 :(得分:0)

如果你有很多函数在数组上工作,听起来好像很复杂。我会考虑将每一行分成一个类来更简洁地管理函数调用。例如,您可以包含类中的所有相关函数:

class Row:
    def __init__(self, row):
        self.row = row

        self.sum1 = None
        self.sub1 = None

        self._add(row)
        self._sub(row)

    def _add(self, items):
        self.sum1 = sum([items[0][1], items[0][2], items[-1][1], items[-1][2]])

    def _sub(self, items):
        self.sub1 = items[0][2] - items[-1][2]

    def update(self):
        self.row = [[self.row[0][0], self.sum1, self.sub1], self.row[1]]

# Data
arr = ([[1, 0, 50], [2, 0, 50], [1, 3.0, 1.0]],
 [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]])

# Usage
for row in arr:
    r = Row(row)
    print r.sum1, r.sub1

    r.update()
    print r.row



>>> 54.0 49.0
    [[1, 54.0, 49.0], [2, 0, 50]]
    54.0 49.0
    [[1, 54.0, 49.0], [2, 0, 50]]  # This row doesnt match your example, but you get the idea

答案 2 :(得分:0)

这是执行第一个(最内部)步骤的函数,假设2个输入是列表:

def merge(a,b):
    res = [a[0]]  # test b[0] is same?
    abcd = a[1:]+b[1:]   # list join  
    # use np.concatenate here is a,b are arrays
    res.append(f_add(*abcd))
    res.append(f_sum(a[2],b[2]))
    return res
def f_add(a,b,c,d):
    return a+b+c+d
def f_sum(b,d):
    return b-d

In [484]: merge([1,0,50],[1,3,1])
Out[484]: [1, 54, 49]

通过混合使用元素和一般函数,将这些作为数组处理没有多大意义。

然后编写一个函数来处理'row',列表中列出了具有相同x[0] id的列表。收集匹配对的最简单方法(只有对吗?)是defaultdict

所以我找到了对;并将它们与上述功能合并。

def subs(alist):
    # collect the matching ids
    from collections import defaultdict
    dd = defaultdict(list)
    for i,x in enumerate(alist):
        dd[x[0]].append(x)
    # merge pairs
    for i in dd.keys():
        if len(dd[i])==2:
           dd[i]=merge(dd[i][0],dd[i][1])
        elif len(dd[i])==1:
           dd[i]=dd[i][0]  # flatten
        else:
           pass  # do nothing with triplets etc.
    return list(dd.values())

In [512]: lll= [[[1, 0, 50], [2, 0, 50], [1, 3.0, 1.0]],
     ...:  [[1, 0, 50], [2, 0, 50], [2, 3.0, 1.0]]]

In [513]: [subs(l) for l in lll]
Out[513]: [[[1, 54.0, 49.0], [2, 0, 50]], 
           [[1, 0, 50], [2, 54.0, 49.0]]]

lll可以变成3d数组:

In [523]: arr=np.array(lll)
In [524]: arr
Out[524]: 
array([[[  1.,   0.,  50.],
        [  2.,   0.,  50.],
        [  1.,   3.,   1.]],

       [[  1.,   0.,  50.],
        [  2.,   0.,  50.],
        [  2.,   3.,   1.]]])

我们要混合和匹配的ID是:

In [525]: arr[:,:,0]
Out[525]: 
array([[ 1.,  2.,  1.],
       [ 1.,  2.,  2.]])

要合并的对是

In [526]: arr[0,[0,2],:]
Out[526]: 
array([[  1.,   0.,  50.],
       [  1.,   3.,   1.]])

和2次合并:

In [527]: merge(*arr[0,[0,2],:].tolist())
Out[527]: [1.0, 54.0, 49.0]
In [528]: merge(*arr[1,[1,2],:].tolist())
Out[528]: [2.0, 54.0, 49.0]

但是,识别这些对,并执行合并并构建新数组并不比使用列表更容易。

In [532]: np.array([subs(l.tolist()) for l in arr])
Out[532]: 
array([[[  1.,  54.,  49.],
        [  2.,   0.,  50.]],

       [[  1.,   0.,  50.],
        [  2.,  54.,  49.]]])