Декартовы данные продукта в R

Я имею три или более независимых переменных, представленных как R-векторы, например:

A <- c(1,2,3) B <- factor(c('x','y')) C <- c(0.1,0.5) 

и я хочу взять декартово произведение всех из них и поместить результат в кадр данных, например:

 ABC 1 x 0.1 1 x 0.5 1 y 0.1 1 y 0.5 2 x 0.1 2 x 0.5 2 y 0.1 2 y 0.5 3 x 0.1 3 x 0.5 3 y 0.1 3 y 0.5 

Я могу сделать это, вручную выписав вызовы rep :

 d <- data.frame(A = rep(A, times=length(B)*length(C)), B = rep(B, times=length(A), each=length(C)), C = rep(C, each=length(A)*length(B)) 

но должен быть более элегантный способ сделать это, да? product в itertools делает часть работы, но я не могу найти способ поглотить вывод iteratorа и поместить его в кадр данных. Какие-либо предложения?

ps Следующий шаг в этом вычислении выглядит следующим образом:

 d$D <- f(d$A, d$B, d$C) 

поэтому, если вы знаете способ сделать оба действия сразу, это также будет полезно.

вы можете использовать expand.grid(A, B, C)

EDIT: альтернатива использованию do.call для достижения второй части – это функция mdply. вот код

 d = expand.grid(x = A, y = B, z = C) d = mdply(d, f) 

чтобы проиллюстрировать его использование, используя тривиальную функцию «вставить», вы можете попробовать

 d = mdply(d, 'paste', sep = '+'); 

Существует функция, манипулирующая файловой рамкой, что полезно в этом случае.

Он может создавать различные соединения (в терминологии SQL), в то время как декартово произведение является частным случаем.

Сначала вам нужно преобразовать переменные в кадры данных, поскольку в качестве параметров требуется фрейм данных.

поэтому что-то вроде этого будет делать:

 AB=merge(data.frame(A=A), data.frame(B=B),by=NULL); ABC=merge(AB, data.frame(C=C),by=NULL); 

Единственное, о чем нужно заботиться, это то, что строки не сортируются, как вы изображали. Вы можете отсортировать их вручную по своему усмотрению.

merge(x, y, by = intersect(names(x), names(y)), by.x = by, by.y = by, all = FALSE, all.x = all, all.y = all, sort = TRUE, suffixes = c(".x",".y"), incomparables = NULL, ...)

«Если by или оба by.x и by.y имеют длину 0 (вектор нулевой длины или NULL), результат, r, является декартовым произведением x и y”

см. этот url для деталей: http://stat.ethz.ch/R-manual/R-patched/library/base/html/merge.html

Вот как это сделать, используя предложение expand.grid о expand.grid :

 f <- function(x,y,z) paste(x,y,z,sep="+") d <- expand.grid(x=A, y=B, z=C) d$D <- do.call(f, d) 

Обратите внимание, что do.call работает с d "as-is", потому что data.frame - это list . Но do.call ожидает, что имена столбцов d соответствуют именам аргументов f .

Подумайте об использовании замечательной библиотеки data.table для выразительности и скорости. Он обрабатывает много вариантов использования plyr (реляционная группа), а также преобразование, подмножество и реляционное объединение с использованием довольно простого единообразного синтаксиса.

 library(data.table) d <- CJ(x=A, y=B, z=C) # Cross join d[, w:=f(x,y,z)] # Mutates the data.table 

или в одной строке

 d <- CJ(x=A, y=B, z=C)[, w:=f(x,y,z)] 

С библиотекой tidyr можно использовать tidyr::crossing (порядок будет таким же, как в OP):

 library(tidyr) crossing(A,B,C) # A tibble: 12 x 3 # ABC #    # 1 1 x 0.1 # 2 1 x 0.5 # 3 1 y 0.1 # 4 1 y 0.5 # 5 2 x 0.1 # 6 2 x 0.5 # 7 2 y 0.1 # 8 2 y 0.5 # 9 3 x 0.1 # 10 3 x 0.5 # 11 3 y 0.1 # 12 3 y 0.5 

Следующим шагом будет использование tidyverse и особенно семейства purrr::pmap* :

 library(tidyverse) crossing(A,B,C) %>% mutate(D = pmap_chr(.,paste,sep="_")) # A tibble: 12 x 4 # ABCD #     # 1 1 x 0.1 1_1_0.1 # 2 1 x 0.5 1_1_0.5 # 3 1 y 0.1 1_2_0.1 # 4 1 y 0.5 1_2_0.5 # 5 2 x 0.1 2_1_0.1 # 6 2 x 0.5 2_1_0.5 # 7 2 y 0.1 2_2_0.1 # 8 2 y 0.5 2_2_0.5 # 9 3 x 0.1 3_1_0.1 # 10 3 x 0.5 3_1_0.5 # 11 3 y 0.1 3_2_0.1 # 12 3 y 0.5 3_2_0.5 

Я никогда не помню эту стандартную функцию expand.grid . Итак, вот еще одна версия.

 crossproduct <- function(...,FUN='data.frame') { args <- list(...) n1 <- names(args) n2 <- sapply(match.call()[1+1:length(args)], as.character) nn <- if (is.null(n1)) n2 else ifelse(n1!='',n1,n2) dims <- sapply(args,length) dimtot <- prod(dims) reps <- rev(cumprod(c(1,rev(dims))))[-1] cols <- lapply(1:length(dims), function(j) args[[j]][1+((1:dimtot-1) %/% reps[j]) %% dims[j]]) names(cols) <- nn do.call(match.fun(FUN),cols) } A <- c(1,2,3) B <- factor(c('x','y')) C <- c(.1,.5) crossproduct(A,B,C) crossproduct(A,B,C, FUN=function(...) paste(...,sep='_')) 
Interesting Posts

Qt: Лучшая практика защиты одного экземпляра приложения

Как обновить / обновить определенный элемент в RecyclerView

Как настроить мультимодульный Maven + Sonar + JaCoCo для предоставления объединенного отчета о покрытии?

Подключение к рабочей машине

Как распечатать большую веб-страницу на одностраничном pdf с настраиваемыми параметрами?

jQuery Call to WebService возвращает ошибку «Нет транспорта»

Что такое встроенные методы в Java и где они должны использоваться?

Должен ли я помещать файл своей страницы в свой собственный раздел?

Почему эти горуты не масштабируют свою работу от более одновременных казней?

Случайно создал вирус?

Возможно ли создать ssh-агент для нового сеанса tmux?

Как получить контактный идентификатор электронной почты?

Android – Как создать интерактивный список?

Сохранение сеанса связанного приложения ASP.NET из другого приложения ASP.NET

Прозрачность PNG IE6

Давайте будем гением компьютера.