从长格式的值重建对称矩阵
Reconstruct symmetric matrix from values in long-form
我有一个看起来像这样的 tsv(长格式):
one two value
a b 30
a c 40
a d 20
b c 10
b d 05
c d 30
我正在尝试将其放入 R 的数据框中(或 pandas)
a b c d
a 00 30 40 20
b 30 00 10 05
c 40 10 00 30
d 20 05 30 00
问题是,在我的 tsv 中我只定义了 a、b 而没有定义 b、a。所以我的数据框中有很多 NA。
最终目标是获得用于聚类的距离矩阵。任何帮助将不胜感激。
确保您的数据已排序 tsv=tsv[with(tsv,order(one,two)),]
,然后试试这个:
n=4
B <- matrix(rep(0,n*n), n)
dimnames(B) <- list(letters[1:n],letters[1:n])
B[lower.tri(B)] <- tsv$value
B[upper.tri(B)]=tsv$value
B
你可以试试
un1 <- unique(unlist(df1[1:2]))
df1[1:2] <- lapply(df1[1:2], factor, levels=un1)
m1 <- xtabs(value~one+two, df1)
m1+t(m1)
# two
#one a b c d
#a 0 30 40 20
#b 30 0 10 5
#c 40 10 0 30
#d 20 5 30 0
或者您使用 row/col
索引
m1 <- matrix(0, nrow=length(un1), ncol=length(un1),
dimnames=list(un1, un1))
m1[cbind(match(df1$one, rownames(m1)),
match(df1$two, colnames(m1)))] <- df1$value
m1+t(m1)
# a b c d
#a 0 30 40 20
#b 30 0 10 5
#c 40 10 0 30
#d 20 5 30 0
一个 igraph
解决方案,您在其中读取数据框,并将值假定为边权重。然后您可以将其转换为邻接矩阵
dat <- read.table(header=T, text=" one two value
a b 30
a c 40
a d 20
b c 10
b d 05
c d 30")
library(igraph)
# Make undirected so that graph matrix will be symmetric
g <- graph.data.frame(dat, directed=FALSE)
# add value as a weight attribute
get.adjacency(g, attr="value", sparse=FALSE)
# a b c d
#a 0 30 40 20
#b 30 0 10 5
#c 40 10 0 30
#d 20 5 30 0
另一种方法是reshape::cast
df.long = data.frame(one=c('a','a','a','b','b','c'),
two=c('b','c','d','c','d','d'),
value=c(30,40,20,10,05,30) )
# cast will recover the upper/lower-triangles...
df <- as.matrix( cast(df.long, one ~ two, fill=0) )
# b c d
# a 30 40 20
# b 0 10 5
# c 0 0 30
因此我们构建具有完整索引的矩阵,并插入:
df <- matrix(nrow=length(indices), ncol=length(indices),dimnames = list(indices,indices))
diag(df) <- 0
# once we assure that the full upper-triangle is present and in sorted order (as Robert's answer does), then we
df[upper.tri(df)] <- as.matrix( cast(df.long, one ~ two, fill=0) )
df[lower.tri(df)] <- df[upper.tri(df)]
更新:原始草图包含这些手动拼凑
然后用相同的方法添加缺失的行 'd' 和列 'a',并通过添加转置 t(df) 填充下三角:
df <- cbind(a=rep(0,4), rbind(df, d=rep(0,3)))
# a b c d
# a 0 30 40 20
# b 0 0 10 5
# c 0 0 0 30
# d 0 0 0 0
df + t(df)
# a b c d
# a 0 30 40 20
# b 30 0 10 5
# c 40 10 0 30
# d 20 5 30 0
这是一个基本 R
解决方案,适合不想学习新功能的人。它创建了一个对称矩阵。
df.long = data.frame(one=c('a','a','a','b','b','c'),
two=c('b','c','d','c','d','d'),
value=c(30,40,20,10,05,30) )
v <- unique(c(df.long$one, df.long$two))
mx <- sapply(v, function(x) {
sapply(v, function(y) {
df.long[df.long$one %in% c(x, y) & df.long$two %in% c(x, y), "value"]
})
})
diag(mx) <- 0
a b c d
a 0 30 40 20
b 30 0 10 5
c 40 10 0 30
d 20 5 30 0
我有一个看起来像这样的 tsv(长格式):
one two value
a b 30
a c 40
a d 20
b c 10
b d 05
c d 30
我正在尝试将其放入 R 的数据框中(或 pandas)
a b c d
a 00 30 40 20
b 30 00 10 05
c 40 10 00 30
d 20 05 30 00
问题是,在我的 tsv 中我只定义了 a、b 而没有定义 b、a。所以我的数据框中有很多 NA。
最终目标是获得用于聚类的距离矩阵。任何帮助将不胜感激。
确保您的数据已排序 tsv=tsv[with(tsv,order(one,two)),]
,然后试试这个:
n=4
B <- matrix(rep(0,n*n), n)
dimnames(B) <- list(letters[1:n],letters[1:n])
B[lower.tri(B)] <- tsv$value
B[upper.tri(B)]=tsv$value
B
你可以试试
un1 <- unique(unlist(df1[1:2]))
df1[1:2] <- lapply(df1[1:2], factor, levels=un1)
m1 <- xtabs(value~one+two, df1)
m1+t(m1)
# two
#one a b c d
#a 0 30 40 20
#b 30 0 10 5
#c 40 10 0 30
#d 20 5 30 0
或者您使用 row/col
索引
m1 <- matrix(0, nrow=length(un1), ncol=length(un1),
dimnames=list(un1, un1))
m1[cbind(match(df1$one, rownames(m1)),
match(df1$two, colnames(m1)))] <- df1$value
m1+t(m1)
# a b c d
#a 0 30 40 20
#b 30 0 10 5
#c 40 10 0 30
#d 20 5 30 0
一个 igraph
解决方案,您在其中读取数据框,并将值假定为边权重。然后您可以将其转换为邻接矩阵
dat <- read.table(header=T, text=" one two value
a b 30
a c 40
a d 20
b c 10
b d 05
c d 30")
library(igraph)
# Make undirected so that graph matrix will be symmetric
g <- graph.data.frame(dat, directed=FALSE)
# add value as a weight attribute
get.adjacency(g, attr="value", sparse=FALSE)
# a b c d
#a 0 30 40 20
#b 30 0 10 5
#c 40 10 0 30
#d 20 5 30 0
另一种方法是reshape::cast
df.long = data.frame(one=c('a','a','a','b','b','c'),
two=c('b','c','d','c','d','d'),
value=c(30,40,20,10,05,30) )
# cast will recover the upper/lower-triangles...
df <- as.matrix( cast(df.long, one ~ two, fill=0) )
# b c d
# a 30 40 20
# b 0 10 5
# c 0 0 30
因此我们构建具有完整索引的矩阵,并插入:
df <- matrix(nrow=length(indices), ncol=length(indices),dimnames = list(indices,indices))
diag(df) <- 0
# once we assure that the full upper-triangle is present and in sorted order (as Robert's answer does), then we
df[upper.tri(df)] <- as.matrix( cast(df.long, one ~ two, fill=0) )
df[lower.tri(df)] <- df[upper.tri(df)]
更新:原始草图包含这些手动拼凑
然后用相同的方法添加缺失的行 'd' 和列 'a',并通过添加转置 t(df) 填充下三角:
df <- cbind(a=rep(0,4), rbind(df, d=rep(0,3)))
# a b c d
# a 0 30 40 20
# b 0 0 10 5
# c 0 0 0 30
# d 0 0 0 0
df + t(df)
# a b c d
# a 0 30 40 20
# b 30 0 10 5
# c 40 10 0 30
# d 20 5 30 0
这是一个基本 R
解决方案,适合不想学习新功能的人。它创建了一个对称矩阵。
df.long = data.frame(one=c('a','a','a','b','b','c'),
two=c('b','c','d','c','d','d'),
value=c(30,40,20,10,05,30) )
v <- unique(c(df.long$one, df.long$two))
mx <- sapply(v, function(x) {
sapply(v, function(y) {
df.long[df.long$one %in% c(x, y) & df.long$two %in% c(x, y), "value"]
})
})
diag(mx) <- 0
a b c d
a 0 30 40 20
b 30 0 10 5
c 40 10 0 30
d 20 5 30 0