Найти все комбинации между двумя векторами разной длины - PullRequest
2 голосов
/ 29 июня 2019

Предположим, у меня есть два вектора разной длины x_1 и y_1 следующим образом:

x_1 = seq(0,49,2)
y_1 = seq(-90,-51,2)

Теперь я хочу найти все возможные комбинации этих двух векторов с размером = 5и поэтому я делаю:

library(tidyr)
x_all = data.frame(t(rbind(combn(x_1, 5))))
y_all = data.frame(t(rbind(combn(y_1, 5))))

Теперь я хочу сохранить только комбинации со значениями, прогрессирующими с шагом 2:

x_all = x_all[x_all$X2 - x_all$X1 == 2 &
                x_all$X3 - x_all$X2 == 2 &
                x_all$X4 - x_all$X3 == 2 &
                x_all$X5 - x_all$X4 == 2, ]

y_all = y_all[y_all$X2 - y_all$X1 == 2 &
                y_all$X3 - y_all$X2 == 2 &
                y_all$X4 - y_all$X3 == 2 &
                y_all$X5 - y_all$X4 == 2, ]

А теперь мой вопрос:

Как я могу объединить x_all и y_all, чтобы получить уникальный data.frame со всеми возможными комбинациями между этими двумя наборами?

Любые предложения?

Вот что я пыталсябез успеха:

# Assign an index to each set
x_all$index = c(1:nrow(x_all))
y_all$index = c(1:nrow(y_all))

# Merge the sets
x_y_all = merge(x_all, y_all, by = 'index', all = TRUE)

Вывод должен выглядеть примерно так:

X1.x X2.x X3.x X4.x X5.x X1.y X2.y X3.y X4.y X5.y 
 0    2    4    6    8   -90  -88  -86  -84  -82
 0    2    4    6    8   -88  -86  -84  -82  -80
 0    2    4    6    8   -86  -84  -82  -80  -78
....
 2    4    6    8   10   -90  -88  -86  -84  -82
 2    4    6    8   10   -88  -86  -84  -82  -80
 2    4    6    8   10   -86  -84  -82  -80  -78
....

Ответы [ 4 ]

2 голосов
/ 01 июля 2019

Еще один возможный базовый подход R с использованием индексации для создания комбинаций x_all и y_all (без создания множества комбинаций в combn и последующего поднабора), а затем перекрестного объединения ваших комбинаций:

x_1 = seq(0,49,2)
y_1 = seq(-90,-51,2)

#creating combinations
x_all <- do.call(rbind, lapply(head(seq_along(x_1), -4L), function(n) x_1[n + 0L:4L]))
y_all <- do.call(rbind, lapply(head(seq_along(y_1), -4L), function(n) y_1[n + 0L:4L]))
#or also 
#x_nc <- length(x_1)-4L
#x_all <- matrix(x_1[t(embed(seq_along(x_1), x_nc)[, x_nc:1L])], ncol=5L)

#cross join
cbind(
    x_all[rep(seq_len(nrow(x_all)), each=nrow(y_all)),],
    y_all[rep(seq_len(nrow(y_all)), times=nrow(x_all)),]
)
2 голосов
/ 29 июня 2019

Небольшое изменение в вашем предложении решает проблему:

#Assign same, constant index so the merge function will fill
x_all$index <- 1
y_all$index <- 1

#Merge to get all information
x_y_all <- merge(x_all, y_all, by = "index")

#Delete the index
x_y_all$index <- NULL
2 голосов
/ 29 июня 2019

Вот более простой способ (также проще по памяти, чем ваш combn подход) получить желаемый результат -

library(dplyr)

x_1 = seq(0, 49, 2)
y_1 = seq(-90, -51, 2)

x_all <- sapply(x_1, function(x) {
  seq(x, by = 2, length.out = 5)
}) %>% 
  t() %>% 
  as_tibble() %>% 
  mutate(cj = 1)

y_all <- sapply(y_1, function(x) {
  seq(x, by = 2, length.out = 5)
}) %>% 
  t() %>% 
  as_tibble() %>% 
  mutate(cj = 1)

inner_join(x_all, y_all, by = "cj") %>% 
  select(-cj)

# A tibble: 500 x 10
    V1.x  V2.x  V3.x  V4.x  V5.x  V1.y  V2.y  V3.y  V4.y  V5.y
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1     0     2     4     6     8   -90   -88   -86   -84   -82
 2     0     2     4     6     8   -88   -86   -84   -82   -80
 3     0     2     4     6     8   -86   -84   -82   -80   -78
 4     0     2     4     6     8   -84   -82   -80   -78   -76
 5     0     2     4     6     8   -82   -80   -78   -76   -74
 6     0     2     4     6     8   -80   -78   -76   -74   -72
 7     0     2     4     6     8   -78   -76   -74   -72   -70
 8     0     2     4     6     8   -76   -74   -72   -70   -68
 9     0     2     4     6     8   -74   -72   -70   -68   -66
10     0     2     4     6     8   -72   -70   -68   -66   -64
# ... with 490 more rows
0 голосов
/ 29 июня 2019

Вот мое (не элегантное) решение:

# create empty list
    x_all_lst = list()

# put into list the `x_all` data.frame n times based on the number of y_all combinations (here 16)
    for (i in 1:nrow(y_all)) {
      x_all_lst[[i]] = x_all
    }

# merge list
    x_all = do.call(rbind, x_all_lst)

# order list by column
    x_all = x_all[with(x_all, order(X1)), ]

# bind x_all and y_all columns
    x_y_all = cbind(x_all, y_all)

# remove row.names
    row.names(x_y_all) = NULL
...