我有以下代码,它读取表的列,如果元素包含正确的字符串,它会增加另一个向量中的相应值。这是代码:
dateArray <- integer(365)
for (i in 189500:207097) {
if (grepl("Jan", csvaryana[i, "Date"], ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE)) {
for (j in 1:31) {
if (j < 10) {
if (grepl(paste(sprintf(" 0%d", j), ""), csvaryana[i, "Date"], ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE))
dateArray[j] <- dateArray[j] + 1
}
if (grepl(paste(sprintf(" %d", j), ""), csvaryana[i, "Date"], ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE))
dateArray[j] <- dateArray[j] + 1
}
}
}
dateArray
请注意,csvaryana是一个包含207,097行的表。该代码应该检查所有行,但我将其减少到只有大约10,000行。运行它需要几分钟,完整代码需要更长的时间。我怎样才能更快地完成同样的事情呢?我听说for循环效率不高。
答案 0 :(得分:1)
for
循环非常慢
如果你想加快你的循环,你可以阅读这篇文章:
Strategies to Speed-up R Code
根据文章,您可以执行以下步骤:
ifesle
代替if
答案 1 :(得分:1)
如果没有一个运行示例,您可以通过将循环的每个元素转换为函数来开始。我们将这些行编号如下:
#1 for (i in 189500:207097) {
#2 if (grepl("Jan", csvaryana[i, "Date"], ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE)) {
#3 for (j in 1:31) {
#4 if (j < 10) {
#5 if (grepl(paste(sprintf(" 0%d", j), ""), csvaryana[i, "Date"], ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE))
#6 dateArray[j] <- dateArray[j] + 1
#7 }
#8 if (grepl(paste(sprintf(" %d", j), ""), csvaryana[i, "Date"], ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE))
#9 dateArray[j] <- dateArray[j] + 1
#10 }
#11 }
#12 }
然后你可以将你的grepl作为一个函数包装起来(这可能比节省时间更美观):
## The grepl function (lines 2, 5 and 8)
grepl.ifelse <- function(i, pattern, data) {
grepl(pattern, data[i, "Date"], ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE)
}
对于循环的其他部分,我们可以使用sapply
函数将向量的值传递给函数。由于我们只需更新dateArray
,因此我们可以使用<<-
赋值,将值从函数环境中分配出来(有关详细信息,请参阅?"<<-"
):
## Update dateArray function (lines 4 to 10)
update.dateArray <- function(j, i, dateArray, csvaryana) {
if (j < 10) {
if (grepl.ifelse(paste(sprintf(" 0%d", j), ""), i, csvaryana)) {
dateArray[j] <<- dateArray[j] + 1
}
} else {
if (grepl.ifelse(paste(sprintf(" %d", j), ""), i, csvaryana)){
dateArray[j] <<- dateArray[j] + 1
}
}
}
此函数将在函数外更新dateArray
(无需返回)。我们可以将相同的原则应用于更大的循环(i
):
## Checking the month of January (lines 2 to 11)
check.jan <- function(i, dateArray, csvaryana) {
if(grepl.ifelse("Jan", i, csvaryana)) {
## Update dateArray out of the function
dateArray <<- sapply(1:31, update.dateArray, i, dateArray, csvaryana)
}
return(dateArray)
}
同样,如果没有正在运行的示例,很难进行测试,因此这篇文章可能需要进行一些编辑,但这可能是这样的:
dateArray <- integer(365)
## Running the whole loop
sapply(189500:207097, check.jan, dateArray, csvaryana)
## Updated dateArray
dateArray
答案 2 :(得分:0)
我没有循环就解决了。我将Date列分为Year,Month和Day以及Time,所以我只调用count(Month和Day)并返回一个每月和每天频率的向量:
dateVector <- count(outfile, "X2")
答案 3 :(得分:-1)
请勿使用apply
循环。有一个非常好的SO帖子讨论这个:
Why are loops slow in R?
答案是对数据框进行矢量化以加快处理速度(通过purrr
系列或结帐sprintf(" 0%d", j)
。清理数据和代码,以便在循环期间不计算grepl
并考虑arr
的替代品,因为在这种情况下似乎有点过分。
讨论其中一些概念的好博文: https://robinsones.github.io/Making-R-Code-Faster-A-Case-Study/