比较大型数据集 R 上时间值的有效方法
Efficient way to compare time values over huge dataset R
我正在使用 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] }
}
但是,由于我的文件很大(约 650 万行),执行循环需要花费很多时间。是否有更多 'R-style'(例如使用 apply 或 sapply)解决方案可以更有效地做到这一点?
谢谢。
我建议如下:
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" 中那些行号的向量,其中时间不早于下一行中的时间。
如果 连续 行中缺少 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]
和以前一样,"m" 是缺少 ID 的行号向量。
向量 "b1" 和 "b2" 包含 "m" 中的那些行号,其中一块连续缺失的 ID
分别是开始和结束,即这些块的下限和上限。
所以 "m" 是区间 "b1[i]:b2[i]" 的并集,其中 "i" 从 1 到 "b1" 和 "b2" 的长度。
"k1" 和 "k2" 也包含这些边界,但它们的长度与 "m" 和 "m[j]" 包含在
每个索引 "j" 的块 "k1[j]:k2[j]"。
"m[j]" 行中的 ID 设置为 "k1[j]-1" 行或 "k2[j]+1" 行中的 ID 之一。
"m[j]" 行中的时间与 k2[j]+1" 行中的时间的比较,
产生向量 "n1" 和 "n2",决定选择哪一个。
我正在使用 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] }
}
但是,由于我的文件很大(约 650 万行),执行循环需要花费很多时间。是否有更多 'R-style'(例如使用 apply 或 sapply)解决方案可以更有效地做到这一点?
谢谢。
我建议如下:
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" 中那些行号的向量,其中时间不早于下一行中的时间。
如果 连续 行中缺少 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]
和以前一样,"m" 是缺少 ID 的行号向量。 向量 "b1" 和 "b2" 包含 "m" 中的那些行号,其中一块连续缺失的 ID 分别是开始和结束,即这些块的下限和上限。 所以 "m" 是区间 "b1[i]:b2[i]" 的并集,其中 "i" 从 1 到 "b1" 和 "b2" 的长度。 "k1" 和 "k2" 也包含这些边界,但它们的长度与 "m" 和 "m[j]" 包含在 每个索引 "j" 的块 "k1[j]:k2[j]"。 "m[j]" 行中的 ID 设置为 "k1[j]-1" 行或 "k2[j]+1" 行中的 ID 之一。 "m[j]" 行中的时间与 k2[j]+1" 行中的时间的比较, 产生向量 "n1" 和 "n2",决定选择哪一个。