将presence/absence的矩阵变换为顶点连接的Data.frame。 (删除具有 eeuqal 无序值的重复行)
Transforming matrix of presence/absence to Data.frame of vertice connection. (Removing duplicated rows with eeuqal unordered values)
我有一个矩阵 table,其中行表示一个地点,列表示特定岩石的 presence/absence。
>Mat
A B C D E F G
Aiz 1 0 0 0 0 0 0
Aren 0 1 1 0 1 0 0
Atx 0 0 1 0 1 0 0
Berr 1 1 0 0 0 1 0
Bra 0 0 0 0 0 1 0
Bur 0 1 0 0 1 0 0
Cab 1 0 1 1 1 0 0
如您所见,有些行在某些列中具有相同的元素,例如。行 Aiz
和行 Berr
在列 A
中共享一个存在,这表明在我的示例中它们共享同一块岩石。
我想从这个矩阵构造无向图,其中节点是站点(行名),链接是列元素的份额。
所以,基本上,我需要将此矩阵转换为 data.frame 样式:
>DF
siteA siteB weight
1 Aiz Berr 1
2 Aiz Cab 1
3 Aren Atxos 2
4 Aren Berr 1
5 Aren Bur 2
6 Aren Cab 1
7 Atx Bur 1
...
其中每一行标识共享相同岩石的两个站点(存在于原始 Mat
的同一列中)并且列 weight
,表示两个站点共有的岩石数量.
因此,通过一系列嵌套的 for loops
和 if
条件,我设法接近 DF
矩阵,尽管我的 DF
有行重复的结果,例如:
> df_links
siteA siteB weight
1 Aiz Berr 1
2 Aiz Cab 1
3 Aren Atxos 2
4 Berr Aiz 1
5 Atxos Aren 2
您看到的地方,例如:row 1
和 row 4
(row 3
和 row 5
相同)的网站栏共享相同的元素。由于这是针对无向图的,因此 Aiz-Berr 或 Ber-Aiz 的含义相同,因此我只需要其中一行。
Q 1: 所以,我尝试用 tidyverse
解决重复问题,但似乎没有任何效果。充其量我只会摆脱重复行中的一个而不是全部。所以,我的问题是,有没有办法可以做到这一点?只保留具有相同元素的行之一 [i,j]
,而不考虑顺序?
Q 2:这个可能比较繁琐,所以排在第二位。即使我的代码有效(直到上面 Q1 中指出的问题),它也不是最漂亮的。是 data.frames 到 data.frames 和 for loops
的矩阵序列,并且包含条件。
是否有更整洁的版本可以从原始 Mat
到所需的 DF
?我不太熟悉 sapply
和整个家庭,所以我使用了循环。有没有更快更好看的解决方案?
要删除 2 个可互换列的重复条目,请先重新排序,然后删除数据框的重复行。
df_links <- transform(df_links, siteA = pmin(siteA, siteB),
siteB = pmax(siteA, siteB))
unique(df_links)
# siteA siteB weight
#1 Aiz Berr 1
#2 Aiz Cab 1
#3 Aren Atxos 2
为了避免在无向图中删除重复的顶点对,您可以使用 dist
函数,这在处理向量对之间的相似性时非常有用。当您将相似性(或权重)定义为站点(或向量)之间常见岩石的数量时,您需要传递一个自定义函数,这可以使用包 proxy 中的 dist
来完成。
#The similarity is the number of matching '1'
similarityMatrix <- as.matrix(proxy::dist(Mat, method = function(x,y){
length(which(x+y==2))
}))
similarityMatrix
# Aiz Aren Atx Berr Bra Bur Cab
#Aiz 0 0 0 1 0 0 1
#Aren 0 0 2 1 0 2 2
#Atx 0 2 0 0 0 1 2
#Berr 1 1 0 0 1 1 1
#Bra 0 0 0 1 0 0 0
#Bur 0 2 1 1 0 0 1
#Cab 1 2 2 1 0 1 0
在那里,所有成对的网站之间都有一个相似度矩阵。由于您要构建的图形是无向的,因此您需要从该矩阵中每对 select 一次。
#Unique pairwise combinations of different vectors
combinations <- t(combn(colnames(similarityMatrix), 2))
pairwiseSites <- data.frame(combinations, similarityMatrix[combinations])
colnames(pairwiseSites) <- c("siteA", "siteB", "weight")
pairwiseSites
# siteA siteB weight
#1 Aiz Aren 0
#2 Aiz Atx 0
#3 Aiz Berr 1
#4 Aiz Bra 0
#5 Aiz Bur 0
#6 Aiz Cab 1
#7 Aren Atx 2
#8 Aren Berr 1
#9 Aren Bra 0
#10 Aren Bur 2
#11 Aren Cab 2
#12 Atx Berr 0
#13 Atx Bra 0
#14 Atx Bur 1
#15 Atx Cab 2
#16 Berr Bra 1
#17 Berr Bur 1
#18 Berr Cab 1
#19 Bra Bur 0
#20 Bra Cab 0
#21 Bur Cab 1
原始数据
Mat <- read.table(header=TRUE, text="
A B C D E F G
Aiz 1 0 0 0 0 0 0
Aren 0 1 1 0 1 0 0
Atx 0 0 1 0 1 0 0
Berr 1 1 0 0 0 1 0
Bra 0 0 0 0 0 1 0
Bur 0 1 0 0 1 0 0
Cab 1 0 1 1 1 0 0")
df_links <- read.table(header=TRUE, text="
siteA siteB weight
1 Aiz Berr 1
2 Aiz Cab 1
3 Aren Atxos 2
4 Berr Aiz 1
5 Atxos Aren 2")
使用 purrr 包可以解决问题。
# reproduce input
mat <- matrix(
data = c(1,0,0,0,0,0,0,
0,1,1,0,1,0,0,
0,0,1,0,1,0,0,
1,1,0,0,0,1,0,
0,0,0,0,0,1,0,
0,1,0,0,1,0,0,
1,0,1,1,1,0,0), nrow = 7, ncol = 7)
colnames(mat) <- LETTERS[1:7]
rownames(mat) <- c("Aiz", "Aren", "Atx", "Berr", "Bra", "Bur", "Cab")
# convert to dataframe
df <- mat %>%
dplyr::as_tibble() %>%
dplyr::bind_cols(
tibble::tibble(Names = rownames(mat)))
# calculate the connections
purrr::map_df(df$Names, function(x){
output <-purrr::map_df(df$Names, function(y){
if(x >= y) return(tibble::tibble()) # avoid double counting
tibble::tibble(
siteA = x,
siteB = y,
weight = sum(as.integer(df[df$Names==x,1:7]) & as.integer(df[df$Names==y,1:7])))
})
})
祝你好运
我有一个矩阵 table,其中行表示一个地点,列表示特定岩石的 presence/absence。
>Mat
A B C D E F G
Aiz 1 0 0 0 0 0 0
Aren 0 1 1 0 1 0 0
Atx 0 0 1 0 1 0 0
Berr 1 1 0 0 0 1 0
Bra 0 0 0 0 0 1 0
Bur 0 1 0 0 1 0 0
Cab 1 0 1 1 1 0 0
如您所见,有些行在某些列中具有相同的元素,例如。行 Aiz
和行 Berr
在列 A
中共享一个存在,这表明在我的示例中它们共享同一块岩石。
我想从这个矩阵构造无向图,其中节点是站点(行名),链接是列元素的份额。
所以,基本上,我需要将此矩阵转换为 data.frame 样式:
>DF
siteA siteB weight
1 Aiz Berr 1
2 Aiz Cab 1
3 Aren Atxos 2
4 Aren Berr 1
5 Aren Bur 2
6 Aren Cab 1
7 Atx Bur 1
...
其中每一行标识共享相同岩石的两个站点(存在于原始 Mat
的同一列中)并且列 weight
,表示两个站点共有的岩石数量.
因此,通过一系列嵌套的 for loops
和 if
条件,我设法接近 DF
矩阵,尽管我的 DF
有行重复的结果,例如:
> df_links
siteA siteB weight
1 Aiz Berr 1
2 Aiz Cab 1
3 Aren Atxos 2
4 Berr Aiz 1
5 Atxos Aren 2
您看到的地方,例如:row 1
和 row 4
(row 3
和 row 5
相同)的网站栏共享相同的元素。由于这是针对无向图的,因此 Aiz-Berr 或 Ber-Aiz 的含义相同,因此我只需要其中一行。
Q 1: 所以,我尝试用 tidyverse
解决重复问题,但似乎没有任何效果。充其量我只会摆脱重复行中的一个而不是全部。所以,我的问题是,有没有办法可以做到这一点?只保留具有相同元素的行之一 [i,j]
,而不考虑顺序?
Q 2:这个可能比较繁琐,所以排在第二位。即使我的代码有效(直到上面 Q1 中指出的问题),它也不是最漂亮的。是 data.frames 到 data.frames 和 for loops
的矩阵序列,并且包含条件。
是否有更整洁的版本可以从原始 Mat
到所需的 DF
?我不太熟悉 sapply
和整个家庭,所以我使用了循环。有没有更快更好看的解决方案?
要删除 2 个可互换列的重复条目,请先重新排序,然后删除数据框的重复行。
df_links <- transform(df_links, siteA = pmin(siteA, siteB),
siteB = pmax(siteA, siteB))
unique(df_links)
# siteA siteB weight
#1 Aiz Berr 1
#2 Aiz Cab 1
#3 Aren Atxos 2
为了避免在无向图中删除重复的顶点对,您可以使用 dist
函数,这在处理向量对之间的相似性时非常有用。当您将相似性(或权重)定义为站点(或向量)之间常见岩石的数量时,您需要传递一个自定义函数,这可以使用包 proxy 中的 dist
来完成。
#The similarity is the number of matching '1'
similarityMatrix <- as.matrix(proxy::dist(Mat, method = function(x,y){
length(which(x+y==2))
}))
similarityMatrix
# Aiz Aren Atx Berr Bra Bur Cab
#Aiz 0 0 0 1 0 0 1
#Aren 0 0 2 1 0 2 2
#Atx 0 2 0 0 0 1 2
#Berr 1 1 0 0 1 1 1
#Bra 0 0 0 1 0 0 0
#Bur 0 2 1 1 0 0 1
#Cab 1 2 2 1 0 1 0
在那里,所有成对的网站之间都有一个相似度矩阵。由于您要构建的图形是无向的,因此您需要从该矩阵中每对 select 一次。
#Unique pairwise combinations of different vectors
combinations <- t(combn(colnames(similarityMatrix), 2))
pairwiseSites <- data.frame(combinations, similarityMatrix[combinations])
colnames(pairwiseSites) <- c("siteA", "siteB", "weight")
pairwiseSites
# siteA siteB weight
#1 Aiz Aren 0
#2 Aiz Atx 0
#3 Aiz Berr 1
#4 Aiz Bra 0
#5 Aiz Bur 0
#6 Aiz Cab 1
#7 Aren Atx 2
#8 Aren Berr 1
#9 Aren Bra 0
#10 Aren Bur 2
#11 Aren Cab 2
#12 Atx Berr 0
#13 Atx Bra 0
#14 Atx Bur 1
#15 Atx Cab 2
#16 Berr Bra 1
#17 Berr Bur 1
#18 Berr Cab 1
#19 Bra Bur 0
#20 Bra Cab 0
#21 Bur Cab 1
原始数据
Mat <- read.table(header=TRUE, text="
A B C D E F G
Aiz 1 0 0 0 0 0 0
Aren 0 1 1 0 1 0 0
Atx 0 0 1 0 1 0 0
Berr 1 1 0 0 0 1 0
Bra 0 0 0 0 0 1 0
Bur 0 1 0 0 1 0 0
Cab 1 0 1 1 1 0 0")
df_links <- read.table(header=TRUE, text="
siteA siteB weight
1 Aiz Berr 1
2 Aiz Cab 1
3 Aren Atxos 2
4 Berr Aiz 1
5 Atxos Aren 2")
使用 purrr 包可以解决问题。
# reproduce input
mat <- matrix(
data = c(1,0,0,0,0,0,0,
0,1,1,0,1,0,0,
0,0,1,0,1,0,0,
1,1,0,0,0,1,0,
0,0,0,0,0,1,0,
0,1,0,0,1,0,0,
1,0,1,1,1,0,0), nrow = 7, ncol = 7)
colnames(mat) <- LETTERS[1:7]
rownames(mat) <- c("Aiz", "Aren", "Atx", "Berr", "Bra", "Bur", "Cab")
# convert to dataframe
df <- mat %>%
dplyr::as_tibble() %>%
dplyr::bind_cols(
tibble::tibble(Names = rownames(mat)))
# calculate the connections
purrr::map_df(df$Names, function(x){
output <-purrr::map_df(df$Names, function(y){
if(x >= y) return(tibble::tibble()) # avoid double counting
tibble::tibble(
siteA = x,
siteB = y,
weight = sum(as.integer(df[df$Names==x,1:7]) & as.integer(df[df$Names==y,1:7])))
})
})
祝你好运