R创建边缘列表

时间:2015-03-30 17:42:41

标签: r algorithm networking

Stack Overflow的新功能,即使我已经检查了你们发布的内容并回答了很长一段时间(只是没有时间在我的主人的工作中加入)。

TL; DR:我使用此处提供的脚本来处理如下结构的数据集,以获得网络的边缘。它起作用但是花了太长时间来处理(2k行24小时)。向初学R用户提示加快哪些提示?

在我的上一个研究项目中,我最终得到的数据框架非常像:

ID | Trait 1 | Trait 2 | Trait 3 | Trait 4 |  Trait 5
01 |  TRUE   |   TRUE  |  Photo  |   City  |  Portrait
02 |  FALSE  |   TRUE  |  Draw   |  Child  |  Portrait
03 |  TRUE   |  FALSE  |  Photo  |   Misc  |  Landscape
.
.
.

这持续了大约2k行。目的是建立一个网络,其中每个ID是一个节点,2个ID之间的共同特征的总和将组成一个加权边缘,即ID 01将具有ID 2和3的权重2边缘,而ID 2将没有ID 3的优势。

为了解决这个问题,我使用以下脚本运行每一行,比较每个列值以增加权重(每个匹配= +1),忽略已经比较的行(作为无向网络,没有必要匹配两种方式) :

Key:Source =要比较的ID;目标=正在比较的ID;重量=匹配细胞/性状的总和。

findEdges <- function(){
    input <- read.csv("nodes.csv",header=TRUE,stringsAsFactors=FALSE,sep=";")
    edges <- read.csv("edges.csv",header=TRUE,stringsAsFactor=FALSE,skip=1,colClasses=c("integer","integer","integer"),col.names=c("Source","Target","Weight"))    
    for(i in 1:nrow(input)){ #row to be compared: Source
        for(j in 1:nrow(entrada)){ #rows that will compare to: Target
            weight <- 0
            if( i >= j ){
            } else {
                for(k in 1:ncol(input)){ #column by column comparison
                    col <- k
                    if(input[i,k] == input[j,k]){ #edge weight modifier
                        weight <- weight+1
                        }
                }
                print(c("source= ",i,"target= ",j,"weight= ",weight)) #visual feedback of running script
                newRow <- data.frame(Source=i,Target=j,Weight=weight) #create row for compared pair
                edges <- rbind(edges,newRow) # add edge row to data frame
            }
        }
    }
    write.csv(edges,"edges.csv") #write data frame to csv file
}
findEdges()

工作得很好,给了我所需的加权边缘列表。 edgelist的每一行都是presentes:

Source | Target | Weight
  01   |   02   |   2
  01   |   03   |   2

依旧......

然而,这个脚本花了差不多24小时来处理整个数据集(2k行,除了ID之外的5列),虽然之前不是问题,但我认为检查更好/更快的一些提示会很好实现相同结果的方法。

1 个答案:

答案 0 :(得分:1)

一种方法是分别处理每个列,在每个行之间生成成对相似性矩阵。例如,让我们假装我们在一个列上进行操作:

col <- c(1, 1, 2, 3, 2, 4)
outer(col, col, "==") * 1
#      [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    1    1    0    0    0    0
# [2,]    1    1    0    0    0    0
# [3,]    0    0    1    0    1    0
# [4,]    0    0    0    1    0    0
# [5,]    0    0    1    0    1    0
# [6,]    0    0    0    0    0    1

outer函数在每对元素之间执行运算符(==),返回矩阵(*1仅用于转换TRUE / {{1}到0/1)。一个很好的方面是,这是一个矢量化运算符,因此与涉及for循环的方法相比,它将非常快速地工作。

现在,很清楚我们需要做的就是为每一列获取一个相似度矩阵并将它们全部添加起来。

FALSE

此函数已确定每行具有与其自身共同的所有5列。更多行1和2共有3个元素,第1行和第3行共有1个元素,第2行和第3行没有共同的元素。

您可以轻松地从图表的宽表示到长表示转换(此处我已经过滤了自我链接和源ID为&gt;目标ID的边缘):

(dat <- data.frame(ID=c(1, 2, 3), T1=c(F, F, T), T2=c(T, T, F), T3=c("Photo", "Draw", "Photo"), T4=c("City", "Child", "Misc"), T5=c("Portrait", "Portrait", "Landscape")))
#   ID    T1    T2    T3    T4        T5
# 1  1 FALSE  TRUE Photo  City  Portrait
# 2  2 FALSE  TRUE  Draw Child  Portrait
# 3  3  TRUE FALSE Photo  Misc Landscape
(res <- Reduce("+", lapply(2:ncol(dat), function(x) outer(dat[,x], dat[,x], "=="))))
#      [,1] [,2] [,3]
# [1,]    5    3    1
# [2,]    3    5    0
# [3,]    1    0    5

基准测试表明,矢量化subset(cbind(expand.grid(Source=dat$ID, Target=dat$ID), Weight=as.vector(res)), Source < Target) # Source Target Weight # 4 1 2 3 # 7 1 3 1 # 8 2 3 0 函数比for循环具有更大的优势:

outer

我们使用矢量化方法为100行实现了大约1000倍的加速。