使用Sparklyr用LOCF替换NA

时间:2019-07-03 12:10:52

标签: r apache-spark sparklyr

我的目标是使用最后一次观察结转方法替换火花数据框中的NA。我编写了以下代码,并且 works 。但是,对于较大的数据集,它似乎比预期花费了更长的时间。

如果有人可以推荐更好的方法或改进代码,那将是很好的。

Sparklyr的示例和代码

在下面的示例中,使用NA time并按grp分组。

df_with_nas <- data.frame(time = seq(as.Date('2001/01/01'), 
                                as.Date('2010/01/01'), length.out = 10),
                          grp = c(rep(1, 5), rep(2, 5)),
                          v1 = c(1, rep(NA, 3), 5, rep(NA, 5)),
                          v2 = c(NA, NA, 3, rep(NA, 4), 3, NA, NA))

tbl <- copy_to(sc, df_with_nas, overwrite = TRUE)

tbl %>%
  spark_apply(function(df) {
    library(dplyr)
    na_locf <- function(x) {
      v <- !is.na(x)
      c(NA, x[v])[cumsum(v) + 1]
    }
    df %>% arrange(time) %>% group_by(grp) %>% mutate_at(vars(-v1, -grp), 
    funs(na_locf(.)))
  })

# # Source: spark<?> [?? x 4]
#      time   grp    v1    v2
#     <dbl> <dbl> <dbl> <dbl>
#  1 11323      1     1   NaN
#  2 11688.     1   NaN   NaN
#  3 12053.     1   NaN     3
#  4 12419.     1   NaN     3
#  5 12784.     1     5     3
#  6 13149.     2   NaN   NaN
#  7 13514.     2   NaN   NaN
#  8 13880.     2   NaN     3
#  9 14245.     2   NaN     3
# 10 14610      2   NaN     3

data.table

目前,对于数据,我使用data.table的以下方法非常快。我预计数据大小很快就会增加,然后我可能不得不依靠sparklyr

library(data.table)
setDT(df_with_nas)
df_with_nas <- df_with_nas[order(time)]
cols <- c("v1", "v2")

df_with_nas[, (cols) := zoo::na.locf(.SD, na.rm = FALSE), 
                                 by = grp, .SDcols = cols]

3 个答案:

答案 0 :(得分:1)

我做了这样的循环,很慢...

df_with_nas = df_with_nas%>%变异(行= 1:nrow(df_with_nas))

for(n in 1:50){
  df_with_nas = df_with_nas %>% 
    arrange(row) %>% 
    mutate_all(~if_else(is.na(.),lag(.,1),.))
}

运行直到没有NA

然后

collect(df_with_nas)

将运行代码。

答案 1 :(得分:1)

您可以利用spark_apply()函数并在每个群集节点中运行na.locf函数。

  1. 在每个群集节点上安装R运行时。
  2. 还要在每个节点上安装zoo R软件包。
  3. 运行spark的方法如下:
data_filled <- spark_apply(data_with_holes, function(df) zoo:na.locf(df))

答案 2 :(得分:0)

您可以使用sql快速完成此操作,并具有可以轻松按组应用LOCF的附加好处。您要使用的模式是LAST_VALUE(column, true) OVER (window)-在窗口上搜索不是NA的最新列值(将“ true”传递给LAST_VALUEignore NA = true)。由于您想从当前值向后看,所以窗口应该是

ORDER BY time
ROWS BETWEEN UNBOUNDED PRECEDING AND -1 FOLLOWING

当然,如果组中的第一个值为NA,它将保持NA。

library(sparklyr)
library(dplyr)

sc <- spark_connect(master = "local")

test_table <- data.frame(
  v1 =   c(1, 2, NA, 3, NA, 5, NA, 6, NA),
  v2 =   c(1, 1,  1, 1,  1, 2,  2, 2,  2),
  time = c(1, 2,  3, 4,  5, 2,  1, 3,  4)
) %>%
  sdf_copy_to(sc, ., "test_table")

spark_session(sc) %>%
  sparklyr::invoke("sql", "SELECT *, LAST_VALUE(v1, true)
                   OVER (PARTITION BY v2
                         ORDER BY time
                         ROWS BETWEEN UNBOUNDED PRECEDING AND -1 FOLLOWING) 
                   AS last_non_na
                   FROM test_table") %>%
  sdf_register() %>%
  mutate(v1 = ifelse(is.na(v1), last_non_na, v1))
#> # Source: spark<?> [?? x 4]
#>      v1    v2  time last_non_na
#>   <dbl> <dbl> <dbl>       <dbl>
#> 1     1     1     1         NaN
#> 2     2     1     2           1
#> 3     2     1     3           2
#> 4     3     1     4           2
#> 5     3     1     5           3
#> 6   NaN     2     1         NaN
#> 7     5     2     2         NaN
#> 8     6     2     3           5
#> 9     6     2     4           6

reprex package(v0.3.0)于2019-08-27创建