在巨大数据集R上比较时间值的有效方法

时间:2015-08-04 11:24:08

标签: r loops datetime difference wikidata

我正在使用R对维基数据转储进行分析。我之前从XML转储中提取了我需要的变量,并在较小的csv文件中创建了自己的数据集。这是我的文件的样子。

Q939818;35199259;2013-05-04T20:28:48Z;KLBot2;/* wbcreateclaim-create:2| */ [[Property:P373]], Tour de Pologne 2010
Q939818;72643278;2013-09-26T03:46:26Z;Coyau;/* wbcreateclaim-create:1| */[[Property:P107]]: [[Q1656682]]
Q939818;72643283;2013-09-26T03:46:28Z;Coyau;/* wbcreateclaim-create:1| */[[Property:P31]]: [[Q2215841]]
Q939818;90117273;2013-11-28T14:14:04Z;DanmicholoBot;/* wbsetlabel-add:1|nb */from the [no] label
Q939818;90117281;2013-11-28T14:14:07Z;DanmicholoBot;/* wbsetlabel-remove:1|no */
Q939818;92928394;2013-11-28T14:14:07Z;DanmicholoBot;/* wbsetlabel-remove:1|no */

不幸的是,提取变量的脚本有时会跳过某些标记,因此在某些行中,项ID(第一个值)不存在,并被“wikimedia page”替换。

我想通过检查第三列中的时间来推断缺少的项目ID:如果缺少值的行中的时间在下一个之前,那么我可以假设项目ID是相同的(它们是同一价值的两个修订版)。否则,项目ID将与上一行相同。

为此,我编写了一些代码,首先检查第一列中带有“wikimedia page”的所有行,然后执行我刚才描述的内容:

wikimedia_lines <- grep("wikimedia page", wikiedits_clean$V1)

for (i in wikimedia_lines){
  if (wikiedits_clean$time[i] < wikiedits_clean$time[i + 1]) {
     wikiedits_clean$V1[i] <- wikiedits_clean$V1[i + 1] 
  }
  else {wikiedits_clean$V1[i] <- wikiedits_clean$V1[i - 1] }
}

但是,由于我的文件非常大(约6.5M行),因此需要花费大量时间来执行循环。是否有更多'R-style'(如使用apply或sapply)解决方案可以更有效地实现这一目标?

谢谢。

2 个答案:

答案 0 :(得分:0)

我建议如下:

data <- read.table(filename,
                   sep=";",
                   header=TRUE,
                   colClasses=c("character","character","character","character","character"))

data$time <- as.POSIXct(data$time,format="%Y-%m-%dT%H:%M:%S")

m <- which( data$ID == "wikimedia page" )
n <- m[which( data$time[m]-data$time[m+1] >= 0 )]

cleanData <- data

cleanData$ID[n]             <- data$ID[n-1]
cleanData$ID[setdiff(m,n)]  <- data$ID[setdiff(m,n)+1]

“m”是行号的向量,其中缺少“ID”。 “n”是“m”中那些行号的向量,其中时间不是下一行中的时间。

答案 1 :(得分:0)

如果连续行中缺少ID,我之前的解决方案无法填补所有空白。 以下解决方案更复杂,但它可以处理这种情况:

data <- read.table(filename,
                   sep=";",
                   header=TRUE,
                   colClasses=c("character","character","character","character","character"))

data$time <- as.POSIXct(data$time,format="%Y-%m-%dT%H:%M:%S")

m <- sort( which( data$ID == "wikimedia page" ) )
d <- diff(c(-1,m))
e <- diff(c(0,diff(m)==1,0))

b1 <- c(-Inf, m[which( e>0 | (d>1 & e==0) )], Inf)
b2 <- c(-Inf, m[which( e<0 | (d>1 & e==0) )], Inf)

k1 <- b1[unlist(lapply( m, function(x){ which.max(x<b1)-1 }))]
k2 <- b2[unlist(lapply( m, function(x){ which.max(x<=b2)  }))]

n1 <- which(((data$time[k2+1]-data$time[m]<0) & k1>1) | k2==nrow(data) )
n2 <- setdiff(1:length(m),n1)

cleanData <- data

cleanData$ID[m[n1]] <- data$ID[k1[n1]-1]
cleanData$ID[m[n2]] <- data$ID[k2[n2]+1]

和以前一样,&#34; m&#34;是缺少ID的行号的向量。 向量&#34; b1&#34;和&#34; b2&#34;包含&#34; m&#34;中的那些行号。其中一个连续缺失ID的块 分别开始和结束,即这些块的下限和上限。 所以&#34; m&#34;是区间的联合&#34; b1 [i]:b2 [i]&#34;在哪里&#34;我&#34;从1开始到&#34; b1&#34;和&#34; b2&#34;。 还&#34; k1&#34;和&#34; k2&#34;包含这些边界,但它们的长度与&#34; m&#34;相同。和&#34; m [j]&#34;包含在 阻止&#34; k1 [j]:k2 [j]&#34;对于每个索引&#34; j&#34;。 &#34; m [j]&#34;&n;行中的ID设置为&#34; k1 [j] -1&#34;&#中的一个ID&#; 39; s行或&#34; k2 [j] + 1&#34;&n;行。 &#34; m [j]&#34;&#34;&#34;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&pbsp; 导致向量&#34; n1&#34;和&#34; n2&#34;,决定选择哪一个。

相关问题