[英]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_add
和f_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.