如何将多个数组减少为一个?
How to reduce multiple arrays to one?
忽略我的数据结构,只给出一个包含多个 numpy 数组的列表(所有数组都完全相同 size/shape):
list[0] = [[0, 2, 0],
[1, 3, 0]]
list[1] = [[0, 0, 0],
[0, 0, 3]]
list[2] = [[5, 0, 0],
[0, 0, 0]]
我想将这个数组列表缩减为只有一个数组。零意味着没有价值。对于每个条目,应该采用唯一的给定值。没有重叠的值。对于给定位置,一个数组中始终只有一个分配值。
result: [[5, 2, 0]
[1, 3, 3]]
在我的例子中,我有一个字典,其中元组作为键,数组作为值。数组是布尔数组。每个字典条目代表一个特殊的通道,并且在一个特定位置只有一个字典条目具有值True
。
我现在想用字典键替换所有 True
值,并将该字典减少到只有一个数组。
例如(接近我的真实数据):
dict { (9, 2, 6): [[False, True],
[True, False]]
(1, 5, 8): [[True, False],
[False, True]] }
result: [[(1, 5, 8),(9, 2, 6)]
[(9, 2, 6),(1, 5, 8)]]
如何使用列表理解、numpy 函数 and/or map & reduce 来完成?
第一次尝试:
起初我以为我可以将我的 numpy 数组转换为 0 和 1 (.astype(np.float32)
),然后将这些数组与我的密钥相乘:
values_filled = [key_tuple * value_array for key_tuple, value_array in dict]
然后对所有数组求和:
final = reduce(lambda right, left: right + left, values_filled)
但这显然行不通,因为我的键是值的元组而不仅仅是数字。
我尝试归档的是做以下操作的相反操作:
{color: np.all(mask, axis=-1) for (color, mask) in
((color, segmentation == color) for color in colors) if mask.max()}
通过这个操作,我拍摄了一个分割图像并创建了一个具有预定义颜色的字典。 numpy 数组在颜色等于图像中该位置的颜色/等于字典的键的每个位置都有 True。
现在我想将这本字典缩小回图像(字典上有变化)。
这可以在没有任何花哨的情况下完成,只需使用旧的 for 循环和列表理解,然后枚举。我敢肯定那里有更好的衬垫或可以覆盖它的库,但这里有一个香草 Python 解决方案:
d = { (9, 2, 6): [[False, True],[True, False]],(1, 5, 8): [[True, False],[False, True]] }
new_list = []
for k,v in d.items():
if new_list:
for i, each in enumerate(v):
x = [k if z else new_list[i][j] for j,z in enumerate(each)]
new_list[i] = x
else:
for each in v:
new_list.append([k if x else x for x in each])
print(new_list) # [[(1, 5, 8), (9, 2, 6)], [(9, 2, 6), (1, 5, 8)]]
P.S。也谢谢你的努力。
这是一个 Numpythonic 方法:
arr = np.dstack((lst1, lst2, lst3)) # Create columns along the first axis
mask = arr.astype(bool) # create a mask from places that are nonzero
mask2 = (~mask).all(axis=-1) # another mask that gives rows that are all zero
mask[mask2] = [True, False, False] # Truthify one optional item in all-zero rows
result = arr[mask].reshape(lst1.shape) # get the desire items and reshape
演示:
In [135]: arr = np.dstack((lst1, lst2, lst3))
In [136]: arr
Out[136]:
array([[[0, 0, 5],
[2, 0, 0],
[0, 0, 0]],
[[1, 0, 0],
[3, 0, 0],
[0, 3, 0]]])
In [137]: mask = arr.astype(bool)
In [138]: mask2 = (~mask).all(axis=-1)
In [139]: mask[mask2] = [True, False, False]
In [140]: arr[mask].reshape(lst1.shape)
Out[140]:
array([[5, 2, 0],
[1, 3, 3]])
另一种 numpy
方法,如果你希望它成为一个普通的 numpy
数组:
import numpy as np
d = {(9, 2, 6): [[False, True],
[True, False]],
(1, 5, 8): [[True, False],
[False, True]]}
x = np.sum(np.reshape(k, (1,1,-1)) * np.array(v)[..., None] for k, v in d.items())
# x = np.sum(np.array(k)[None, None, :] * np.array(v)[..., None] for k, v in d.items()) # Alternative way
print(X)
# array([[[1, 5, 8],
# [9, 2, 6]],
# [[9, 2, 6],
# [1, 5, 8]]])
np.all(x == np.array([[(1, 5, 8),(9, 2, 6)], [(9, 2, 6),(1, 5, 8)]]))
# True
这基本上使用了您在问题中概述的方法,即用值乘以真值掩码。我刚刚添加了一个事实,即该值的内容是另一个(第三)维度,并使用 numpy
s 广播功能来实现这一点。
你问题的第一部分只需要一个数组总和:
In [167]: alist = [[[0, 2, 0],
...: [1, 3, 0]],[[0, 0, 0],
...: [0, 0, 3]],[[5, 0, 0],
...: [0, 0, 0]]]
...:
In [168]: alist
Out[168]: [[[0, 2, 0], [1, 3, 0]], [[0, 0, 0], [0, 0, 3]], [[5, 0, 0], [0, 0, 0]]]
In [169]: np.array(alist).shape
Out[169]: (3, 2, 3)
In [170]: np.array(alist).sum(axis=0)
Out[170]:
array([[5, 2, 0],
[1, 3, 3]])
这利用了 0 不影响总和并且没有任何重叠值这一事实。
您显然有第二个问题涉及布尔数组或掩码的字典。假设这与第一个问题有关,那么您只需要一种方法将这些掩码转换为第一个给出的数组(或列表)列表。
从字典开始,我们需要迭代键(或项)。我们可以使用相同的求和。经过一些实验后,我决定 I,J=np.where(v)
是将布尔掩码映射到目标数组的最简单方法:
In [200]: dd={ (9, 2, 6): [[False, True],
...: [True, False]],
...: (1, 5, 8): [[True, False],
...: [False, True]] }
...:
In [201]: arr = np.zeros((2,2,3),int)
In [202]: for k,v in dd.items():
...: I,J = np.where(v)
...: arr[I,J,:] += k
...:
In [203]: arr
Out[203]:
array([[[1, 5, 8],
[9, 2, 6]],
[[9, 2, 6],
[1, 5, 8]]])
最后一次迭代:
In [204]: k
Out[204]: (1, 5, 8)
In [205]: v
Out[205]: [[True, False], [False, True]]
In [206]: I,J=np.where(v)
In [207]: I,J
Out[207]: (array([0, 1]), array([0, 1]))
In [208]: arr[I,J,:]
Out[208]:
array([[1, 5, 8],
[1, 5, 8]])
忽略我的数据结构,只给出一个包含多个 numpy 数组的列表(所有数组都完全相同 size/shape):
list[0] = [[0, 2, 0],
[1, 3, 0]]
list[1] = [[0, 0, 0],
[0, 0, 3]]
list[2] = [[5, 0, 0],
[0, 0, 0]]
我想将这个数组列表缩减为只有一个数组。零意味着没有价值。对于每个条目,应该采用唯一的给定值。没有重叠的值。对于给定位置,一个数组中始终只有一个分配值。
result: [[5, 2, 0]
[1, 3, 3]]
在我的例子中,我有一个字典,其中元组作为键,数组作为值。数组是布尔数组。每个字典条目代表一个特殊的通道,并且在一个特定位置只有一个字典条目具有值True
。
我现在想用字典键替换所有 True
值,并将该字典减少到只有一个数组。
例如(接近我的真实数据):
dict { (9, 2, 6): [[False, True],
[True, False]]
(1, 5, 8): [[True, False],
[False, True]] }
result: [[(1, 5, 8),(9, 2, 6)]
[(9, 2, 6),(1, 5, 8)]]
如何使用列表理解、numpy 函数 and/or map & reduce 来完成?
第一次尝试:
起初我以为我可以将我的 numpy 数组转换为 0 和 1 (.astype(np.float32)
),然后将这些数组与我的密钥相乘:
values_filled = [key_tuple * value_array for key_tuple, value_array in dict]
然后对所有数组求和:
final = reduce(lambda right, left: right + left, values_filled)
但这显然行不通,因为我的键是值的元组而不仅仅是数字。
我尝试归档的是做以下操作的相反操作:
{color: np.all(mask, axis=-1) for (color, mask) in
((color, segmentation == color) for color in colors) if mask.max()}
通过这个操作,我拍摄了一个分割图像并创建了一个具有预定义颜色的字典。 numpy 数组在颜色等于图像中该位置的颜色/等于字典的键的每个位置都有 True。
现在我想将这本字典缩小回图像(字典上有变化)。
这可以在没有任何花哨的情况下完成,只需使用旧的 for 循环和列表理解,然后枚举。我敢肯定那里有更好的衬垫或可以覆盖它的库,但这里有一个香草 Python 解决方案:
d = { (9, 2, 6): [[False, True],[True, False]],(1, 5, 8): [[True, False],[False, True]] }
new_list = []
for k,v in d.items():
if new_list:
for i, each in enumerate(v):
x = [k if z else new_list[i][j] for j,z in enumerate(each)]
new_list[i] = x
else:
for each in v:
new_list.append([k if x else x for x in each])
print(new_list) # [[(1, 5, 8), (9, 2, 6)], [(9, 2, 6), (1, 5, 8)]]
P.S。也谢谢你的努力。
这是一个 Numpythonic 方法:
arr = np.dstack((lst1, lst2, lst3)) # Create columns along the first axis
mask = arr.astype(bool) # create a mask from places that are nonzero
mask2 = (~mask).all(axis=-1) # another mask that gives rows that are all zero
mask[mask2] = [True, False, False] # Truthify one optional item in all-zero rows
result = arr[mask].reshape(lst1.shape) # get the desire items and reshape
演示:
In [135]: arr = np.dstack((lst1, lst2, lst3))
In [136]: arr
Out[136]:
array([[[0, 0, 5],
[2, 0, 0],
[0, 0, 0]],
[[1, 0, 0],
[3, 0, 0],
[0, 3, 0]]])
In [137]: mask = arr.astype(bool)
In [138]: mask2 = (~mask).all(axis=-1)
In [139]: mask[mask2] = [True, False, False]
In [140]: arr[mask].reshape(lst1.shape)
Out[140]:
array([[5, 2, 0],
[1, 3, 3]])
另一种 numpy
方法,如果你希望它成为一个普通的 numpy
数组:
import numpy as np
d = {(9, 2, 6): [[False, True],
[True, False]],
(1, 5, 8): [[True, False],
[False, True]]}
x = np.sum(np.reshape(k, (1,1,-1)) * np.array(v)[..., None] for k, v in d.items())
# x = np.sum(np.array(k)[None, None, :] * np.array(v)[..., None] for k, v in d.items()) # Alternative way
print(X)
# array([[[1, 5, 8],
# [9, 2, 6]],
# [[9, 2, 6],
# [1, 5, 8]]])
np.all(x == np.array([[(1, 5, 8),(9, 2, 6)], [(9, 2, 6),(1, 5, 8)]]))
# True
这基本上使用了您在问题中概述的方法,即用值乘以真值掩码。我刚刚添加了一个事实,即该值的内容是另一个(第三)维度,并使用 numpy
s 广播功能来实现这一点。
你问题的第一部分只需要一个数组总和:
In [167]: alist = [[[0, 2, 0],
...: [1, 3, 0]],[[0, 0, 0],
...: [0, 0, 3]],[[5, 0, 0],
...: [0, 0, 0]]]
...:
In [168]: alist
Out[168]: [[[0, 2, 0], [1, 3, 0]], [[0, 0, 0], [0, 0, 3]], [[5, 0, 0], [0, 0, 0]]]
In [169]: np.array(alist).shape
Out[169]: (3, 2, 3)
In [170]: np.array(alist).sum(axis=0)
Out[170]:
array([[5, 2, 0],
[1, 3, 3]])
这利用了 0 不影响总和并且没有任何重叠值这一事实。
您显然有第二个问题涉及布尔数组或掩码的字典。假设这与第一个问题有关,那么您只需要一种方法将这些掩码转换为第一个给出的数组(或列表)列表。
从字典开始,我们需要迭代键(或项)。我们可以使用相同的求和。经过一些实验后,我决定 I,J=np.where(v)
是将布尔掩码映射到目标数组的最简单方法:
In [200]: dd={ (9, 2, 6): [[False, True],
...: [True, False]],
...: (1, 5, 8): [[True, False],
...: [False, True]] }
...:
In [201]: arr = np.zeros((2,2,3),int)
In [202]: for k,v in dd.items():
...: I,J = np.where(v)
...: arr[I,J,:] += k
...:
In [203]: arr
Out[203]:
array([[[1, 5, 8],
[9, 2, 6]],
[[9, 2, 6],
[1, 5, 8]]])
最后一次迭代:
In [204]: k
Out[204]: (1, 5, 8)
In [205]: v
Out[205]: [[True, False], [False, True]]
In [206]: I,J=np.where(v)
In [207]: I,J
Out[207]: (array([0, 1]), array([0, 1]))
In [208]: arr[I,J,:]
Out[208]:
array([[1, 5, 8],
[1, 5, 8]])