将一个由一对对数据组成的列表转换为Numpy中的对称矩阵

4

我有一个相关矩阵,但它是以对的形式指定的,例如:

cm = pd.DataFrame({'name1': ['A', 'A', 'B'], 
                   'name2': ['B', 'C', 'C'], 
                   'corr': [0.1, 0.2, 0.3]})
cm
    name1   name2   corr
0   A       B       0.1
1   A       C       0.2
2   B       C       0.3

什么是将其转换为numpy 2d数组相关矩阵的最简单方法?
    A   B   C
A 1.0 0.1 0.2
B 0.1 1.0 0.3
C 0.2 0.3 1.0
3个回答

6

如果你处理的是pandas数据框架,那么不确定是否要使用pure numpy。这里提供了一种纯pandas解决方案:

s = cm.pivot(*cm)

ret = s.add(s.T, fill_value=0).fillna(1)

输出:

     A    B    C
A  1.0  0.1  0.2
B  0.1  1.0  0.3
C  0.2  0.3  1.0
额外信息: 对于反向(ret如上所述)
(ret.where(np.triu(np.ones(ret.shape, dtype=bool),1))
    .stack()
    .reset_index(name='corr')
)

输出:

  level_0 level_1  corr
0       A       B   0.1
1       A       C   0.2
2       B       C   0.3

1
非常优雅的解决方案!您能解释一下 cm.pivot(*cm) 的作用吗? - MachineLearner
1
@MachineLearner *cm 本质上等同于 *list(cm.column)。因此,在这种情况下,该行代码等同于 cm.pivot('name1','name2', 'corr') - Quang Hoang
什么是反转?如何使用 melts 返回到 cm - Jonathan
1
@Jonathan请查看新增的额外内容。 - Quang Hoang

3

一种方法是使用networkX构建一个图形,将corr列设置为边缘weight,然后使用nx.to_pandas_adjacency获取邻接矩阵

import networkx as nx
G = nx.from_pandas_edgelist(cm.rename(columns={'corr':'weight'}), 
                            source='name1', 
                            target='name2', 
                            edge_attr ='weight')

G.edges(data=True)
# EdgeDataView([('A', 'B', {'weight': 0.1}), ('A', 'C', {'weight': 0.2}), 
#               ('B', 'C', {'weight': 0.3})])

adj = nx.to_pandas_adjacency(G)
# sets the diagonal to 1 (node can't be connected to itself)
adj[:] = adj.values + np.eye(adj.shape[0])

print(adj)

    A    B    C
A  1.0  0.1  0.2
B  0.1  1.0  0.3
C  0.2  0.3  1.0

非常聪明和不错的解决方案!让我们看看是否可以使用纯numpy,但这肯定是一种可能性。 - Jonathan

0

假设最后一列以适当的方式排序,我们可以使用以下代码。

import pandas as pd
import numpy as np

# define data frame
data = pd.DataFrame({
    'name1': ['A', 'A', 'B'],
    'name2': ['B', 'C', 'C'],
    'correlation': [0.1, 0.2, 0.3]})

# get correlation column and dimension
correlation = data['correlation'].values
dimension = correlation.shape[0]

# define empty matrix to fill and unit matrix
matrix_upper_triangular = np.zeros((dimension, dimension))

# fill upper triangular matrix with one half at diagonal
counter = 0
for (row, column), element in np.ndenumerate(matrix_upper_triangular):
    # half of diagonal terms
    if row == column:
        matrix_upper_triangular[row, column] = 0.5
    # upper triangular values
    elif row < column:
        matrix_upper_triangular[row, column] = correlation[counter]
        counter = counter + 1
    else:
        pass

# add upper triangular + lower triangular matrix
correlation_matrix = matrix_upper_triangular
correlation_matrix += matrix_upper_triangular.transpose()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接