Разреженная случайная матрица в Python с диапазоном, отличным от [0,1]

Мне нужно сгенерировать разреженную случайную матрицу в Python со всеми значениями в диапазоне [-1,1] с равномерным распределением. Каков наиболее эффективный способ сделать это?

У меня есть базовая разреженная случайная матрица:

from scipy import sparse
from numpy.random import RandomState

p = sparse.rand(10, 10, 0.1, random_state=RandomState(1))

И это дает мне значения в [0,1]:

print p
  (0, 0)    0.419194514403
  (0, 3)    0.0273875931979
  (1, 4)    0.558689828446
  (2, 7)    0.198101489085
  (3, 5)    0.140386938595
  (4, 1)    0.204452249732
  (4, 3)    0.670467510178
  (8, 1)    0.878117436391
  (9, 0)    0.685219500397
  (9, 3)    0.417304802367

Было бы хорошо иметь решение на месте или что-то, что не требует раздувания его до полной матрицы, поскольку на практике я буду использовать очень большие размеры. Меня удивляет, что для самого sparse.rand нет быстрых параметров.


person adamconkey    schedule 02.06.2015    source источник


Ответы (2)


Похоже, что функция, которую вы хотите, была добавлена ​​около двух месяцев назад и будет доступна в scipy 0.16: L671" rel="noreferrer">https://github.com/scipy/scipy/blob/77af8f44bef43a67cb14c247bc230282022ed0c2/scipy/sparse/construct.py#L671

Вы сможете вызвать sparse.random(10, 10, 0.1, random_state=RandomState(1), data_fvs=func), где func "должен принимать один аргумент, указывающий длину возвращаемого массива ndarray. Структурно ненулевые элементы разреженной случайной матрицы будут взяты из массива, отобранного этой функцией". Таким образом, вы сможете предоставить произвольный дистрибутив для выборки.

На данный момент вы можете, по крайней мере, растянуть равномерное распределение до [0,N], умножив p на скаляр N:

>>> print 2*p

(0, 0)  0.838389028807
(9, 0)  1.37043900079
(4, 1)  0.408904499463
(8, 1)  1.75623487278
(0, 3)  0.0547751863959
(4, 3)  1.34093502036
(9, 3)  0.834609604734
(1, 4)  1.11737965689
(3, 5)  0.28077387719
(2, 7)  0.39620297817

Вы не можете добавлять скаляры, но в качестве хака вы можете создать разреженную матрицу со всеми единицами в ненулевых элементах с p.ceil(), поскольку все элементы p были сгенерированы в пределах [0,1]. Затем, чтобы преобразовать равномерное распределение в [-1,1], вы можете сделать

 print 2*p - p.ceil()

(0, 0)  -0.161610971193
(0, 3)  -0.945224813604
(1, 4)  0.117379656892
(2, 7)  -0.60379702183
(3, 5)  -0.71922612281
(4, 1)  -0.591095500537
(4, 3)  0.340935020357
(8, 1)  0.756234872782
(9, 0)  0.370439000794
(9, 3)  -0.165390395266

В общем, если вам нужен какой-то интервал [a,b], просто выполните:

p = (b - a)*p + a*p.ceil()

В настоящее время я не вижу лучшего решения, кроме написания собственного конструктора, похожего на sparse.rand, но мне было бы любопытно узнать, знает ли кто-нибудь хотя бы способ обойти хак ceil().

person Eric Appelt    schedule 02.06.2015
comment
Удивительно узнать, что это в предстоящем выпуске, я буду следить за этим. Между тем, ваше решение отлично работает. - person adamconkey; 04.06.2015

Поскольку sparse.rand создает матрицу coo (по умолчанию), вы можете напрямую манипулировать ее атрибутом .data. (формат 'csr' может быть преобразован таким образом)

p=sparse.rand(10,10,0.1)
p.data *=2
p.data -=1

До и после значения будут:

  (0, 4)    0.758811389117
  (1, 8)    0.703514506105
  (1, 9)    0.640418745353
  (4, 0)    0.896198785835
  (4, 6)    0.511459880587
  (5, 2)    0.580048680358
  (7, 1)    0.739418689993
  (8, 3)    0.506395207688
  (8, 5)    0.900696518461
  (9, 4)    0.474014207942

  (0, 4)    0.517622778234
  (1, 8)    0.40702901221
  (1, 9)    0.280837490706
  (4, 0)    0.79239757167
  (4, 6)    0.0229197611736
  (5, 2)    0.160097360716
  (7, 1)    0.478837379986
  (8, 3)    0.0127904153758
  (8, 5)    0.801393036923
  (9, 4)    -0.051971584115

Та же пространственная плотность, просто другое распределение значений.

На самом деле вы могли бы сгенерировать совершенно новые значения .data. Конец sparse.rand:

....
j = .... # tweak random values
i = ...  # tweak ints
vals = random_state.rand(k).astype(dtype)
return coo_matrix((vals, (i, j)), shape=(m, n)).asformat(format)

Случайный массив генерируется из 3 случайных последовательностей, 2 из которых производят целые числа в правильном диапазоне формы, а третья — случайные значения.

Например, случайные значения, выбранные из списка:

In [209]: p.data=np.random.choice(np.arange(20)-10,len(p.data))/10

In [210]: print(p.A)
[[ 0.   0.   0.   0.   0.9  0.   0.   0.   0.   0. ]
 [ 0.   0.   0.   0.   0.   0.   0.   0.  -0.1 -0.7]
 [ 0.   0.   0.   0.   0.   0.   0.   0.   0.   0. ]
 [ 0.   0.   0.   0.   0.   0.   0.   0.   0.   0. ]
 [-1.   0.   0.   0.   0.   0.  -0.8  0.   0.   0. ]
 [ 0.   0.   0.5  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. ]
 [ 0.   0.   0.   0.5  0.   0.4  0.   0.   0.   0. ]
 [ 0.   0.   0.   0.  -0.8  0.   0.   0.   0.   0. ]]

Код разработки просто меняет вторую строку на последнюю:

vals = data_rvs(k).astype(dtype)

где data_rvs — параметр (или значение по умолчанию randomstate.rand).

person hpaulj    schedule 03.06.2015
comment
Ваш ответ полностью работает и для меня, к сожалению, я могу отметить только один принятый ответ. Спасибо! - person adamconkey; 04.06.2015