簡體   English   中英

如何用一個替換兩個NumPy子數組

[英]How to substitute two NumPy subarrays with a single one

是否有一個簡單的解決方案將兩個NumPy子數組替換為一個子數組,而整體是對兩個前一個數組的條目調用函數的結果。

例如:

[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.]])

您可以使用生成器表達式獲取此結果(假設數組的每個元素都有三個子元素):

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,50]],[[1,0,50],[2,54.0,49.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

假設兩個輸入是列表,這是執行第一步(最內部)的功能:

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]

通過元素和通用函數的這種混合使用,將它們視為數組沒有太多意義。

然后編寫一個處理“行”的函數,將合並具有相同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.]]])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM