2017-04-13 44 views
3

在从未收到创建包的两位作者的回复后,我会在下面提及,我认为这里的某个人可以对此问题有所了解。包含字符和大数字的iGraph和disparityfilter包问题

我正在处理一个包含Origin Destination对的大型数据集,以及从A到B的相应乘客。Origin和Destination变量都使用IATA机场名称(3个字母)进行编码。 原始的csv文件可以在这里找到https://github.com/FilipeamTeixeira/network。 请注意,所有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)

现在的问题是,无论何时原始数据帧的字符或数字超过4位的数字都是原始数据帧和目标数据,它将返回0.但是,当原始数据帧具有3位数的2个变量时,它工作得很好,并返回一些结果。

运行下面的代码,提供了一个清晰的问题概述。

# 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创建一个图形发生的事情,它的节点转换成字符,所以逻辑上一切都应该在年底相同。

回答

2

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

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

我将演示,然后指出问题出现在代码中的位置。然后,我会很快显示结果与当前存在的代码版本的不同以及导致“正确”输出的快速“修复”(丑陋的黑客攻击)有多不同(我是吓人的引用是正确的,吨真的知道输出应该是什么或如何测试)。

复制您发现

OK,你的网络文件的链接被打破,所以我会从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 

现在让我们创建字符和large-顶点名称的数字版本

# 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转换回gr APHS

# 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组成,文件disparity_filter.R可见here。在第58行,disparity_filter函数将backbone()中提供的图转换回数据帧。让我们做的是用图形的我们的“性格”版本:

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 

正如我们从和列在这里有我们赋予他们的名字见。然后从行63开始,disparity_filter()函数会循环使用行for (u in which(d > 1))的程度(d)大于1的情况。然后在第65行上switch声明一系列比较的节点的名称和指数ü两种情况:

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,对应于节点char25。值char25存在于向量e[,1]中,但当然不会与索引匹配 - 尽管这是作者推测的意图。在第76行开始的switch()语句中重复出现了同样的问题。由于没有匹配,当节点具有非数字名称或数字名称超过节点数时,不会返回任何结果。

问题有多严重?

好吧,那么节点的名称从一个起算的情况如何呢?让我们来看看ue[,1]的值是什么。我们将使用图形的版本顶点的名字是“工作”:

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 

OK,我们只得到9个观察回:所以他们对应的指数,我们将重命名的顶点!显然,该功能有些问题。这个新答案是否正确?老实说,我不确定,因为我不确定输出应该是什么,或者我可以如何验证它。此外,如果我要依赖代码,我想真正重做比较以匹配名称和名称。

无论如何,我的建议是,除非软件包作者有机会修复它,否则不要使用这个函数。我将在github上打开一个bug报告。

+0

我已经在几个月前在github上创建了一个bug报告,他们从未回复过。但事实上,你对相关部门的分析是正确的。我冒昧地根据'tidyverse'软件包自己创建一些代码,从而产生更接近原始发表的论文的结果。 – FilipeTeixeira

+0

嗯这太糟糕了,他们没有解决它。 CRAN软件包的下载量为7k,但不应该以目前的形式真正使用。也许你可以在这里链接到你的算法工作版本(如果它在github上)那些搜索答案的人? – gfgm

+0

我把它作为一个包的一部分,我一直在开发其他东西,可以在这里找到https://github.com/FilipeamTeixeira/skynet。但是,您可以将其作为单独的R文件在那里调用disparityfilter.R。这是一个相当简单的实现,但到目前为止它达到了目的,并且与原始论文的结果相匹配。 – FilipeTeixeira