R: перечисление возможных последовательностей для разрыва связей в рейтинге
MEMORY1 MEMORY2 MEMORY3 MEMORY4 MEMORY5 MEMORY6 MEMORY7 MEMORY8
1 2.5 2.5 4 5 6 7 8
Предположим, что у меня есть вышеприведенный рейтинг из 8 пунктов. Есть 2 способа разорвать эту связь: 1 2 3 4 5 6 7 8
или 1 3 2 4 5 6 7 8
. Я пытаюсь написать функцию, которая выводит эти две возможные последовательности при заданном исходном ранжировании со связями в нем.
В случае
MEMORY1 MEMORY2 MEMORY3 MEMORY4 MEMORY5 MEMORY6 MEMORY7 MEMORY8
4.5 4.5 4.5 4.5 4.5 4.5 4.5 4.5
Все элементы связаны, поэтому есть 8!
возможные последовательности. permn(8)
или что-то подобное перечисляло бы последовательности просто отлично.
В случае
MEMORY1 MEMORY2 MEMORY3 MEMORY4 MEMORY5 MEMORY6 MEMORY7 MEMORY8
7.5 5 5 2 7.5 2 2 5
Существуют 3! x 3! x 2! = 72
возможные последовательности. Как я могу написать функцию, которая выводит эти 72 возможных последовательности с учетом исходного ранжирования?
myfun = function(ranking){
output = vector()
values = sort(unique(ranking))
if(length(values) < 8){
#if there are ties
for(i in 1:length(values)){
value_in_question = values[i]
if(sum(value_in_question %in% values[i] == 1)){
output = output
}else output[i] = permn(values[i])
}
}
return(output)
}
Это моя попытка, она не работает. И мне трудно придумать способ перечисления последовательностей, когда есть несколько связей...
Редактировать:
dat = c(2.5, 2.5, 2.5, 2.5, 6.5, 6.5, 6.5, 6.5)
names(dat) <- paste0("MEMORY", 1:8)
## Group similar items, compute run lengths, then permute
library(combinat) # permn
gs <- cumsum(abs(c(0, diff(sort(dat)))) > 1e-9)
lens <- rle(gs)$lengths
lst <- mapply(function(a,b) lapply(permn(1:b), `+`, a), c(0, cumsum(head(lens, -1))), lens)
## Expand into data.frame (don't expand if all were the same)
res <- if(!is.null(dim(lst)) && dim(lst)[2] == 1) lst else expand.grid(lst)
Error: cannot allocate vector of size 16.0 Gb
In addition: Warning messages:
1: In rep.int(seq_len(nx), rep.int(rep.fac, nx)) :
Reached total allocation of 8070Mb: see help(memory.size)
2: In rep.int(seq_len(nx), rep.int(rep.fac, nx)) :
Reached total allocation of 8070Mb: see help(memory.size)
3: In rep.int(seq_len(nx), rep.int(rep.fac, nx)) :
Reached total allocation of 8070Mb: see help(memory.size)
4: In rep.int(seq_len(nx), rep.int(rep.fac, nx)) :
Reached total allocation of 8070Mb: see help(memory.size)
5: In rep.int(seq_len(nx), rep.int(rep.fac, nx)) :
Reached total allocation of 8070Mb: see help(memory.size)
6: In rep.int(seq_len(nx), rep.int(rep.fac, nx)) :
Reached total allocation of 8070Mb: see help(memory.size)
1 ответ:
Поскольку вы сравниваете поплавки, вы не хотите использовать тесты
==
. Вместо этого убедитесь, что разница между числами достаточно мала. Вот возможное решение, которое не претендует на эффективность.## Example dat <- c(7.5, 5, 5, 2, 7.5, 2, 2, 5) names(dat) <- paste0("MEMORY", 1:8) ## Group similar items, compute run lengths, then permute library(combinat) # permn gs <- cumsum(abs(c(0, diff(sort(dat)))) > 1e-9) lens <- rle(gs)$lengths lst <- mapply(function(a,b) lapply(permn(1:b), `+`, a), c(0, cumsum(head(lens, -1))), lens, SIMPLIFY = FALSE) ## Expand into data.frame (don't expand if all were the same) res <- if(!is.null(dim(lst)) && dim(lst)[2] == 1) lst else expand.grid(lst) ## Unnest columns if desired res <- data.frame(t(apply(res, 1, unlist))) ## Name the columns names(res) <- names(sort(dat)) head(res) # MEMORY4 MEMORY6 MEMORY7 MEMORY2 MEMORY3 MEMORY8 MEMORY1 MEMORY5 # 1 1 2 3 4 5 6 7 8 # 2 1 3 2 4 5 6 7 8 # 3 3 1 2 4 5 6 7 8 # 4 3 2 1 4 5 6 7 8 # 5 2 3 1 4 5 6 7 8 # 6 2 1 3 4 5 6 7 8 ## Gets all 72 sequences from example: 3!*3!*2! nrow(res) # [1] 72
Результатом должны быть данные.фрейм, где каждая строка является одной из возможных последовательностей (последовательности являются индексами отсортированных данных).