Применить функцию к каждой комбинации столбцов - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть фрейм данных со столбцами n, и я хочу применить функцию к каждой комбинации столбцов.Это очень похоже на то, как функция cor() принимает кадр данных в качестве входных данных и создает матрицу корреляции в качестве выходных данных, например:

X <- data.frame(A=rnorm(100), B=rnorm(100), C=rnorm(100))
cor(X)

, которая будет генерировать эти выходные данные:

> cor(X)
            A           B          C
A  1.00000000 -0.01199511 0.02337429
B -0.01199511  1.00000000 0.07918920
C  0.02337429  0.07918920 1.00000000

Однако у меня есть пользовательская функция, которую нужно применить к каждой комбинации столбцов.Сейчас я использую решение, которое использует вложенные для циклов, которое работает:

f <- function(x, y) sum((x+y)^2) # some placeholder function

out <- matrix(NA, ncol = ncol(X), nrow = ncol(X)) # pre-allocate
for(i in seq_along(X)) {
  for(j in seq_along(X)) {
    out[i, j] <- f(X[, i], X[, j]) # apply f() to each combination
  }
}

, которое производит:

> out
         [,1]     [,2]     [,3]
[1,] 422.4447 207.0833 211.4198
[2,] 207.0833 409.1242 218.2430
[3,] 211.4198 218.2430 397.5321

В настоящее время я пытаюсь перейти в Tidyverse и будетпредпочитают избегать использования для петель. Может ли кто-нибудь показать мне аккуратное решение для этой ситуации? Спасибо!

Ответы [ 3 ]

0 голосов
/ 25 сентября 2018

Это не tidyverse решение, но оно избегает использования для циклов.Мы используем RcppAlgos (я автор) для генерации всех парных перестановок столбцов и применяем вашу пользовательскую функцию к каждому из них.После этого мы приводим к матрице.

set.seed(42)
X <- data.frame(A=rnorm(100), B=rnorm(100), C=rnorm(100))
library(RcppAlgos)

matrix(permuteGeneral(ncol(X), 2, repetition = TRUE, FUN = function(y) {
    sum((X[,y[1]] + X[,y[2]])^2)
}), ncol = ncol(X))
#          [,1]     [,2]     [,3]
# [1,] 429.8549 194.4271 179.4449
# [2,] 194.4271 326.8032 197.2585
# [3,] 179.4449 197.2585 409.6313
0 голосов
/ 25 сентября 2018

Используя базу R, вы можете сделать:

set.seed(42)
X <- data.frame(A=rnorm(100), B=rnorm(100), C=rnorm(100))

OUT = diag(colSums((X+X)^2))
OUT[lower.tri(OUT)] = combn(X, 2, function(x) sum(do.call('+', x)^2)) #combn(X,2,function(x)sum(rowSums(x)^2))
OUT[upper.tri(OUT)] = OUT[lower.tri(OUT)]
OUT
         [,1]     [,2]     [,3]
[1,] 429.8549 194.4271 179.4449
[2,] 194.4271 326.8032 197.2585
[3,] 179.4449 197.2585 409.6313
0 голосов
/ 25 сентября 2018

Вы могли бы сделать

library(tidyverse)
f <- function(x, y) sum((x+y)^2)
X <- data.frame(A=rnorm(100), B=rnorm(100), C=rnorm(100))

as.list(X) %>%
  expand.grid(., .) %>%
  mutate(out = map2_dbl(Var1, Var2, f)) %>%
  as_tibble()
...