Фильтрация декартовых произведений с помощью purrr::cross_n

Я пробую некоторые purrr идиомы - особенно функции, которые циклически (или применяют, если хотите) функции через один data.frame и сравнивают со всеми другими строками в другом data.frame... и фильтруют декартово произведение на основе этого сравнения функция..

> df1    
        chr start   end
      (fctr) (int) (int)
    1   chr1  9069  9176
    2   chr1 10460 11368
    3   chr1 34633 35625
    4   chr1 36791 37023
> df2
     chr start2
  (fctr) (dbl)
1   chr1  9169
2   chr1 10360
3   chr1 34633

Итак, простой пример функции:

> is.between <- function(x1, y1, y2){
  ifelse(x1 >= y1 & x1 <= y2, TRUE, FALSE)
}

Результат, который я ищу (на данный момент), должен быть 2 на 4 data.frame df3 как

             # desired result
             chr start  end  start2
          (fctr) (int) (int)
        1   chr1  9069  9176  9169
        2   chr1  34633 35625 34633

Наивно тогда я попытался использовать функцию purrr::cross_n вот так...

> cross_n(list(df2$start2, df1$start, df1$start), .filter = is.between)

Конечно, это не работает, это поиск по декартовому произведению 3 входных столбцов (48 комбинаций). Я хочу найти комбинации df2$start2 против [df1$start и df1$end] (12 комбинаций).

И так... Есть ли способ сделать это в рамках purrr?

Не могу понять это с cross_n или cross2 и ошибаюсь.. Я не совсем понимаю документы по cross_d


person Stephen Henderson    schedule 22.02.2016    source источник
comment
Я не вижу в этом проблемы, которую решает purrr. Я бы порекомендовал посмотреть data.table::foverlaps()   -  person davechilders    schedule 22.02.2016
comment
@DMC, спасибо, это выглядит интересно, но is.between - это просто пример. Меня действительно интересует этот тип контроля декартовых комбинаций. Если существует элегантное решение, я мог бы использовать его во многих местах.   -  person Stephen Henderson    schedule 22.02.2016
comment
Есть ли разница между ifelse(x1 >= y1 & x1 <= y2, TRUE, FALSE) и ванильной x1 >= y1 & x1 <= y2?   -  person Frank    schedule 22.02.2016
comment
@ Фрэнк Нет. Я просто подумал, что это яркий пример.   -  person Stephen Henderson    schedule 22.02.2016


Ответы (1)


OK FWIW - я адаптировал некоторые функции purrr::cross_n, чтобы ответить на свой вопрос. Новая функция cross2d выглядит так:

# this makes sense only if the .l in the same groups are the same length
# ie they are probably from the same data.frame
cross2d<- function(.l, groups = NULL, .filter = NULL){
  if (is_empty(.l) | is.null(groups)) {
    return(.l)
  }
  if (!is.null(.filter)) {
    .filter <- as_function(.filter)
  }

  n <- length(.l)

  #separate df for each group
  df1<- data.frame(.l[groups==0])
  df2<- data.frame(.l[groups==1])


  exp.coords<-expand.grid(1:nrow(df1), 1:nrow(df2))
  df<- data.frame(df1[exp.coords$Var1,], df2[exp.coords$Var2,])
  names(df)<-c(colnames(df1),colnames(df2))

  df[do.call(.filter, unname(df)),]
}

С данными примера df1 и df2 и функцией is.between, показанной выше, вы используете ее следующим образом:

> cross2d(list(x1=df2$start, x2=df1$start, y2=df1$end), group=c(0,1,1), .filter=is.between)
       x1    x2    y2
1    9169  9069  9176
3.2 34633 34633 35625

Я закодировал это для 2 групп (на самом деле data.frames) и вывода data.frame ... но, возможно, можно обобщить дальше ...?

person Stephen Henderson    schedule 23.02.2016