【问题标题】:R vectorization implementation in a function函数中的 R 向量化实现
【发布时间】:2018-03-13 12:52:09
【问题描述】:

我很难理解如何利用 R 矢量化以更有效的方式做我想做的事。

简而言之,对于每一行,我想将当前行的第二列($start)与上一行和下一行的 $start 进行比较(所有值都是整数,我们将这些值称为 prev_dist 和 next_dist)。接下来,打印当前行的第 4 列($condition),后跟 5 个前一个 $condition 或 5 个下一个 $condition,这取决于哪个较低的距离值(即上一行或下一行的 $start 最接近当前行的 $start)。

weather    146   17   Rainy 
weather    147   17   Rainy 
weather    163   16   Sunny 
weather    173   15   Sunny 
weather    176   15   Rainy   
weather    197   12   Rainy    

我希望我的输出类似于(在数据框中):

Rainy Rainy Sunny Sunny Sunny Rainy
Rainy Sunny Sunny Sunny Rainy Rainy
etc.

我尝试在下面编写一个函数,但这个函数对于大型模拟数据集永远运行。

有人可以帮助我了解在这种情况下如何实现矢量化吗?

buildMatrix <- function(input){
 len <- nrow(input)-6
 sequence_matrix <- data.frame()

 for(line in 6:len){

   start <- input[line,]$start
   prev_start <- input[line-1,]$start
   next_start <- input[line+1,]$start
   prev_dist <- abs(start-prev_start)
   next_dist <- abs(start-next_start)
   current_seq <- input[line,]$condition

   if(prev_dist < next_dist || prev_dist == next_dist){
     for(i in 1:5){
       prev_seq <- input[line-i,]$condition
       current_seq <- c(current_seq, prev_seq)}
   } else if(prev_dist > next_dist){
     for(i in 1:5){
       next_seq <- input[line+i,]$condition
       current_seq <- c(current_seq, next_seq)}
   }
   sequence_matrix <- rbind(sequence_matrix, current_seq)
  }
 colnames(sequence_matrix) <- c("p0", "p1", "p2", "p3", "p4", "p5")
 sequence_matrix
}

修改代码:

library(dplyr)
islessthan <- abs(df$V2-lead(df$V2)) < abs(df$V2-lag(df$V2))

ans <- lapply(seq_along(islessthan), function(i) if (is.na(islessthan[i])) {
   NA
} else if(islessthan[i]==FALSE) {
c(df$V4[i], head(lag(df$V4, pmax(6-i, 0)), 5))
} else {
c(df$V4[i], head(lead(df$V4, i), 5))
})

【问题讨论】:

  • 而不是$V2 等——为什么不给列提供信息性名称呢?之后,您可以为prev_startnext_start 创建新列(根据情况在最后一行或最后一行填充NA)。这可以在 1 行无循环语句中完成。一旦你到了那个阶段,问题就会容易得多。
  • 关于命名的观点。您的意思是像上面的列修改代码(我编辑了我的问题)吗?
  • 我想到的是 df$prev_start &lt;- c(NA,head(df$start,-1))df$next_start &lt;- c(tail(df$start,-1),NA),尽管基于 dplyr 的解决方案可能更可取。

标签: r performance function vectorization large-data


【解决方案1】:

使用dplyr::lead/lagfunctions 来发挥你的优势

您的数据

df <- read.table(text="weather    146   17   Rainy 
weather    147   17   Rainy 
weather    163   16   Sunny 
weather    173   15   Sunny 
weather    176   15   Rainy   
weather    197   12   Rainy", header=FALSE, stringsAsFactors=F)

判断每一行(0-row)是否有+1-row &lt; -1-row

library(dplyr)
islessthan <- lead(df$V2) < lag(df$V2)
# [1]    NA FALSE FALSE FALSE FALSE    NA

使用lapply 遍历上面创建的逻辑向量和您的数据框。 is.na(row) == TRUE 将返回 NA 的行; islessthan == FALSE 将返回 0-row + +5-rows of column V4 的行;以及islessthan == TRUE 将返回-5-rows of column V4 + 0-row 的行

ans <- lapply(seq_along(islessthan), function(i) if (is.na(islessthan[i])) {
                                    NA
                                } else if(islessthan[i]==FALSE) { 
                                    c(df$V4[i], head(lead(df$V4, i), 6))
                                } else { 
                                    c(head(lag(df$V4, 6-i), 6))
                                })

输出

# [[1]]
# [1] NA

# [[2]]
# [1] "Rainy" "Sunny" "Sunny" "Rainy" "Rainy" NA      NA     

# [[3]]
# [1] "Sunny" "Sunny" "Rainy" "Rainy" NA      NA      NA     

# [[4]]
# [1] "Sunny" "Rainy" "Rainy" NA      NA      NA      NA     

# [[5]]
# [1] "Rainy" "Rainy" NA      NA      NA      NA      NA     

# [[6]]
# [1] NA

请注意,您尚未指定如何处理边缘情况(第 1 行和第 N 行),并且您的示例没有足够的观察结果来返回完整向量,因此存在NAs在输出中作为填充符。

【讨论】:

  • 感谢您的回答!我想知道一件事,dplyr 的该功能是否仍然保留行的顺序还是与顺序无关?
  • 简短的回答是它会保留订单。 dplyr::lead 将把数据中的值提高N,这样索引 N 将变为索引 1。dplyr::lag 将做相反的事情。
  • 我根据我的需要修改了我的代码($V2s 的差异比较,而不仅仅是 $V2 比较):islessthan &lt;- abs(df$V2-lead(df$V2)) &lt; abs(df$V2-lag(df$V2)) ans &lt;- lapply(seq_along(islessthan), function(i) if (is.na(islessthan[i]) || any(is.na(islessthan[i:i-6])) || any(is.na(islessthan[i:i+6]))) { NA } else if(islessthan[i]==FALSE) { c(df$V4[i], head(lead(df$V4, i), 6)) } else { c(head(lag(df$V4, 6-i), 6)) }) 我更改第一个 if 语句的原因是这个错误:错误在 lag(df$V4, 6 - i) 中:n 必须是单个正整数。
  • 但是,上面的错误仍然存​​在。你能指出我在哪里修复代码吗?
  • 是的,pmax不是必须的,我想你可以使用max
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
相关资源
最近更新 更多