2017-04-13 82 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