根据另一个数组的值(未排序,但已分组),将NumPy数组拆分为子数组。

3
假设我有两个NumPy数组。
x = [[1, 2, 8],
     [2, 9, 1],
     [3, 8, 9],
     [4, 3, 5],
     [5, 2, 3],
     [6, 4, 7],
     [7, 2, 3],
     [8, 2, 2],
     [9, 5, 3],
     [10, 2, 3],
     [11, 2, 4]]
y = [0, 0, 1, 0, 1, 1, 2, 2, 2, 0, 0] 

注意: (x 中的值没有排序。我选择了这个例子来更好地说明这个例子) (这只是 xy 的两个例子。 xy 可以是任意多个不同的数字,而 y 可以有任意不同的数字,但在 x 中始终有与 y 中相同数量的值) 我希望能够根据 y 中的值有效地将数组 x 分成子数组。 我的期望输出将是:
z_0 = [[1, 2, 8],
       [2, 9, 1],
       [4, 3, 5],
       [10, 2, 3],
       [11, 2, 4]]
z_1 = [[3, 8, 9],
       [5, 2, 3],
       [6, 4, 7],]
z_2 = [[7, 2, 3],
       [8, 2, 2],
       [9, 5, 3]]

假设 y 以零开始,且未排序但已分组,最有效的方法是什么?
注意:此问题是这个问题的未排序版本: 按另一个数组的值(按升序排序)将NumPy数组拆分为子数组

1
你能用言语表达出期望的输出与y中数字序列的关系吗? - wwii
想象一下,x 是一个点云,y 是根据聚类算法对 x 中每个点的标签。z 将是原始点云 x 的所有聚类子点云。 - danielhe
3个回答

3

解决此问题的一种方法是为每个y值建立一个过滤器索引列表,然后简单地选择x的这些元素。例如:

z_0 = x[[i for i, v in enumerate(y) if v == 0]]
z_1 = x[[i for i, v in enumerate(y) if v == 1]]
z_2 = x[[i for i, v in enumerate(y) if v == 2]]

输出

array([[ 1,  2,  8],
       [ 2,  9,  1],
       [ 4,  3,  5],
       [10,  2,  3],
       [11,  2,  4]])
array([[3, 8, 9],
       [5, 2, 3],
       [6, 4, 7]])
array([[7, 2, 3],
       [8, 2, 2],
       [9, 5, 3]])

如果你想更加通用并支持不同的数字集合 y,你可以使用推导式生成一个数组列表,例如:
z = [x[[i for i, v in enumerate(y) if v == m]] for m in set(y)]

输出:

[array([[ 1,  2,  8],
       [ 2,  9,  1],
       [ 4,  3,  5],
       [10,  2,  3],
       [11,  2,  4]]),
 array([[3, 8, 9],
       [5, 2, 3],
       [6, 4, 7]]),
 array([[7, 2, 3],
       [8, 2, 2],
       [9, 5, 3]])]

如果y也是一个np.array并且与x长度相同,您可以简化为使用布尔索引:
z = [x[y==m] for m in set(y)]

输出结果与上面相同。

我应该补充一下,'y'可以包含任意数量的不同值。它们不必限于两个。 - danielhe
如果y中有20个不同的值,你期望的输出是什么?是20个不同的变量还是一个包含20个条目的列表? - Nick
我还应该补充一点,x中的三维值与y中的值一样多。 - danielhe
@danielhe 看一下我的修改,可能更有用 - Nick

1

只需使用列表推导和布尔索引

x = np.array(x)
y = np.array(y)

z = [x[y == i] for i in range(y.max() + 1)]

z
Out[]: 
[array([[ 1,  2,  8],
        [ 2,  9,  1],
        [ 4,  3,  5],
        [10,  2,  3],
        [11,  2,  4]]),
 array([[3, 8, 9],
        [5, 2, 3],
        [6, 4, 7]]),
 array([[7, 2, 3],
        [8, 2, 2],
        [9, 5, 3]])]

0

轻微变化。

from operator import itemgetter
label = itemgetter(1)

将隐含的信息与标签关联起来... (索引,标签)
y1 = [thing for thing in enumerate(y)]

按标签排序

y1.sort(key=label)

按标签分组并构建结果
import itertools
d = {}
for key,group in itertools.groupby(y1,label):
    d[f'z{key}'] = [x[i] for i,k in group]

Pandas解决方案:
>>> import pandas as pd
>>> >>> df = pd.DataFrame({'points':[thing for thing in x],'cat':y})
>>> z = df.groupby('cat').agg(list)
>>> z       
                                                points
cat
0    [[1, 2, 8], [2, 9, 1], [4, 3, 5], [10, 2, 3], ...
1                    [[3, 8, 9], [5, 2, 3], [6, 4, 7]]
2                    [[7, 2, 3], [8, 2, 2], [9, 5, 3]]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接