这个循环可以在R中加速吗?

时间:2018-04-12 16:19:42

标签: r loops optimization vectorization

我本周刚开始学习R,所以我很擅长。我已经编写了一个收到三个参数的函数,我想执行以下操作:

for (k in 1:nrow(df_t)){
  df_t$colv[k] = link_targets(data = df,
                              target_date = df_t$mtime[k],
                              tag = tag)
}

所以基本上我要做的是将函数应用于某个df_t列的每个元素,函数返回的值取决于同一数据帧的另一列。 (该函数返回一个标量值)。

我想知道这是否可以被矢量化以避免使用循环,这似乎真的会减慢代码。

如果您需要任何进一步的信息来帮助我,请告诉我。

编辑:

我在循环中调用的函数如下:

link_targets = function (data, target_date, tag){
  # Delete all rows that don't have the tag as name
  data[data$NAME != as.character(unlist(tag[1])),] = NA
  data = na.omit(data)
  # Delete all rows that do not correspond to the dates of the tag
  limit_time_1 = target_date - as.numeric(60 * tag[2] - 60)
  limit_time_2 = target_date - as.numeric(60 * tag[3])
  data[(data$IP_TREND_TIME < min(limit_time_1,limit_time_2))
       | (data$IP_TREND_TIME > max(limit_time_1,limit_time_2)),] = NA
  data = na.omit(data)
  mean_data = mean(as.numeric(data$IP_TREND_VALUE))
  return(mean_data)
}

我正在使用数据表。 df是这样的:

             NAME       IP_TREND_TIME IP_TREND_VALUE
       1: TC241-1 2018-03-06 12:05:31      194.57875
       2: TC241-1 2018-03-05 17:54:05       196.5219
       3: TC241-1 2018-03-05 05:02:18       211.4066
       4: TC241-1 2018-03-04 03:06:57      211.92874
       5: TC241-1 2018-03-03 06:41:17      205.43651
      ---                                           
13353582: DI204-4 2017-04-06 17:43:41     0.88308918
13353583: DI204-4 2017-04-06 17:43:31     0.88305187
13353584: DI204-4 2017-04-06 17:43:21     0.88303399
13353585: DI204-4 2017-04-06 17:43:11     0.88304734
13353586: DI204-4 2017-04-06 17:43:01     0.88305187

tag数组包含我想在NAME列中查找的单词,以及两个代表我想要的时间范围的数字。例如:

     tag  start end
1 TC204-1    75 190

我正在寻找的输出(df_t)将是这样的:

              TREND_TIME TREND_VALUE         colv 
  1: 2018-03-05 05:35:00   1.9300001     16.86248 
  2: 2018-03-05 02:21:00        1.95     18.04356 
  3: 2018-03-04 22:35:00        1.98     17.85405 
  4: 2018-03-04 17:01:00           2     17.87318 
  5: 2018-03-04 12:49:00        2.05     18.10455
 ---                                                      
940: 2017-04-07 15:01:00   2.1500001     20.14933 
941: 2017-04-07 09:27:00         1.9     20.19337    
942: 2017-04-07 04:46:00        1.95     20.20166    
943: 2017-04-07 01:34:00   2.0699999     20.20883    
944: 2017-04-06 21:46:00         1.9     20.15735 

其中colv包含与所选标记对应的列IP_TREND_VALUE中所有值的平均值,以及tag中数字所确定的时间范围内的平均值,基于时间TREND_TIME中的df_t

1 个答案:

答案 0 :(得分:1)

很难找到更好的解决方案,因为我很难理解你的逻辑和解释,也许你可以创造更好更小的例子,你想要完成什么会更清楚。

但是你应该能够用这个替换link_targets函数:

link_targets <- function(data, target_date, tag) {
  limit_time_1 = target_date - as.numeric(60 * tag[2] - 60)
  limit_time_2 = target_date - as.numeric(60 * tag[3])
  x <- c(limit_time_1, limit_time_2)
  i1 <- data$NAME == as.character(unlist(tag[1]))
  i2 <- (data$IP_TREND_TIME >= min(x)) & (data$IP_TREND_TIME <= max(x))
  mean_data <- mean(as.numeric(data$IP_TREND_VALUE[i1 & i2]))
  return(mean_data)
}

并且看到了极大的速度提升。

更新

也许此功能可以提高您特定数据的速度:

link_targets2 <- function(data, target_date, tag) {
  limit_time_1 <- target_date - as.numeric(60 * tag[[2]] - 60)
  limit_time_2 <- target_date - as.numeric(60 * tag[[3]])
  x <- c(limit_time_1, limit_time_2)
  i1 <- data$NAME == as.character(unlist(tag[1]))
  xx <- data$IP_TREND_TIME[i1]
  i2 <- (xx >= min(x)) & (xx <= max(x))
  mean_data <- mean(as.numeric(data$IP_TREND_VALUE[i1][i2]))
  return(mean_data)
}