简体   繁体   English

如何转换二部网络并使用一层的节点属性作为 igraph (R) 中第二层的边权重

[英]How to transform a bipartite Network and use node attributes from one level as edge weights in the second level in igraph (R)

Im trying right now to transfer a bipartite two-mode graph to its one-mode representation.我现在正在尝试将二分二模式图转换为其单模式表示。 The issue is that I want to conserve node atrributes from the two-mode graph to the one-mode representations.问题是我想将节点属性从双模式图保存到单模式表示。 For example a dataframe is given by:例如,数据帧由以下给出:

Person EventLocation DurationEvent Peter Bar 90 Jack Bar 90 Franz Train 20 Franz Bar 90 Laurie Train 20 Jack Train 20 ...

Now I want to get persons network using the igraph function bipartite_projection() on the Person and EventLocation columns but I see no ways how to presafe additional node attributes (duration) that might be transfer to edge weights between Persons, eg Peter-Jack with weight 90 or Franz-Laurie with weight 20.现在我想在 Person 和 EventLocation 列上使用 igraph 函数 bipartite_projection() 来获取人员网络,但我看不到如何预先保护可能转移到人员之间的边缘权重的附加节点属性(持续时间),例如具有权重的彼得杰克90 或 Franz-Laurie 重量为 20。

Edit: I´ve added the last row to be more precise.编辑:为了更精确,我添加了最后一行。 The edge "Jack-Franz" would now correspond to 90+20 = 110. But basically my issue is just related how to implement a bipartite_projection which transfers the node attribute of a bipartite igraph-network to the correspoding edge attribute in the one-mode igraph-network.边“Jack-Franz”现在对应于 90+20 = 110。但基本上我的问题只是与如何实现一个 bipartite_projection 相关,它将二分 igraph 网络的节点属性传输到单模式中的对应边属性igraph-网络。

Edit 2: I just added another example.编辑 2:我刚刚添加了另一个示例。 First, I create a network among persons then I want to add the budget informations to the persons edges implying how much project budget did the both attracted together (the sum of budgets only from different unique projects as weights).首先,我在人之间创建一个网络,然后我想将预算信息添加到人的边缘,暗示两者吸引了多少项目预算(仅来自不同独特项目的预算总和作为权重)。 Then I wanted to do some further weighted centrality calculations:然后我想做一些进一步的加权中心性计算:

person_id <- c("X","Y","Z","Q","W","E","R","X","Y")
project <- c("a","b","c","a","a","b","c","b","a")
budget <- c(100,200,300,100,100,200,300,200,100)
employ.data <- data.frame(person_id, project, budget)
View(employ.data)
sna.complete.list <- employ.data
sna.list.complete.igraph.calc <- graph.data.frame(sna.complete.list)
V(sna.list.complete.igraph.calc)$type <- V(sna.list.complete.igraph.calc)$name%in%sna.complete.list$person_id
sna.list.complete.igraph.calc.one <- try(bipartite.projection(sna.list.complete.igraph.calc, type=V(sna.list.complete.igraph.calc)$type))
sna.statistics.persons <- sna.list.complete.igraph.calc.one[[2]]
plot.igraph(sna.statistics.persons)

EDIT3: I try to reformulate my concern: EDIT3:我尝试重新表述我的担忧:

Overall Goal: Get an weighted graph (edge values between nodes weighted with some values)总体目标:得到一个加权图(节点之间的边值用一些值加权)

Outline/Data:大纲/数据:

  1. Data on people participating in different projects that differ in budget size参与预算规模不同的不同项目的人员的数据

  2. Convert bipartite connection graph (People-Project) to one-mode-People-People-graph将二分连接图(People-Project)转换为单模-人-人-图

  3. Use the budget sizes as weights for the edges between the people.使用预算大小作为人与人之间边缘的权重。

BUT for two people this value should only account for the sum of participating at unique projects.但是对于两个人来说,这个值应该只占参与独特项目的总和。 Thus, if A and B are only connected by project x of budget size 100 should result in an edge-weight of 100. If they also participate in another project with value 20, the result should be 120 etc.因此,如果 A 和 B 仅通过预算大小为 100 的项目 x 连接,则应导致边权重为 100。如果他们还参与另一个值为 20 的项目,则结果应为 120,以此类推。

I tried to transfer this information during using bipartite.projection but failed or couldn´t implement this information afterwards.我尝试在使用 bipartite.projection 期间传输此信息,但之后失败或无法实现此信息。

The bipartite_projection() can collect only structural weights of edges , that is to say, Peter and Jack are both affiliated to both Train and Bar. bipartite_projection()只能收集edges 的结构权重,也就是说Peter 和Jack 都隶属于Train 和Bar。 To handle edge -attributes is trickier.处理边缘属性比较棘手。

If you only want to perserve the node -attributes, as you write above bipartite_projection() absolutely does that for you already.如果您只想保留节点属性,正如您在上面写的那样bipartite_projection()绝对已经为您做到了。 Just re-project and find your attributes preserved like so:只需重新投影并找到像这样保留的属性:

V(unipartite_graph)$your_attributee

If you need to preserve edge -attributes when re-projecting, however, there are several questions to ask before.但是,如果您需要在重新投影时保留边缘属性,那么之前有几个问题要问。

  • How should multiple paths be treated when Franz-Train-Jack also has Franz-Bar_Jack?当 Franz-Train-Jack 也有 Franz-Bar_Jack 时,应该如何处理多条路径?
  • What role does directionality have in the calculation方向性在计算中起什么作用

I needed the exact same thing some years back, and solved it by writing my own extended re-projection function.几年前我需要完全相同的东西,并通过编写我自己的扩展重投影函数来解决它。 It is perhaps not the shortest way around this, but calculates sums of a given edge-attribute by the shortest path between each unipartite-vertex-pair in the bipartite graph and returns an graph with one edge-attribute preserved (and summarised).这也许并不解决这个最短的方式,但通过二分图的每个单部分顶点对和返回与一个边缘的属性的图形之间的最短路径计算给定边缘属性的总和保存(总结)。

具有汇总边缘属性的重投影

Note that the function does not calculate the unipartite Laurie-Peter.请注意,该函数不计算单分 Laurie-Peter。 You could manipulate the function to your liking.您可以根据自己的喜好操作该功能。

This reproduces your example data and applies my function这会重现您的示例数据并应用我的功能

# Reproduce your data
df <- data.frame(Person = c("Peter","Jack","Franz","Franz","Laurie","Jack"),
                 EventLocation = c("Bar","Bar","Train","Bar","Train","Train"),
                 DurationEvent = c(90,90,20,90,20,20), stringsAsFactors = F)


## Make bipartite graph from example data
g <- graph_from_data_frame(df, directed=FALSE)
# Set vertex type using bipartite.mapping() (OBS type should be boolean for bipartite_projection())
V(g)$type <- bipartite.mapping(g)$type


## Plot Bipartite graph
E(g)$label <- E(g)$DurationEvent
V(g)$color <- ifelse(V(g)$type, "red", "yellow")
V(g)$size <- ifelse(V(g)$type, 40, 20)
plot(g, edge.label.color="gray", vertex.label.color="black")

# Function to reproject a bipartite graph to unipartite projection while
# calculating an attribute-value sum between reprojected vertecies.
unipartite_projection_attr <- function(graph_bi, attribute, projection=FALSE){

  ## Make initial unipartite projection
  graph_uni <- bipartite_projection(graph_bi, which=FALSE)

  ## List paths in bipartite-graph along which to summarise selected attribute
  el <- as_edgelist(graph_uni)
  el <- matrix(sapply(el, function(x) as.numeric(which(x == V(graph_bi)$name))), ncol=2)

  ## Function to summarise given atribute-value
  summarise_graph_attribute_along_path <- function(source, target, attribute){
    attr_value <- edge_attr(g, attribute)
    path <- get.shortest.paths(g, source, target, output="epath")$epath[[1]]
    sum(E(g)$DurationEvent[path])
  }

  attr_uni <- mapply(summarise_graph_attribute_along_path, el[,1], el[,2], attribute)
  graph_uni <- set_edge_attr(graph_uni, attribute, value=attr_uni)

  (graph_uni)
}

# Use function to make unipartite projection
gg <- unipartite_projection_attr(g, "DurationEvent", FALSE)

# Visualise
V(gg)$color <- "yellow"
E(gg)$label <- E(gg)$DurationEvent
plot(gg, edge.label.color="gray", vertex.label.color="black")

Best of luck祝你好运

Heavily borrowing from @nGL's answer, I changed the code a bit to account for all the shortest paths between 2 Persons and taking their cumulative Event Duration as their edge weight in the projected graph.大量借鉴@nGL 的回答,我稍微更改了代码以考虑 2 个人之间的所有最短路径,并将其累积事件持续时间作为投影图中的边权重。

Resulting graph looks like this (eg edge weight between Jack and Franz = 110):结果图如下所示(例如,Jack 和 Franz 之间的边权重 = 110):

在此处输入图片说明

One word of caution: this assumes that the original weights are equally distributed between Persons (ie Jack and Franz meet for 90 minutes in the Bar).一个警告:这假设原始权重在个人之间平均分配(即 Jack 和 Franz 在酒吧相遇 90 分钟)。 In other situations, Jack and Franz might visit the same Bar but for Jack the Duation is 70 and for Franz it is 110. Then one would need to think about whether taking the average is appropriate or another measure (eg, min or max).在其他情况下,Jack 和 Franz 可能会访问同一个 Bar,但对于 Jack 来说,Dation 是 70,而对于 Franz 来说是 110。然后需要考虑取平均值或其他度量(例如,最小或最大)是否合适。

# Reproduce your data
df <- data.frame(Person = c("Peter","Jack","Franz","Franz","Laurie","Jack"),
                 EventLocation = c("Bar","Bar","Train","Bar","Train","Train"),
                 DurationEvent = c(90,90,20,90,20,20), stringsAsFactors = F)


## Make bipartite graph from example data
g <- graph_from_data_frame(df, directed=FALSE)
# Set vertex type using bipartite.mapping() (OBS type should be boolean for bipartite_projection())
V(g)$type <- bipartite.mapping(g)$type


## Plot Bipartite graph
E(g)$label <- E(g)$DurationEvent
V(g)$color <- ifelse(V(g)$type, "red", "yellow")
V(g)$size <- ifelse(V(g)$type, 40, 20)
plot(g, edge.label.color="gray", vertex.label.color="black")

# Function to reproject a bipartite graph to unipartite projection while
# calculating an attribute-value sum between reprojected vertecies.
unipartite_projection_attr <- function(graph_bi, attribute, projection=FALSE){
  
  ## Make initial unipartite projection
  graph_uni <- bipartite_projection(graph_bi, which=projection)
  
  ## List paths in bipartite-graph along which to summarise selected attribute
  el <- as_edgelist(graph_uni)
  el <- matrix(sapply(el, function(x) as.numeric(which(x == V(graph_bi)$name))), ncol=2)
  
  ## Function to summarise given atribute-value
  summarise_graph_attribute_along_path <- function(source, target, attribute){
    attr_value <- edge_attr(graph_bi, attribute)
    path <- lapply(get.all.shortest.paths(graph_bi, source, target)$res, function(x) E(g, path=x))
    sum(unlist(lapply(path, function (x) mean(attr_value[x]))))
  }
  
  attr_uni <- mapply(summarise_graph_attribute_along_path, el[,1], el[,2], attribute)
  graph_uni <- set_edge_attr(graph_uni, attribute, value=attr_uni)
  
  (graph_uni)
}

# Use function to make unipartite projection
gg <- unipartite_projection_attr(graph_bi = g, attribute = "DurationEvent", projection = FALSE)

# Visualise
V(gg)$color <- "yellow"
E(gg)$label <- E(gg)$DurationEvent
plot(gg, edge.label.color="gray", vertex.label.color="black")

FYI: I also changed the code at a few lines to ensure it is fully reproducable when using other attributes (eg, replacing E(g)$DurationEvent with attr_value)仅供参考:我还更改了几行代码,以确保在使用其他属性时可以完全重现(例如,将 E(g)$DurationEvent 替换为 attr_value)

Additional word of caution: if your graph already has a weight argument, you need to set weights = NA in get.all.shortest.paths(graph_bi, from = source, to = target, weights = NA)额外的警告:如果你的图已经有一个权重参数,你需要在get.all.shortest.paths(graph_bi, from = source, to = target, weights = NA)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM