问题描述
我有一个直接从属关系矩阵,我想将其转换为边缘列表。矩阵如下:
State WarID Initiator
A 1 1
B 1 0
A 2 1
C 2 0
D 2 0
B 3 1
C 3 1
D 3 0
其中“州”是国家/地区的名称,“ WarID”是战争的唯一标识符,而“发起者”是一个虚拟变量,如果州发起战争,则该变量等于1。如果两个州共享相同的“ WarID”,但“ Initiator”的值不同,则这两个州之间会有一条边缘。
我想将上面的隶属关系矩阵更改为这样的边列表:
Initiator Target WarID
A B 1
A C 2
A D 2
B D 3
C D 3
我知道如何将基本隶属关系矩阵更改为边缘列表,但是我在保留“定向网络”组件方面遇到了困难。如果有人能告诉我如何有效地在R中执行此操作,我将不胜感激(我有一个相当大的隶属关系矩阵)。
解决方法
您可以使用tidyverse:
library(tidyverse)
df %>%
group_by(WarID) %>%
summarise(Target = list(State[Initiator==0]),Initiator = list(State[Initiator==1]),.groups='drop') %>%
unnest(c(Initiator,Target)) %>%
rev() # Just to reverse the ordering,otherwise not necessary
# A tibble: 5 x 3
Initiator Target WarID
<chr> <chr> <int>
1 A B 1
2 A C 2
3 A D 2
4 B D 3
5 C D 3
,
这项工作:
> library(dplyr)
> df %>% group_by(WarID) %>% filter(Initiator == 1) %>%
+ inner_join(df %>% group_by(WarID) %>% filter(Initiator == 0),by = ('WarID')) %>% rename(Target = State.y,Initiator = State.x ) %>%
+ select(1,4,2)
# A tibble: 5 x 3
# Groups: WarID [3]
Initiator Target WarID
<chr> <chr> <dbl>
1 A B 1
2 A C 2
3 A D 2
4 B D 3
5 C D 3
>
使用的数据:
> dput(df)
structure(list(State = c("A","B","A","C","D","D"
),WarID = c(1,1,2,3,3),Initiator = c(1,0)),class = c("spec_tbl_df","tbl_df","tbl","data.frame"
),row.names = c(NA,-8L),spec = structure(list(cols = list(
State = structure(list(),class = c("collector_character","collector")),WarID = structure(list(),class = c("collector_double",Initiator = structure(list(),"collector"))),default = structure(list(),class = c("collector_guess",skip = 1),class = "col_spec"))
>
,
您可以使用WarID
将数据按Initiator
和tapply
分组,并为每个expand.grid
制作一个WarID
。只需rbind
的结果即可。
FUN <- function(d) {
r <- with(d,tapply(State,list(WarID,Initiator),I))
r <- lapply(1:nrow(r),function(i) cbind(expand.grid(rev(r[i,])),i))
r <- setNames(do.call(rbind,r),c("Initiator","Target","WarID"))
r
}
FUN(d)
# Initiator Target WarID
# 1 A B 1
# 2 A C 2
# 3 A D 2
# 4 B D 3
# 5 C D 3
请注意,我使用了您指定的连续WarID
。
数据:
d <- structure(list(State = c("A",WarID = c(1L,1L,2L,3L,3L),Initiator = c(1L,0L,0L)),class = "data.frame",-8L))