在单独的行中拆分字符串的有效方法(创建边缘列表)

时间:2017-10-31 14:27:10

标签: r string split

我目前遇到以下问题。我使用Web-of-Science科学出版物和引文数据,它具有以下结构:变量“SR”是具有出版物名称的字符串,“CR”是带有包含文章中所有引用参考文献的字符串的变量,以“;”分隔。

我现在的任务是在具有相应引用的所有出版物之间创建边缘列表,其中每个出版物和引文组合都在一行中。我目前使用以下代码执行此操作:

# Some minimal data for example
pub <- c("pub1", "pub2", "pub3")
cit <- c("cit1;cit2;cit3;cit4","cit1;cit4;cit5","cit5;cit1")
M <- cbind(pub,cit)
colnames(M) <- c("SR","CR")

# Create an edgelist
cit_el <- data.frame() # 
for (i in seq(1, nrow(M), 1)) { #   i=3
  cit <- data.frame(strsplit(as.character(M[i,"CR"]), ";", fixed=T), stringsAsFactors=F) 
  colnames(cit)[1] <- c("SR")
  cit$SR_source <- M[i,"SR"]
  cit <- unique(cit)
  cit_el <- rbind(cit_el, cit)
}

然而,对于大约10k +的出版物(通常有50多次引用)的大型数据集,该脚本运行15分钟+。我知道循环通常是一种低效的R编码方式,但却找不到能产生我想要的东西。

任何人都知道一些让它更快的技巧吗?

2 个答案:

答案 0 :(得分:1)

不确定这是否更快,但如果我正确理解,这应该会给出所需的结果

rbindlist(lapply(1:nrow(M), function(i){
data.frame(SR_source = M[i, 'SR'], SR = strsplit(M[i, 'CR'], ';'))
}))

答案 1 :(得分:1)

这是我的尝试。我还没有比较不同方法的速度。

首先是拥有10k个酒吧的人工数据,可能引用10万次,每个酒吧最多引用80次。

library(data.table)
library(stringr)

pubCount = 10000

citCount = 100000 

maxCitPerPub = 80

pubList <- paste0("pub", seq(pubCount))

citList <- paste0("cit", seq(citCount))

cit <- sapply(sample(seq(maxCitPerPub), pubCount, replace = TRUE),
               function(x) str_c(sample(citList, x), collapse = ";"))

data <- data.table(pub = pubList,
                   cit = cit)

为了处理,我使用stringr :: str_split_fixed将引文拆分成列,并使用data.table :: melt来折叠列。

temp <- data.table(pub = pubList, str_split_fixed(data$cit, ";", maxCitPerPub))

result <- melt(temp, id.vars = "pub")[, variable:= NULL][value!='']