考虑矩阵M1
,为所有组合x,y
提供值。考虑分区f(x)->X
和分区g(y)->Y
。此外,请考虑对p(A)
个数字设置A
的操作max(A)
。
映射sum(A)
可用于从f,g
创建一个块矩阵M1
,其中映射到同一M2
的所有x
都相邻,所有X
都是一样的。
此矩阵y
为“集合”M2
的每个组合都有一个块。
现在,我想通过在每个块上分别应用X,Y
,将此矩阵M2
压缩到另一个矩阵M3
中。 p
的每个组合M3
都有一个值。
理想情况下,我想暂时使用X,Y
和M1
跳过M2
到f
的转换。
执行此类操作的最有效方法是什么?是否可以为其部署g
或numpy
?
特殊情况:实际上,在我的情况下,scipy
和x
是相同的,并且只有一个函数y
适用于它们。我只关心对角线下的f
部分。
答案 0 :(得分:3)
我能想到的最简单的方法,尽管可能不是最有效的(特别是如果你的矩阵很大),是将矩阵转换为一维数组,然后为分区提供相应的数组小组索引X
和Y
。然后,您可以按分区组索引进行分组,最后将矩阵重新构建回原始形式。
例如,如果你的矩阵是
>>> M1 = np.arange(25).reshape((5,5))
>>> M1
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
你的分区是
>>> def f(x):
... return np.array([1,1,1,2,2])[x]
>>> def g(y):
... return np.array([3,4,4,4,5])[y]
从那时起,有几种方法可以实现重塑和后续分组。您可以使用Pandas来执行此操作,例如,通过构造DataFrame
并使用其stack()
方法将所有行“堆叠”在一个列中的彼此之上,索引为他们原来的行和列索引。
>>> st = pd.DataFrame(M1).stack().to_frame('M1')
>>> st
M1
0 0 0
1 1
2 2
3 3
4 4
1 0 5
...
4 3 23
4 24
(为了便于阅读,我已截断输出,我相信如果你想查看它们的输出,你可以自己评估其余的这些例子。)然后你可以添加代表分区组索引的列:
>>> st['X'] = f(st.index.get_level_values(0))
>>> st['Y'] = g(st.index.get_level_values(1))
然后您可以按这些索引进行分组并应用您选择的聚合函数。
>>> stp = st.groupby(['X', 'Y']).agg(p)
您必须定义p
(或查找现有定义),以便它采用一维Numpy数组并返回单个数字。如果你想使用像sum()
这样的东西,你可以使用st.groupby(...).sum()
,因为Pandas内置了对它和其他一些标准函数的支持,但agg
是通用的,适用于任何您可以提供的缩减功能p
。
最后,unstack()
方法会将DataFrame转换回正确的2D“矩阵形式”,然后如果需要,可以使用as_matrix()
方法将其转换回纯Numpy数组
>>> M3 = stp.unstack().as_matrix()
>>> M3
array([[ 15, 63, 27],
[ 35, 117, 43]])
如果您不想引入Pandas,还有其他库可以执行相同的操作。例如,您可能会看numpy-groupies,但是当我写这篇文章时,它似乎只与Python 2兼容。但是我没有找到任何真正的二维分组库,如果你可能需要它正在使用非常大的矩阵,足够大,额外的2或3个副本会耗尽可用的内存。
答案 1 :(得分:1)
让M1
成为一个numpy n
x m
数组。您可以从确定您拥有的分区开始。 set构造函数删除重复的条目,但是任意命令它们。我对它们进行排序只是为了有一个明确定义的顺序:
xs = sorted(set(f(i) for i in range(n)))
ys = sorted(set(g(i) for i in range(m)))
要为每个X,Y
构建块矩阵,您可以使用numpy布尔索引以及网格构造帮助器ix_
来仅选择属于X
和{{1的行和列}}, 分别。最后,将Y
应用于选定的子矩阵:
p
分区from numpy import zeros, arange, ix_
ii, jj = arange(n), arange(m)
M3 = zeros((len(xs), len(ys)))
for k, X in enumerate(xs):
for l, Y in enumerate(ys):
M3[k,l] = p(M1[ix_(f(ii) == X, g(jj) == Y)])
和f
必须以元素方式应用于numpy数组才能使其正常工作。正如在另一个答案中提到的,可以使用g
装饰器来实现这一点。
举个例子:
numpy.vectorize
答案 2 :(得分:0)
几年后,我遇到了同样的问题,我认为,实现此目的的最佳解决方案如下:
M2 = np.zeros((n,m))
for i in range(n):
for j in range(m):
M2[i,j] = p(M1[f(x) == i, :][: , g(y) == j])
这假设f取[0,1,.. n-1]上的值,而g取[0,1 ... m-1]上的值
一个例子是
import numpy as np
M1 = np.random.random((4,6))
print(M1)
x = range(4)
y = range(6)
p = np.sum
def f(x):
return np.array([0,0,1,2])[x]
def g(y):
return np.array([0,1,1,0,1,0])[y]
n = 3 # number of elements in partition f
m = 2 # number of elements in partition g
M2 = np.zeros((n,m))
for i in range(n):
for j in range(m):
M2[i,j] = p(M1[f(x) == i, :][: , g(y) == j])
print(M2)
要使n和m自动化,可以使用len(set(f(x())))和len(set(g(y)))