创建稀疏零均值随机矩阵
Create a Sparse Zero Mean Random Matrix
有没有人有创建稀疏矩阵的经验,非零值遵循 [-0.5, 0.5] 的均匀分布并且在 python 中具有零均值(零中心)(例如使用 Scipy.sparse)?
我知道 scipy.sparse 包提供了一些创建随机稀疏矩阵的方法,比如 'rand' 和 'random'。但是我无法用这些方法实现我想要的。例如,我试过:
import numpy as np
import scipy.sparse as sp
s = np.random.uniform(-0.5,0.5)
W=sp.random(1024, 1024, density=0.01, format='csc', data_rvs=s)
具体说明我的想法:
假设我想要上面提到的非稀疏矩阵或密集矩阵,我将通过以下方式创建它:
dense=np.random.rand(1024,1024)-0.5
'np.random.rand(1024,1024)' 将创建一个密集的均匀矩阵,其值在 [0,1] 中。为了使其均值为零,我通过减去 0.5 来使矩阵居中。
但是,如果我创建一个稀疏矩阵,假设:
sparse=sp.rand(1024,1024,density=0.01, format='csc')
矩阵将在统一 [0,1] 中具有非零值。但是,如果我想使矩阵居中,我不能简单地执行 'sparse-=0.5' 这将导致所有最初为零的条目在减法后都为非零。
那么,对于稀疏矩阵上的密集矩阵,我该如何实现与上述示例相同的效果?
感谢大家的帮助!
data_rvs
参数期望 "callable" 需要一个大小。这在文档中并不十分明显。这可以使用 lambda 来完成,如下所示:
import numpy as np
import scipy.sparse as sp
W = sp.random(1024, 1024, density=0.01, format='csc',
data_rvs=lambda s: np.random.uniform(-0.5, 0.5, size=s))
然后 print(W)
给出:
(243, 0) -0.171300809713
(315, 0) 0.0739590145626
(400, 0) 0.188151369316
(440, 0) -0.187384896218
: :
(1016, 0) 0.29262088084
(156, 1) -0.149881296136
(166, 1) -0.490405135834
(191, 1) 0.188167190147
(212, 1) 0.0334533020488
: :
(411, 1) 0.122330200832
(431, 1) -0.0494334160833
(813, 1) -0.0076379249885
(828, 1) 0.462807265425
: :
(840, 1021) 0.456423017883
(12, 1022) -0.47313075329
: :
(563, 1022) -0.477190349161
(655, 1022) -0.460942546313
(673, 1022) 0.0930207181126
(676, 1022) 0.253643616387
: :
(843, 1023) 0.463793903168
(860, 1023) 0.454427252782
对于新手来说,lambda 可能看起来很奇怪 - 这只是一个未命名的函数。 sp.random
函数接受一个可选参数 data_rvs
,默认为 None
。指定后,它应该是一个函数,它接受一个大小参数和 returns 个随机数。执行此操作的一个简单函数是:
def generate_n_uniform_randoms(n):
return np.uniform(-0.5, 0.5, n)
我不知道 API 的来源,但不需要形状,因为 sp.random
大概首先弄清楚哪些索引将是非零的,然后它只需要计算这些索引的随机值,这是一组已知大小。
lambda 只是语法糖,它允许我们根据其他函数调用定义内联函数。我们可以改写
W = sp.random(1024, 1024, density=0.01, format='csc',
data_rvs=generate_n_uniform_randoms)
实际上,这可以是一个 "callable" - 一些对象 f
,其中 f(n)
returns n
个随机变量。这可以是一个函数,但也可以是实现 __call__(self, n)
函数的 class 的对象。例如:
class ufoo(object):
def __call__(self, n):
import numpy
return numpy.random.uniform(-0.5, 0.5, n)
W = sp.random(1024, 1024, density=0.01, format='csc',
data_rvs=ufoo())
如果您需要均值恰好为零(当然在舍入范围内),这可以通过从非零值中减去均值来完成,正如我上面提到的:
W.data -= np.mean(W.data)
然后:
W[idx].mean()
-2.3718641632430623e-18
在我看来,您的要求仍然不完整(见下文提到的缺点)。
下面是我在评论中概述的简单构造的一些实现:
import numpy as np
import scipy.sparse as sp
M, N, NNZ = 5, 5, 10
assert NNZ % 2 == 0
flat_dim = M*N
valuesA = np.random.uniform(-0.5, 0.5, size=NNZ // 2)
valuesB = valuesA * -1
values = np.hstack((valuesA, valuesB))
positions_flat = np.random.choice(flat_dim, size=NNZ, replace=False)
positions_2d = np.unravel_index(positions_flat, dims=(M, N))
mat = sp.coo_matrix((values, (positions_2d[0], positions_2d[1])), shape=(M, N))
print(mat.todense())
print(mat.data.mean())
输出:
[[ 0. 0. 0. 0.0273862 0. ]
[-0.3943963 0. 0. -0.04134932 0. ]
[-0.10121743 0. -0.0273862 0. 0.04134932]
[ 0.3943963 0. 0. 0. 0. ]
[-0.24680983 0. 0.24680983 0.10121743 0. ]]
0.0
优势
- 稀疏
- 零均值
- 来自均匀分布的条目
潜在劣势:
- 对于矩阵中的每个值 x,都可以在某处找到 -x!
- 意思是:在更广泛的联合分布意义上它是不均匀的
- 如果那是伤害只有你能说
- 如果是:可以轻松修改上述构造以使用来自某个分布的任何居中值,因此您的问题会分解为这个稍微小一点(但不一定更容易的问题)
现在关于那个相关的问题:我在这里猜测,但我不会惊讶地看到使用约束 mean(x)=0
统一采样 x
值是 NP-hard。
请记住,正如另一个答案中所建议的那样,非零值的后验居中会改变基础分布(即使对于 simple distributions)。在某些情况下甚至使边界无效(离开间隔 -0.5, 0.5)。
这意味着:这个问题是关于形式化 objective 有多重要 并以某种方式平衡它们。
sparse.random
做了两件事 - 随机分布非零值,并生成随机统一值。
In [62]: M = sparse.random(10,10,density=.2, format='csr')
In [63]: M
Out[63]:
<10x10 sparse matrix of type '<class 'numpy.float64'>'
with 20 stored elements in Compressed Sparse Row format>
In [64]: M.data
Out[64]:
array([ 0.42825407, 0.51858978, 0.8084335 , 0.08691635, 0.13210409,
0.61288928, 0.39675205, 0.58242891, 0.5174367 , 0.57859824,
0.48812484, 0.13472883, 0.82992478, 0.70568697, 0.45001632,
0.52147305, 0.72943809, 0.55801913, 0.97018861, 0.83236235])
您可以在不改变稀疏分布的情况下廉价地修改 data
值:
In [65]: M.data -= 0.5
In [66]: M.A
Out[66]:
array([[ 0. , 0. , 0. , -0.07174593, 0. ,
0. , 0. , 0. , 0. , 0. ],
[ 0.01858978, 0. , 0. , 0.3084335 , -0.41308365,
0. , 0. , 0. , 0. , -0.36789591],
[ 0. , 0. , 0. , 0. , 0.11288928,
-0.10324795, 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0.08242891, 0.0174367 , 0. ],
[ 0. , 0. , 0.07859824, 0. , 0. ,
0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. ,
0. , -0.01187516, 0. , 0. , -0.36527117],
[ 0. , 0. , 0.32992478, 0. , 0. ,
0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0.20568697,
0. , 0. , -0.04998368, 0. , 0. ],
[ 0.02147305, 0. , 0.22943809, 0.05801913, 0. ,
0. , 0. , 0. , 0. , 0. ],
[ 0. , 0.47018861, 0.33236235, 0. , 0. ,
0. , 0. , 0. , 0. , 0. ]])
In [67]: np.mean(M.data)
Out[67]: 0.044118297661574338
或用一组新值替换非零值:
In [69]: M.data = np.random.randint(-5,5,20)
In [70]: M
Out[70]:
<10x10 sparse matrix of type '<class 'numpy.int32'>'
with 20 stored elements in Compressed Sparse Row format>
In [71]: M.A
Out[71]:
array([[ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0],
[-1, 0, 0, 1, 2, 0, 0, 0, 0, -4],
[ 0, 0, 0, 0, 0, 4, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, -5, -5, 0],
[ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, -3, 0, 0, 3],
[ 0, 0, -1, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, -4, 0, 0, -1, 0, 0],
[-1, 0, -5, -2, 0, 0, 0, 0, 0, 0],
[ 0, 3, 1, 0, 0, 0, 0, 0, 0, 0]])
In [72]: M.data
Out[72]:
array([ 4, -1, 1, 2, -4, 0, 4, -5, -5, 2, -3, 3, -1, -4, -1, -1, -5,
-2, 3, 1])
有没有人有创建稀疏矩阵的经验,非零值遵循 [-0.5, 0.5] 的均匀分布并且在 python 中具有零均值(零中心)(例如使用 Scipy.sparse)?
我知道 scipy.sparse 包提供了一些创建随机稀疏矩阵的方法,比如 'rand' 和 'random'。但是我无法用这些方法实现我想要的。例如,我试过:
import numpy as np
import scipy.sparse as sp
s = np.random.uniform(-0.5,0.5)
W=sp.random(1024, 1024, density=0.01, format='csc', data_rvs=s)
具体说明我的想法: 假设我想要上面提到的非稀疏矩阵或密集矩阵,我将通过以下方式创建它:
dense=np.random.rand(1024,1024)-0.5
'np.random.rand(1024,1024)' 将创建一个密集的均匀矩阵,其值在 [0,1] 中。为了使其均值为零,我通过减去 0.5 来使矩阵居中。
但是,如果我创建一个稀疏矩阵,假设:
sparse=sp.rand(1024,1024,density=0.01, format='csc')
矩阵将在统一 [0,1] 中具有非零值。但是,如果我想使矩阵居中,我不能简单地执行 'sparse-=0.5' 这将导致所有最初为零的条目在减法后都为非零。
那么,对于稀疏矩阵上的密集矩阵,我该如何实现与上述示例相同的效果?
感谢大家的帮助!
data_rvs
参数期望 "callable" 需要一个大小。这在文档中并不十分明显。这可以使用 lambda 来完成,如下所示:
import numpy as np
import scipy.sparse as sp
W = sp.random(1024, 1024, density=0.01, format='csc',
data_rvs=lambda s: np.random.uniform(-0.5, 0.5, size=s))
然后 print(W)
给出:
(243, 0) -0.171300809713
(315, 0) 0.0739590145626
(400, 0) 0.188151369316
(440, 0) -0.187384896218
: :
(1016, 0) 0.29262088084
(156, 1) -0.149881296136
(166, 1) -0.490405135834
(191, 1) 0.188167190147
(212, 1) 0.0334533020488
: :
(411, 1) 0.122330200832
(431, 1) -0.0494334160833
(813, 1) -0.0076379249885
(828, 1) 0.462807265425
: :
(840, 1021) 0.456423017883
(12, 1022) -0.47313075329
: :
(563, 1022) -0.477190349161
(655, 1022) -0.460942546313
(673, 1022) 0.0930207181126
(676, 1022) 0.253643616387
: :
(843, 1023) 0.463793903168
(860, 1023) 0.454427252782
对于新手来说,lambda 可能看起来很奇怪 - 这只是一个未命名的函数。 sp.random
函数接受一个可选参数 data_rvs
,默认为 None
。指定后,它应该是一个函数,它接受一个大小参数和 returns 个随机数。执行此操作的一个简单函数是:
def generate_n_uniform_randoms(n):
return np.uniform(-0.5, 0.5, n)
我不知道 API 的来源,但不需要形状,因为 sp.random
大概首先弄清楚哪些索引将是非零的,然后它只需要计算这些索引的随机值,这是一组已知大小。
lambda 只是语法糖,它允许我们根据其他函数调用定义内联函数。我们可以改写
W = sp.random(1024, 1024, density=0.01, format='csc',
data_rvs=generate_n_uniform_randoms)
实际上,这可以是一个 "callable" - 一些对象 f
,其中 f(n)
returns n
个随机变量。这可以是一个函数,但也可以是实现 __call__(self, n)
函数的 class 的对象。例如:
class ufoo(object):
def __call__(self, n):
import numpy
return numpy.random.uniform(-0.5, 0.5, n)
W = sp.random(1024, 1024, density=0.01, format='csc',
data_rvs=ufoo())
如果您需要均值恰好为零(当然在舍入范围内),这可以通过从非零值中减去均值来完成,正如我上面提到的:
W.data -= np.mean(W.data)
然后:
W[idx].mean()
-2.3718641632430623e-18
在我看来,您的要求仍然不完整(见下文提到的缺点)。
下面是我在评论中概述的简单构造的一些实现:
import numpy as np
import scipy.sparse as sp
M, N, NNZ = 5, 5, 10
assert NNZ % 2 == 0
flat_dim = M*N
valuesA = np.random.uniform(-0.5, 0.5, size=NNZ // 2)
valuesB = valuesA * -1
values = np.hstack((valuesA, valuesB))
positions_flat = np.random.choice(flat_dim, size=NNZ, replace=False)
positions_2d = np.unravel_index(positions_flat, dims=(M, N))
mat = sp.coo_matrix((values, (positions_2d[0], positions_2d[1])), shape=(M, N))
print(mat.todense())
print(mat.data.mean())
输出:
[[ 0. 0. 0. 0.0273862 0. ]
[-0.3943963 0. 0. -0.04134932 0. ]
[-0.10121743 0. -0.0273862 0. 0.04134932]
[ 0.3943963 0. 0. 0. 0. ]
[-0.24680983 0. 0.24680983 0.10121743 0. ]]
0.0
优势
- 稀疏
- 零均值
- 来自均匀分布的条目
潜在劣势:
- 对于矩阵中的每个值 x,都可以在某处找到 -x!
- 意思是:在更广泛的联合分布意义上它是不均匀的
- 如果那是伤害只有你能说
- 如果是:可以轻松修改上述构造以使用来自某个分布的任何居中值,因此您的问题会分解为这个稍微小一点(但不一定更容易的问题)
现在关于那个相关的问题:我在这里猜测,但我不会惊讶地看到使用约束 mean(x)=0
统一采样 x
值是 NP-hard。
请记住,正如另一个答案中所建议的那样,非零值的后验居中会改变基础分布(即使对于 simple distributions)。在某些情况下甚至使边界无效(离开间隔 -0.5, 0.5)。
这意味着:这个问题是关于形式化 objective 有多重要 并以某种方式平衡它们。
sparse.random
做了两件事 - 随机分布非零值,并生成随机统一值。
In [62]: M = sparse.random(10,10,density=.2, format='csr')
In [63]: M
Out[63]:
<10x10 sparse matrix of type '<class 'numpy.float64'>'
with 20 stored elements in Compressed Sparse Row format>
In [64]: M.data
Out[64]:
array([ 0.42825407, 0.51858978, 0.8084335 , 0.08691635, 0.13210409,
0.61288928, 0.39675205, 0.58242891, 0.5174367 , 0.57859824,
0.48812484, 0.13472883, 0.82992478, 0.70568697, 0.45001632,
0.52147305, 0.72943809, 0.55801913, 0.97018861, 0.83236235])
您可以在不改变稀疏分布的情况下廉价地修改 data
值:
In [65]: M.data -= 0.5
In [66]: M.A
Out[66]:
array([[ 0. , 0. , 0. , -0.07174593, 0. ,
0. , 0. , 0. , 0. , 0. ],
[ 0.01858978, 0. , 0. , 0.3084335 , -0.41308365,
0. , 0. , 0. , 0. , -0.36789591],
[ 0. , 0. , 0. , 0. , 0.11288928,
-0.10324795, 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0.08242891, 0.0174367 , 0. ],
[ 0. , 0. , 0.07859824, 0. , 0. ,
0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. ,
0. , -0.01187516, 0. , 0. , -0.36527117],
[ 0. , 0. , 0.32992478, 0. , 0. ,
0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0.20568697,
0. , 0. , -0.04998368, 0. , 0. ],
[ 0.02147305, 0. , 0.22943809, 0.05801913, 0. ,
0. , 0. , 0. , 0. , 0. ],
[ 0. , 0.47018861, 0.33236235, 0. , 0. ,
0. , 0. , 0. , 0. , 0. ]])
In [67]: np.mean(M.data)
Out[67]: 0.044118297661574338
或用一组新值替换非零值:
In [69]: M.data = np.random.randint(-5,5,20)
In [70]: M
Out[70]:
<10x10 sparse matrix of type '<class 'numpy.int32'>'
with 20 stored elements in Compressed Sparse Row format>
In [71]: M.A
Out[71]:
array([[ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0],
[-1, 0, 0, 1, 2, 0, 0, 0, 0, -4],
[ 0, 0, 0, 0, 0, 4, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, -5, -5, 0],
[ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, -3, 0, 0, 3],
[ 0, 0, -1, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, -4, 0, 0, -1, 0, 0],
[-1, 0, -5, -2, 0, 0, 0, 0, 0, 0],
[ 0, 3, 1, 0, 0, 0, 0, 0, 0, 0]])
In [72]: M.data
Out[72]:
array([ 4, -1, 1, 2, -4, 0, 4, -5, -5, 2, -3, 3, -1, -4, -1, -1, -5,
-2, 3, 1])