iGraph和disparityfilter包有字符和大数字的问题

时间:2017-04-13 08:35:24

标签: r igraph

在我从未得到创建该软件包的两位作者的回复后,我认为这里有人可以解释这个问题。

我正在使用包含Origin Destination对的大型数据集,以及从A到B的相应乘客。原点和目的地变量都使用IATA机场名称(3个字母)进行编码。 可以在https://github.com/FilipeamTeixeira/network找到原始csv文件。 请注意,所有3个csv文件都是相同的,除了那个具有ORIGIN / DEST变量作为字符,另一个作为数字,第三个作为较大的数字。但是出于网络目的,它们与提供相同数量的连接完全相同。

    ORIGIN  DEST    weight
     ABE    ATL     1530
     ABE    AVP     6
     ABE    BDL     2
     ABE    BOS     1
     ABE    BWI     3
     ABE    CLT     1053

导入文件后,我使用a <- graph_from_data_frame(netchr, directed = TRUE)创建了一个新图表。

然后,由于我通常使用大型数据集,我使用差异过滤器https://github.com/alessandrobessi/disparityfilter/blob/master/R/disparity_filter.R来查找网络的骨干结构,并减少边/节点的数量。

为此我运行backbone(a)

现在的问题是,只要原始数据框的Origin和Destination变量为字符或数字超过4位数,它就会返回0.但是当原始数据帧有2个变量而是3位数时,效果非常好,它会返回一些结果。

运行下面的代码,可以清楚地概述问题。

# Import network
# Imports csv

netchr <- read.csv("netchr.csv", header = TRUE,sep = “,”, stringsAsFactors = FALSE)

netnumber <- read.csv("netnum.csv", header = TRUE, sep = “,”, stringsAsFactors = FALSE)

netnumber2 <- read.csv("netnum2.csv", header = TRUE, sep = “,”, stringsAsFactors = FALSE)

# Load igraph and dispfilter

library(igraph)
library(disparityfilter)

a <- graph_from_data_frame(netchr, directed = TRUE)

b <- graph_from_data_frame(netnumber, directed = TRUE)

c <- graph_from_data_frame(netnumber2, directed = TRUE)

# Create backbone network

backbone(a) # finds 0

backbone(b) # has results

backbone(c) # finds 0

我真的很难理解可能发生的事情,即使iGraph创建了一个图形,它也会将节点转换为字符,所以逻辑上一切都应该是相同的。

1 个答案:

答案 0 :(得分:4)

问题源于disparityfilter包中的错误。 disparity_filter函数的内部由backbone()调用,涉及将节点名称与节点索引(一个错误)进行比较,因此该函数仅在节点名称恰好等于节点时才起作用指数。要清楚,这意味着在通用情况下(例子中的情况b),结果可能都是错误的 - 尽管有些东西会被返回。

将索引与名称进行比较是函数不返回带有字符的任何内容的原因,也是它没有返回大数字的原因:如果数字的大小超过了节点的数量网络匹配永远不会发生。

我将演示,然后指出问题在代码中的位置。然后,我会快速显示结果与当前存在的代码版本的不同之处以及快速修复的结果。 (丑陋的黑客)导致“正确的”#39;输出(我引用正确的引用,因为我不知道输出应该是什么或者如何测试它。)

复制您的发现

好的,您网络文件的链接已损坏,因此我将使用igraphdata包中的一些数据:

# Load the requisite libraries
library(igraph)
library(disparityfilter)
library(igraphdata)

# We'll use the enron email network (b/c cool)
data(enron)

# convert it to a df
df <- igraph::as_data_frame(enron, what = 'edges')
summary(df) # we see nodes numbered from 1:184
#>       from             to          Time            Reciptype        
#>  Min.   :  1.0   Min.   :  1   Length:125409      Length:125409     
#>  1st Qu.: 64.0   1st Qu.: 64   Class :character   Class :character  
#>  Median :108.0   Median :113   Mode  :character   Mode  :character  
#>  Mean   :105.4   Mean   :108                                        
#>  3rd Qu.:156.0   3rd Qu.:156                                        
#>  Max.   :184.0   Max.   :184                                        
#>      Topic         LDC_topic     
#>  Min.   :0.000   Min.   :-1.000  
#>  1st Qu.:1.000   1st Qu.: 0.000  
#>  Median :1.000   Median : 0.000  
#>  Mean   :1.711   Mean   : 2.572  
#>  3rd Qu.:3.000   3rd Qu.: 1.000  
#>  Max.   :3.000   Max.   :32.000

# create a weights variable
df$weight <- df$Topic

现在让我们创建字符和大量版本的顶点名称

# Create a char version of the nodes by appending 'char' to the number
dfchar <- df
dfchar$from <- paste0("char", dfchar$from)
dfchar$to <- paste0("char", dfchar$to)

# create a big num version
dfbnum <- df
dfbnum$from <- 1000 * dfbnum$from
dfbnum$to <- 1000 * dfbnum$to

现在我们将data.frames转换回图表

# Now convert the DFs back to graphs
smallnum <- graph_from_data_frame(df, directed = TRUE)

chars <- graph_from_data_frame(dfchar, directed = TRUE)

bignum <- graph_from_data_frame(dfbnum, directed = TRUE)

然后我们可以在这三个图表中运行backbone()来复制您找到的内容:

## Now we document what you found: namely the anomolous behavior of backbone
newbbs <- backbone(smallnum)
dim(newbbs)
#> [1] 231   4

newbbc <- backbone(chars) 
dim(newbbc)
#> [1] 0 4

newbbb <- backbone(bignum)
dim(newbbb)
#> [1] 0 4

正如您所指出的那样,即使在其他数据上,backbone()函数也找不到匹配项,除非节点通常标记为1:N

发现问题

好的,到目前为止我正在复制你记录的内容。我们如何知道backbone()内的索引问题?首先让我告诉你如果我们让节点的名称比它们的索引大一点会发生什么:

# now to demonstrate the indexing issue quickly, lets increment
# the node names just a bit, and see what gets returned.
# create a medium num version
dfmnum <- df
dfmnum$from <- dfmnum$from + 90 #add about half the number of nodes to the name
dfmnum$to <- dfmnum$to + 90

# convert back to graph
midnum <- graph_from_data_frame(dfmnum)
bbmid <- backbone(midnum)
dim(bbmid)
#> [1] 28  4

正如您所看到的,这会极大地改变功能的性能 - 而不是找到231个结果,我们发现了28个!原因是一半的节点名称现在与索引没有匹配,大约有一半 - 所以我们得到随机(并且完全不正确)的结果。

问题在哪里?

disparityfilter包位于github上,由文件disparity_filter.R组成,可以看到here。在第58行,disparity_filter函数将backbone()中提供的图形转换回数据帧。让我们用我们的角色做这件事&#39;图表的版本:

e <- igraph::as_data_frame(chars)[,1:2]
head(e)
    from      to
1 char25 char154
2 char25 char154
3 char30  char30
4 char30  char30
5 char30  char30
6 char30  char30

我们可以看到这里的from和to列有我们分配的名称。然后从第63行开始,disparity_filter()函数使用行d循环遍历度(for (u in which(d > 1)))大于1的情况。然后在第65行的switch语句中,对节点名称和索引 u进行了一系列比较:

w = switch(substr(mode, 1, 1),
      a = which(e[, 1] == u | e[, 2] == u),
      i = which(e[, 2] == u),
      o = which(e[, 1] == u)
)

这显然不正确,只有在节点名称恰好与其索引匹配时才有效。明确地说,使用我们的chars版图表,u的第一个值将是1,对应于节点char25char25值存在于向量e[,1]中,但当然永远不会与索引匹配 - 尽管这是作者可能想要的。下面在第76行开头的switch()语句中重复了同样的问题。由于没有匹配项,当节点具有非数字名称或数字名称超过节点数时,不会返回任何内容。

问题有多严重?

那么节点的名称从一个开始的情况怎么样?让我们来看看ue[,1]的值是什么。我们将使用图表的版本,其顶点名称为&#39;工作&#39;:

d <- degree(smallnum)
which(d>1)
 25  30  39  52  61  64  66  67  93 100 115 125 138 141 146 156 164 168 170 
  1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19 

正如我们所看到的,顶点的数字名称无论如何都不对应于索引!因此,即使在某些东西被归还的情况下,我们也只是在回复噪音。快速编辑以查看差异;我们将重命名顶点,使它们对应于它们的索引:

renamed <- set.vertex.attribute(smallnum, "name", value=1:length(V(smallnum)))
bbs_problem_revealed <- backbone(renamed)
dim(bbs_problem_revealed)
[1] 9 4

好了,现在指数与顶点匹配,我们只得到9个观察结果!显然,这个功能有些不对劲。这个新答案是否正确?老实说,我不确定,因为我不确定输出应该是什么或我如何验证它。此外,如果我要依赖代码,我想真的重做比较,将名称与名称匹配。

无论如何,我的建议是在包装作者有机会修复它之前不要使用此功能。我将在github上打开一个错误报告。