根据另一个数组的值(不是排序,而是分组)将 NumPy 数组拆分为子数组
Split a NumPy array into subarrays according to the values (not sorted, but grouped) of another array
假设我有两个 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
中的值没有以任何方式排序。我选择这个例子是为了更好地说明这个例子)
(这些只是 x
和 y
的两个例子。x
和 y
的值可以是任意多个不同的数字,而 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
从零开始,不排序而是分组,最有效的方法是什么?
注意:此问题是此问题的未排序版本:
解决这个问题的一种方法是为每个 y
值建立一个过滤器索引列表,然后简单地 select 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)]
输出同上
只需使用列表理解和布尔索引
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]])]
略有不同。
from operator import itemgetter
label = itemgetter(1)
将隐含信息与标签相关联... (index,label)
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]]
假设我有两个 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
中的值没有以任何方式排序。我选择这个例子是为了更好地说明这个例子)
(这些只是 x
和 y
的两个例子。x
和 y
的值可以是任意多个不同的数字,而 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
从零开始,不排序而是分组,最有效的方法是什么?
注意:此问题是此问题的未排序版本:
解决这个问题的一种方法是为每个 y
值建立一个过滤器索引列表,然后简单地 select 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)]
输出同上
只需使用列表理解和布尔索引
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]])]
略有不同。
from operator import itemgetter
label = itemgetter(1)
将隐含信息与标签相关联... (index,label)
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]]