Построение ковариационной матрицы в Python
1 ответов
во-первых, для тех, кто может столкнуться с этим вопросом в будущем: если у вас есть данные и вы хотите оценить ковариационную матрицу, как отметили несколько человек, используйте np.cov
или что-то подобное.
Построение Массивов Из Моделей
однако ваш вопрос заключается в том, как построить большую матрицу с учетом некоторых предопределенных правил. Чтобы прояснить некоторую путаницу в комментариях: ваш вопрос, похоже, не об оценке ковариационной матрицы, это об указании одного. Другими словами, вы спрашиваете, как создать большой массив с учетом некоторых предопределенных правил.
какой способ наиболее эффективен, будет зависеть от того, что вы делаете подробно. Большинство трюков производительности в этом случае будут включать использование симметрии в расчетах, которые вы формируете. (Например, будет ли одна строка идентична?)
трудно сказать что-либо конкретное, не зная точно, что вы делаете. Поэтому я сосредоточусь на том, как делать такого рода вещи вообще. (Примечание: Я только что заметил ваше редактирование. Чуть позже я приведу пример броуновского моста...)
постоянная (или простая) строка / столбец
самым основным случаем является постоянная строка или столбец в выходном массиве. Легко создать массив и назначить значения столбцу или строке с помощью синтаксиса среза:
import numpy as np
num_vars = 10**4
cov = np.zeros((num_vars, num_vars), dtype=float)
установить весь столбец/строку:
# Third column will be all 9's
cov[:,2] = 9
# Second row will be all 1's (will overwrite the 9 in col3)
cov[1,:] = 1
вы также можете назначить массивов столбцы / строки:
# 5th row will have random values
cov[4,:] = np.random.random(num_vars)
# 6th row will have a simple geometric sequence
cov[5,:] = np.arange(num_vars)**2
Укладку Массива
во многих случаях (но не в этом конкретном случае) вы хотите строить свой выход из существующих массивов. Вы можете использовать vstack
/hstack
/column_stack
/tile
и многие другие подобные функции для этого.
хорошим примером является то, что мы настраиваем матрицу для линейной инверсии многочлена:
import numpy as np
num = 10
x = np.random.random(num) # Observation locations
# "Green's functions" for a second-order polynomial
# at our observed locations
A = np.column_stack([x**i for i in range(3)])
однако это создаст несколько временных массивов (в данном случае три). Если мы работали с 10000-мерным полиномом с 10^6 наблюдениями, подход выше использовал бы слишком много ОЗУ. Поэтому вместо этого вы можете перебирать столбцы:
ndim = 2
A = np.zeros((x.size, ndim + 1), dtype=float)
for j in range(ndim + 1):
A[:,j] = x**j
в большинстве случаев, не беспокойтесь о временных массивов. The colum_stack
-основанный пример-правильный путь, если вы не работаете с относительно большими массивами.
самый общий подход
без дополнительной информации мы не можем использовать какую-либо симметрию. Самый общий способ-просто повторить. Обычно вы хотите избежать этого подхода, но иногда это неизбежно (особенно если расчет зависит от предыдущего значения).
Speed-wise это идентично вложенным циклам for, но проще (особенно для >2D-массивов) использовать np.ndindex
вместо нескольких циклов:
import numpy as np
num_vars = 10**4
cov = np.zeros((num_vars, num_vars), dtype=float)
for i, j in np.ndindex(cov.shape):
# Logic presumably in some function...
cov[i, j] = calculate_value(i, j)
вычисления на основе векторного индекса
если много случаев, вы можете векторизовать вычисления на основе индекса. Иначе говоря, работайте непосредственно на массивах индексов вашего выхода.
предположим, у нас был код, который выглядел так:
import numpy as np
cov = np.zeros((10, 10)), dtype=float)
for i, j in np.ndindex(cov.shape):
cov[i,j] = i*j - i
мы могли бы заменить это:
i, j = np.mgrid[:10, :10]
cov = i*j - i
в качестве другого примера давайте построим 100 x 100 "перевернутый конус" значений:
# The complex numbers in "mgrid" give the number of increments
# mgrid[min:max:num*1j, min:max:num*1j] is similar to
# meshgrid(linspace(min, max, num), linspace(min, max, num))
y, x = np.mgrid[-5:5:100j, -5:5:100j]
# Our "inverted cone" is just the distance from 0
r = np.hypot(x, y)
Броуновского Моста
это хороший пример того, что можно легко векторизовать. Если я правильно читаю ваш пример, вам нужно что-то подобное кому:
import numpy as np
st = np.mgrid[1:101, 1:101]
s, t = st
cov = st.min(axis=0) - s * t
в целом, я коснулся только нескольких общих шаблонов. Однако, надеюсь, это приведет вас в правильном направлении.