我的目标是使用最后一次观察结转方法替换火花数据框中的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]
答案 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
函数。
zoo
R软件包。 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_VALUE
集ignore 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创建