为了很好地处理类别变量,matlab的dummyvar函数的pythonic等价物是什么?
这是一个说明我的问题的例子,其中NxM矩阵表示将N个数据点划分为< = N个类别的M种不同方式。
>> partitions
array([[1, 1, 2, 2, 1, 2, 2, 2, 1, 1],
[1, 2, 2, 1, 2, 1, 2, 2, 2, 1],
[1, 1, 1, 2, 2, 2, 1, 3, 3, 2]])
任务是有效地计算任意两个数据点被分类到相同类别的次数,并将结果存储在NxN矩阵中。在matlab中,这可以作为带有dummyvar的单行来完成,它为每个分区的每个类别创建一个列变量。
>> dummyvar(partitions)*dummyvar(partitions)'
ans =
3 2 1 1 1 1 1 0 1 2
2 3 2 0 2 0 2 1 2 1
1 2 3 1 1 1 3 2 1 0
1 0 1 3 1 3 1 1 0 2
1 2 1 1 3 1 1 1 2 2
1 0 1 3 1 3 1 1 0 2
1 2 3 1 1 1 3 2 1 0
0 1 2 1 1 1 2 3 2 0
1 2 1 0 2 0 1 2 3 1
2 1 0 2 2 2 0 0 1 3
我能想到解决这个任务的最有效方法是编写一个模拟dummyvar行为的O(n * m)循环。 (请注意,下面的代码更喜欢partition.shape[0]
<< partition.shape[1]
,这通常可能是正确的,但假设是不安全的。
dv=np.zeros((0,10))
for row in partitions:
for val in xrange(1,np.max(row)+1):
dv=np.vstack((dv,row==val))
np.dot(dv.T,dv)
当然因为循环中的vstack非常低效,所以可以通过找到所需的大小并创建数组开始来改进,但我真的在寻找一个单独的衬里,就像在matlab中一样。< / p>
编辑:有关我正在做的事情的更多信息,仅用于添加上下文。我在python中编写库函数(不存在python实现),用于分析大脑网络的库。现有的工作matlab源是可用的。由于特定于域的约束,输入的大致最大尺寸是几千个节点的网络。但是,基本上我编写的所有函数都必须很好地扩展到大输入。
答案 0 :(得分:5)
你可以做一点广播魔术来快速获得你的虚拟阵列:
>>> partitions = np.array([[1, 1, 2, 2, 1, 2, 2, 2, 1, 1],
... [1, 2, 2, 1, 2, 1, 2, 2, 2, 1],
... [1, 1, 1, 2, 2, 2, 1, 3, 3, 2]])
>>> n = np.max(partitions)
>>> d = (partitions.T[:, None, :] == np.arange(1, n+1)[:, None]).astype(np.int)
>>> d = d.reshape(partitions.shape[1], -1)
>>> d.dot(d.T)
array([[3, 2, 1, 1, 1, 1, 1, 0, 1, 2],
[2, 3, 2, 0, 2, 0, 2, 1, 2, 1],
[1, 2, 3, 1, 1, 1, 3, 2, 1, 0],
[1, 0, 1, 3, 1, 3, 1, 1, 0, 2],
[1, 2, 1, 1, 3, 1, 1, 1, 2, 2],
[1, 0, 1, 3, 1, 3, 1, 1, 0, 2],
[1, 2, 3, 1, 1, 1, 3, 2, 1, 0],
[0, 1, 2, 1, 1, 1, 2, 3, 2, 0],
[1, 2, 1, 0, 2, 0, 1, 2, 3, 1],
[2, 1, 0, 2, 2, 2, 0, 0, 1, 3]])
明显的缺点是,即使一行只有几个不同的值,我们创建的虚拟数组也会为具有最多值的行所需的行提供尽可能多的列。但除非你有庞大的阵列,否则它可能会比任何其他方法更快。
好吧,如果您正在使用可扩展的解决方案,那么您希望为您的虚拟矩阵使用稀疏数组。如果您不熟悉CSR稀疏格式的详细信息,则可能难以遵循以下代码:
import scipy.sparse as sps
def sparse_dummyvar(partitions):
num_rows = np.sum(np.max(partitions, axis=1))
nnz = np.prod(partitions.shape)
as_part = np.argsort(partitions, axis=1)
# You could get s_part from the indices in as_part, left as
# an exercise for the reader...
s_part = np.sort(partitions, axis=1)
mask = np.hstack(([[True]]*len(items_per_row),
s_part[:, :-1] != s_part[:, 1:]))
indptr = np.where(mask.ravel())[0]
indptr = np.append(indptr, nnz)
return sps.csr_matrix((np.repeat([1], nnz), as_part.ravel(), indptr),
shape=(num_rows, partitions.shape[1],))
这将返回dummyvar(partitions)
的转置。只需调用csc_matrix
而不是csr_matrix
并交换形状值,就可以在不进行转置的情况下获取数组。但是因为你只是在矩阵的产品之后使用它的转置,并且scipy在乘法之前将所有内容转换为CSR格式,所以它可能会稍微快一些。你现在可以这样做:
>>> dT = sparse_dummyvar(partitions)
>>> dT.T.dot(dT)
<10x10 sparse matrix of type '<type 'numpy.int32'>'
with 84 stored elements in Compressed Sparse Column format>
>>> dT.T.dot(dT).A
array([[3, 2, 1, 1, 1, 1, 1, 0, 1, 2],
[2, 3, 2, 0, 2, 0, 2, 1, 2, 1],
[1, 2, 3, 1, 1, 1, 3, 2, 1, 0],
[1, 0, 1, 3, 1, 3, 1, 1, 0, 2],
[1, 2, 1, 1, 3, 1, 1, 1, 2, 2],
[1, 0, 1, 3, 1, 3, 1, 1, 0, 2],
[1, 2, 3, 1, 1, 1, 3, 2, 1, 0],
[0, 1, 2, 1, 1, 1, 2, 3, 2, 0],
[1, 2, 1, 0, 2, 0, 1, 2, 3, 1],
[2, 1, 0, 2, 2, 2, 0, 0, 1, 3]])