在numpy中,常规的数据切片,根据轴来进行数据切分等,都很方便。但,如果要根据矩阵中的值来切分数组,并新建一个维度,这个还是有点麻烦。记录过程如下:
有这么一个数组:
import numpy as np
rs = [
[1, 23, 87],
[2, 34, 98],
[3, 32, 73],
[4, 76, 74],
[5, 54, 11],
[6, 65, 76],
[7, 87, 29],
[8, 43, 62],
[9, 54, 36]
]
ndarray = np.array(rs)
我希望,根据第1列的值,增加一个轴,最终拆分成 【x<=3】【3<x<=6】【6<x】三个区间,然后再汇总这三个区间的合计值。
我先切出矩阵的第一列,其他维度不变:
filter_nda = ndarray[:, [0]]
filter_nda
array([[1],
[2],
[3],
[4],
[5],
[6],
[7],
[8],
[9]])
做筛选索引:
where_1 = np.where(filter_nda<=3)
Out: (array([0, 1, 2]), array([0, 0, 0]))
# 当 where 中有多个条件表达式时,每个表达式都必须用括号括起来
where_2 = np.where((filter_nda>3) & (filter_nda<=6))
out:(array([3, 4, 5]), array([0, 0, 0]))
where_3 = np.where(filter_nda>6)
Out: (array([6, 7, 8]), array([0, 0, 0]))
三个区间,所有是三个表达式,看输出,(array([6, 7, 8]), array([0, 0, 0])),可以看到这是numpy中的整数数组索引,代表了三个坐标位置。
为什么第二个数组都是[0,0,0],因为这里只有一列,所以不重要,重要的是前面的其他维度的索引值。
下一步,就是根据这三个索引,构建三个新的矩阵,因为,引入了一个新的维度,所以,新的矩阵要多出一维。
section_1 = np.zeros(ndarray.shape, dtype=np.int32)
section_1 = np.expand_dims(section_1, 0) #在 0 轴插入一个新维度
section_2 = np.zeros(ndarray.shape, dtype=np.int32)
section_2 = np.expand_dims(section_2, 0) #在 0 轴插入一个新维度
section_3 = np.zeros(ndarray.shape, dtype=np.int32)
section_3 = np.expand_dims(section_3, 0) #在 0 轴插入一个新维度
对比一下两个矩阵的 shape
ndarray.shape
Out[165]: (9, 3)
section_1.shape
Out[166]: (1, 9, 3)
好了,下面有一个有意思的操作,根据其他维度的索引值,把所有数据复制到新的矩阵
for y in range(3): # 原矩阵的第1轴有3个数据
for x in range(len(where_1[0])): # 原矩阵的第0轴的索引数组
section_1[0, where_1[0][x], y] = ndarray[where_1[0][x], y] #复制数据
因为,直接切出来,会丧失维度信息,只好手功复制了。看一下结果:
section_1
Out[170]:
array([[[ 1, 23, 87],
[ 2, 34, 98],
[ 3, 32, 73],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0]]], dtype=int32)
果然,只复制出第一个区间的数据。同样生成第二、三区间的矩阵(section_2, section_3)
剩下的就简单了。把三个矩阵,延着第 0 轴,连接起来就可以了。
new_ndarray = np.concatenate([section_1, section_2, section_3], axis=0)
看一下,因为在原来的结构上,新增一个维度,数据还是那些数据。多出的 0 是必要的,因为维度结构被保留了。随着维度的增加,存贮空间是指数级增长的。
new_ndarray
Out[187]:
array([[[ 1, 23, 87],
[ 2, 34, 98],
[ 3, 32, 73],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0]],
[[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 4, 76, 74],
[ 5, 54, 11],
[ 6, 65, 76],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0]],
[[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 7, 87, 29],
[ 8, 43, 62],
[ 9, 54, 36]]], dtype=int32)
好,我们按新的维度,延着第 1 轴来汇总一下数据:
np.sum(new_ndarray, axis=1)
Out[189]:
array([[ 6, 89, 258],
[ 15, 195, 161],
[ 24, 184, 127]])
三行,分别是三个区间的汇总值。
真的有点意思。
更多的维度也是一样的,在代码上要做自适应的处理,这里演示的是单步手动执行的代码。自适应多维的矩阵的代码会更复杂一些。
如果有谁有其他的更好方法,请务必告知我。深表感谢。