Как преобразовать список корреляций в матрицу ковариаций?

У меня есть список корреляций, созданный из текстового файла с этой формой:

(первые два значения указывают, между какими точками находится корреляция)

2     1  -0.798399811877855E-01
3     1   0.357718108972297E+00
3     2  -0.406142457763738E+00
4     1   0.288467030571132E+00
4     2  -0.129115034405361E+00
4     3   0.156739504479856E+00
5     1  -0.756332254716083E-01
5     2   0.479036971438800E+00
5     3  -0.377545460300584E+00
5     4  -0.265467953118191E+00
6     1   0.909003414436468E-01
6     2  -0.363568902645620E+00
6     3   0.482042347959232E+00
6     4   0.292931692897587E+00
6     5  -0.739868576924150E+00

У меня уже есть другой список стандартных отклонений по всем пунктам. Как мне объединить эти два в numpy / scipy для создания ковариационной матрицы?

Это должен быть очень эффективный метод, так как существует 300 точек, поэтому ~ 50 000 корреляций.


person Melanie    schedule 15.05.2015    source источник
comment
Могли бы записать выходные данные ковариационной матрицы для выборки входных данных?   -  person Divakar    schedule 15.05.2015
comment
Как в ответе ниже, но симметрично и с диагональю, заполненной единицами.   -  person Melanie    schedule 15.05.2015


Ответы (3)


Предполагая, что эта таблица называется df и что первый столбец помечен A, а второй - B со значением корреляции, помеченным Correlation:

df2 = df.pivot(index='A', columns='B', values='Correlation')
>>> df2
B       1      2      3      4     5
A                                   
2 -0.0798    NaN    NaN    NaN   NaN
3  0.3580 -0.406    NaN    NaN   NaN
4  0.2880 -0.129  0.157    NaN   NaN
5 -0.0756  0.479 -0.378 -0.265   NaN
6  0.0909 -0.364  0.482  0.293 -0.74

Чтобы преобразовать это в симметричную квадратную матрицу с матрицами по диагонали:

# Get a unique list of all items in rows and columns.
items = list(df2)
items.extend(list(df2.index))
items = list(set(items))

# Create square symmetric correlation matrix
corr = df2.values.tolist()
corr.insert(0, [np.nan] * len(corr))
corr = pd.DataFrame(corr)
corr[len(corr) - 1] = [np.nan] * len(corr)
for i in range(len(corr)):
    corr.iat[i, i] = 1.  # Set diagonal to 1.00
    corr.iloc[i, i:] = corr.iloc[i:, i].values  # Flip matrix.

# Rename rows and columns.
corr.index = items
corr.columns = items

>>> corr
        1       2      3      4       5       6
1  1.0000 -0.0798  0.358  0.288 -0.0756  0.0909
2 -0.0798  1.0000 -0.406 -0.129  0.4790 -0.3640
3  0.3580 -0.4060  1.000  0.157 -0.3780  0.4820
4  0.2880 -0.1290  0.157  1.000 -0.2650  0.2930
5 -0.0756  0.4790 -0.378 -0.265  1.0000 -0.7400
6  0.0909 -0.3640  0.482  0.293 -0.7400  1.0000

Проделайте те же шаги с вашими данными std dev, если они еще не представлены в матричной форме.

Предполагая, что эта матрица называется df_std, вы можете получить ковариационную матрицу следующим образом:

df_cov = corr.multiply(df_std.multiply(df_std.T.values))
person Alexander    schedule 15.05.2015
comment
Вы знаете, как складывать верхнюю треугольную часть и складывать по диагонали? - person Melanie; 15.05.2015

Один подход -

import numpy as np

# Input list: AList

# Convert input list to a numpy array
A = np.asarray(AList)   

# Get the first two columns that are coordinates/points
A01 = A[:,0:2].astype(int)

# Determine size of square output array
N = A01.max()

# Initialize output array & insert values from third column
out = np.zeros((N,N))
out[A01[:,0]-1,A01[:,1]-1] = A[:,2]

# Upper triangular mask
triu_mask = np.triu(np.ones(out.shape,'bool'))

# Fill in the upper triangular region with the 
# symmetrical elements from lower triangular region
out[triu_mask] = out.T[triu_mask]

# Fill diagonal with ones
np.fill_diagonal(out,1)

Пробный прогон -

In [157]: AList  # Input list
Out[157]: 
[[2, 1, -0.0798399811877855],
 [3, 1, 0.357718108972297],
 [3, 2, -0.406142457763738],
 [4, 1, 0.288467030571132],
 [4, 2, -0.129115034405361],
 [4, 3, 0.156739504479856],
 [5, 1, -0.0756332254716083],
 [5, 2, 0.4790369714388],
 [5, 3, -0.377545460300584],
 [5, 4, -0.265467953118191],
 [6, 1, 0.0909003414436468],
 [6, 2, -0.36356890264562],
 [6, 3, 0.482042347959232],
 [6, 4, 0.292931692897587],
 [6, 5, -0.73986857692415]]

In [158]: print(out)  # Print of output numpy array
[[ 1.         -0.07983998  0.35771811  0.28846703 -0.07563323  0.09090034]
 [-0.07983998  1.         -0.40614246 -0.12911503  0.47903697 -0.3635689 ]
 [ 0.35771811 -0.40614246  1.          0.1567395  -0.37754546  0.48204235]
 [ 0.28846703 -0.12911503  0.1567395   1.         -0.26546795  0.29293169]
 [-0.07563323  0.47903697 -0.37754546 -0.26546795  1.         -0.73986858]
 [ 0.09090034 -0.3635689   0.48204235  0.29293169 -0.73986858  1.        ]]
person Divakar    schedule 15.05.2015

Я предполагаю, что вы указываете коэффициенты корреляции, а не перекрестные ковариации (в отличие от @Divakar и @Alexander). Следовательно, запись в вашей ковариационной матрице - c[i,j] = rr[i,j]*sqrt(c[i,i]*c[j,j]), где rr[i,j] - коэффициент корреляции. Очевидно, c[i,i] - это i-я дисперсия, а rr[i,i]==1.

В следующем примере показано, как построить ковариационную матрицу из списка отклонений и списка корреляций:

import numpy as np
from itertools import product

n0 = 5  # dimension of random vector

print("Generating test-matrix CC0 ...")
# Generate a valid test covariance matrix (positive semi-definite)
sq_CC0 = np.random.randn(n0, n0)*10 
CC0 = np.dot(sq_CC0, sq_CC0.T)

# extract lists:
lst_var = [(i, CC0[i, i]) for i in range(n0)] # list vor variances
lst_rr =  [(i, j, CC0[i,j]/np.sqrt(CC0[i, i]*CC0[j,j])) # list of correlations
           for i, j in product(range(n0), range(n0)) if i < j]

print("  Variances:")
for i, val in lst_var:
    print("    ", i, val)
print("  Correlations:")
for i, j, val in lst_rr:
    print("    ", i, j, val)

print("Building matrix CC1 ...")
n1 = len(lst_var)  # dimension

# Exploit CC[i, j] = rr[i, j]* sqrt(CC[i, i]*CC[j, j]):
aa_var = np.array(lst_var)  # convert to array to do index magic
ii = np.array(aa_var[:, 0], dtype=int) # indexes must be ints
vv = np.zeros(n1)
vv[ii] = np.sqrt(aa_var[ :, 1])
CC1a = np.outer(vv, vv)  # Its entries are sqrt(CC[i, i]*CC[j, j])

aa_rr = np.array(lst_rr)
CC1b = np.zeros((n1, n1))
ii, jj = (np.array(aa_rr[ :, k], dtype=int) for k in [0, 1]) # indexes must be ints
CC1b[ii, jj] = aa_rr[:, 2] # build matrix with correlations
CC1 = CC1a * (CC1b + CC1b.T + np.eye(n1))  # build covariance matrix

print("  CC0 == CC1 is:", np.allclose(CC0, CC1))

Обратите внимание, что синтаксический анализ текста не включен, что индексы начинаются с 0 и двойные корреляции (rr[i,j]==rr[j,i]) не указываются.

person Dietrich    schedule 15.05.2015
comment
Обратите внимание, что если у вас есть массив numpy, представляющий матрицу ковариации, вы можете просто использовать self.diagonal () для получения дисперсии. - person Galen; 20.02.2020