Построение ковариационной матрицы в 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

в целом, я коснулся только нескольких общих шаблонов. Однако, надеюсь, это приведет вас в правильном направлении.