将purrr :: map2()与dbplyr一起使用

时间:2018-03-26 18:04:29

标签: r tidyverse purrr dbplyr

我正在尝试从一个表(“positons”)中选择具有特定列(“位置”)的值的行,这些值落在另一个(“my_ranges”)表中定义的范围内,然后添加分组来自“my_ranges”表的标记。

我可以使用tibbles和几个purrr::map2调用来执行此操作,但相同的方法不适用于dbplyr database-tibbles。这是预期的行为,如果是这样的话,我应该采用不同的方法来使用dbplyr来完成这种任务吗?

这是我的例子:

library("tidyverse")
set.seed(42)

my_ranges <-
  tibble(
    group_id = c("a", "b", "c", "d"),
    start = c(1, 7, 2, 25),
    end = c(5, 23, 7, 29)
    )

positions <-
  tibble(
    position = as.integer(runif(n = 100, min = 0, max = 30)),
    annotation = stringi::stri_rand_strings(n = 100, length = 10)
  )

# note: this works as I expect and returns a tibble with 106 obs of 3 variables:
result <- map2(.x = my_ranges$start, .y = my_ranges$end,
             .f = function(x, y) {between(positions$position, x, y)}) %>%
  map2(.y = my_ranges$group_id,
              .f = function(x, y){
                positions %>%
                  filter(x) %>%
                  mutate(group_id = y)}
) %>% bind_rows()

# next, make an in-memory db for testing:
con <- DBI::dbConnect(RSQLite::SQLite(), path = ":memory:")

# copy data to db
copy_to(con, my_ranges, "my_ranges", temporary = FALSE)
copy_to(con, positions, "positions", temporary = FALSE)

# get db-backed tibbles:
my_ranges_db <- tbl(con, "my_ranges")
positions_db <- tbl(con, "positions")

# note: this does not work as I expect, and instead returns a tibble with 0 obsevations of 0 variables:
# database range-based query:
db_result <- map2(.x = my_ranges_db$start, .y = my_ranges_db$end,
                  .f = function(x, y) {
                    between(positions_db$position, x, y)
                    }) %>%
  map2(.y = my_ranges_db$group_id,
       .f = function(x, y){
         positions_db %>%
           filter(x) %>%
           mutate(group_id = y)}
  ) %>% bind_rows()

2 个答案:

答案 0 :(得分:1)

dbplyrR翻译为SQLSQL中不存在列表。 map创建列表。因此,无法将map转换为SQL

主要是dplyr个函数和一些base函数被翻译,他们正在研究tidyr函数,正如我所理解的那样。使用dbplyr尝试在您的方法中使用SQL逻辑时,或者它很容易破坏。

答案 1 :(得分:0)

只要每次迭代都创建一个尺寸相同的表,那么可能会有一种巧妙的方法将整个操作推送到数据库。这个想法是同时使用import ReactDOM from "react-dom"; import { mock } from "jest"; import { renderToDOM } from "./index"; describe("test ReactDOM.render", () => { const originalRender = ReactDOM.render; const originalGetElement = global.document.getElementById; beforeEach(() => { global.document.getElementById = () => true; ReactDOM.render = jest.fn(); }); afterAll(() => { global.document.getElementById = originalGetElement; ReactDOM.render = originalRender; }); it("should call ReactDOM.render", () => { renderToDOM(); expect(ReactDOM.render).toHaveBeenCalled(); }); }); 中的map()reduce()。每个purrr操作都是惰性的,因此我们可以遍历它们而不必担心发送一堆查询,然后我们可以使用tbl_sql(),它基本上将每次迭代使用的结果SQL附加到下一个给定数据库中的union()子句。这是一个示例:

UNION