【问题标题】:How to solve a problem with vectorisation in R? [duplicate]如何解决 R 中的矢量化问题? [复制]
【发布时间】:2020-04-13 00:59:13
【问题描述】:

R 新手(ish)。我在 R 中编写了一些使用 for() 循环的代码。我想以矢量化形式重写它,但它不起作用。

简单的例子来说明:

library(dplyr)

x <- data.frame(name = c("John", "John", "John", "John", "John", "John", "John", "John", "Fred", "Fred"),
                year = c(1, NA, 2, 3, NA, NA, 4, NA, 1, NA))

## if year is blank and name is same as name from previous row
##    take year from previous row
## else
##    stick with the year you already have

# 1. Run as a loop

x$year_2 <- NA
x$year_2[1] <- x$year[1]                

for(row_idx in 2:10)
{
  if(is.na(x$year[row_idx]) & (x$name[row_idx] == x$name[row_idx - 1]))
  {
    x$year_2[row_idx] = x$year_2[row_idx - 1]
  }
  else
  {
    x$year_2[row_idx] = x$year[row_idx]
  }
}  

# 2. Attempt to vectorise

x <- data.frame(name = c("John", "John", "John", "John", "John", "John", "John", "John", "Fred", "Fred"),
                year = c(1, NA, 2, 3, NA, NA, 4, NA, 1, NA))

x$year_2 <- ifelse(is.na(x$year) & x$name == lead(x$name),
                   lead(x$year_2),
                   x$year)

我认为矢量化版本被搞砸了,因为它存在循环性(即 x$year_2 出现在 &lt;- 的两侧)。有没有办法解决这个问题?

谢谢。

【问题讨论】:

    标签: r vectorization


    【解决方案1】:

    我建议你使用已经建立的函数,R一开始感觉很难,因为我们受过重新发明轮子的训练,不要这样做。

    library(tidyverse)
    
    x <- data.frame(name = c("John", "John", "John", "John", "John", "John", "John", "John", "Fred", "Fred"),
                    year = c(1, NA, 2, 3, NA, NA, 4, NA, 1, NA))
    
    
    x %>% 
      group_by(name) %>% 
      tidyr::fill(year)
    

    【讨论】:

    • 天哪……好多了!顺序被改变了 - 大概我可以使用 %>% 安排()来解决这个问题(不一定会影响我的代码逻辑,但会让事情更容易在屏幕上查看)?
    • 是的,它只会改变显示的内容,如果它看起来更适合你,那就去吧
    【解决方案2】:

    如果您使用的是dplyr/tidyverse:

    library(dplyr)
    library(tidyr)
    x %>% 
      group_by(name) %>% 
      fill("year")
    
       name   year
       <fct> <dbl>
     1 John      1
     2 John      1
     3 John      2
     4 John      3
     5 John      3
     6 John      3
     7 John      4
     8 John      4
     9 Fred      1
    10 Fred      1
    

    【讨论】:

    • 非常感谢 - 容易多了。与 Bruno 刚才提出的解决方案相同。
    【解决方案3】:

    如果您知道数据框始终处于这种排序类型,那么通过使用最新的非缺失值填充 NAs,以下应该对您有用。

    library(zoo)
    x <- data.frame(name = c("John", "John", "John", "John", "John", "John", "John", "John", "Fred", "Fred"),
                    year = c(1, NA, 2, 3, NA, NA, 4, NA, 1, NA))
    x$year_2 <- na.locf(x$year)
    x
    

    如果您不想加载 zoo 包,这也可以:

    repeat_last = function(x, forward = TRUE, maxgap = Inf, na.rm = FALSE) {
      if (!forward) x = rev(x)           # reverse x twice if carrying backward
      ind = which(!is.na(x))             # get positions of nonmissing values
      if (is.na(x[1]) && !na.rm)         # if it begins with NA
        ind = c(1,ind)                 # add first pos
      rep_times = diff(                  # diffing the indices + length yields how often
        c(ind, length(x) + 1) )          # they need to be repeated
      if (maxgap < Inf) {
        exceed = rep_times - 1 > maxgap  # exceeding maxgap
        if (any(exceed)) {               # any exceed?
          ind = sort(c(ind[exceed] + 1, ind))      # add NA in gaps
          rep_times = diff(c(ind, length(x) + 1) ) # diff again
        }
      }
      x = rep(x[ind], times = rep_times) # repeat the values at these indices
      if (!forward) x = rev(x)           # second reversion
      x
    }
    
    x$year_3 <- repeat_last(x$year)
    x
    

    【讨论】:

      【解决方案4】:

      可以通过下面的代码在基本 R 中实现这一点的简单方法

      x <- within(x, year <- subset(year,!is.na(year))[cumsum(!is.na(year))])
      

      或

      x$year <- with(x, subset(year,!is.na(year))[cumsum(!is.na(year))])
      

      这样

      > x
         name year
      1  John    1
      2  John    1
      3  John    2
      4  John    3
      5  John    3
      6  John    3
      7  John    4
      8  John    4
      9  Fred    1
      10 Fred    1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-13
        • 1970-01-01
        • 2021-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多