Дисперсия функции комбн
Я использовал чудесную функцию combn из пакета утилит. Эта функция создает все возможные комбинации без повторения описания Combn. Я собираюсь представить одно использование функции, которую мне нужно сделать, но она не определена в функции combn. Я хотел бы представить это с хорошим примером. Тем не менее, реальная цель, которую мы хотим достичь, является более сложной, и она будет выполняться с большим количеством данных.
Мы хотим играть в игру, в которую могут играть только 3 человека. Однако нас 4 человека. Мы хотим знать все возможные группы для игры. Имена участников: Алекс, Дэвид, Джон и Зои. Возможные комбинации будут:
names <- c("Alex","David","John","Zoe")
people.per.group <- 3
combn(names,people.per.group)
#Output
[,1] [,2] [,3] [,4]
[1,] "Alex" "Alex" "Alex" "David"
[2,] "David" "David" "John" "John"
[3,] "John" "Zoe" "Zoe" "Zoe"
Однако у нас есть проблемы, потому что у Алекса нет хороших отношений с Джоном. Так что мы не хотим включать их обоих в группу. Так что мы можем создавать группы для людей, которых мы можем выбрать только один из них.
# Alex --> Group 1
# David --> Group 2
# John --> Group 1
# Zoe --> Group 3
only.one.per.group <- c(1,2,1,3)
Я ищу функцию, которая позволяет мне делать то же самое, что и combn, но ограничивает комбинации только переменной.one.per.group. Называя функцию, которую я с нетерпением жду, чтобы использовать var.combn, код будет:
names <- c("Alex","David","John","Zoe")
only.one.per.group <- c(1,2,1,3)
people.per.group <- 3
var.combn(names,people.per.group,only.one.per.group)
#Output
[,1] [,2]
[1,] "Alex" "David"
[2,] "David" "John"
[3,] "Zoe" "Zoe"
Я долго искал подобную функцию. Таким образом, было бы очень полезно, если бы вы могли сказать мне функцию для этого или любой другой способ, который приходит вам на ум.
Я надеюсь, что вам понравился пример, и я хотел бы получить какие-либо идеи о том, как это сделать.
2 ответа
Вот довольно компактное решение, основанное на предположении, что должен быть выбран ровно один человек из каждой группы (и это предположение не всегда может быть верным - это было немного неясно из ОП). Он использует тот факт, что один человек из каждой группы должен быть выбран, поэтому, если мы добавим имена в группы и использовать expand.grid()
тогда у нас есть решение сразу.
DF <- data.frame(names=c("Alex","David","John","Zoe"),
groups=c(1, 2, 1, 3),
stringsAsFactors =FALSE)
expand.grid(lapply(unique(DF$groups), function(i) {DF$names[which(DF$groups==i)]}))
Это производит
Var1 Var2 Var3
1 Alex David Zoe
2 John David Zoe
какие две комбинации вы были после. Немного более компактное решение (все еще использующее базу R) будет
expand.grid(by(DF, DF$groups, function(x) x$names))
что, возможно, легче читать.
Он также работает с более сложными группировками:
DF <- data.frame(names=c("Alex","David","John","Zoe", "Bob", "Charles"),
groups=c(1, 2, 1, 3, 2, 3),
stringsAsFactors =FALSE)
expand.grid(by(DF, DF$groups, function(x) x$names))
который производит
Var1 Var2 Var3
1 Alex David Zoe
2 John David Zoe
3 Alex Bob Zoe
4 John Bob Zoe
5 Alex David Charles
6 John David Charles
7 Alex Bob Charles
8 John Bob Charles
Теперь, если вы хотите выбрать менее одного из каждой группы, то приведенный выше код должен быть перенесен и применен к результатам, полученным combn()
,
Вот другой способ сделать это
Найдите все возможные групповые комбинации:
names <- c("Alex","David","John","Zoe")
x <- expand.grid(names, names, names)
Все возможные группы:
Var1 Var2 Var3
1 Alex Alex Alex
2 David Alex Alex
3 John Alex Alex
4 Zoe Alex Alex
5 Alex David Alex
6 David David Alex
7 John David Alex
8 Zoe David Alex
9 Alex John Alex
10 David John Alex
11 John John Alex
12 Zoe John Alex
13 Alex Zoe Alex
14 David Zoe Alex
15 John Zoe Alex
16 Zoe Zoe Alex
17 Alex Alex David
18 David Alex David
19 John Alex David
20 Zoe Alex David
21 Alex David David
22 David David David
23 John David David
24 Zoe David David
25 Alex John David
26 David John David
27 John John David
28 Zoe John David
29 Alex Zoe David
30 David Zoe David
31 John Zoe David
32 Zoe Zoe David
33 Alex Alex John
34 David Alex John
35 John Alex John
36 Zoe Alex John
37 Alex David John
38 David David John
39 John David John
40 Zoe David John
41 Alex John John
42 David John John
43 John John John
44 Zoe John John
45 Alex Zoe John
46 David Zoe John
47 John Zoe John
48 Zoe Zoe John
49 Alex Alex Zoe
50 David Alex Zoe
51 John Alex Zoe
52 Zoe Alex Zoe
53 Alex David Zoe
54 David David Zoe
55 John David Zoe
56 Zoe David Zoe
57 Alex John Zoe
58 David John Zoe
59 John John Zoe
60 Zoe John Zoe
61 Alex Zoe Zoe
62 David Zoe Zoe
63 John Zoe Zoe
64 Zoe Zoe Zoe
Найдите группы, которые удовлетворяют условиям:
x <- x[which(x[,1] != x[,2]),]
x <- x[which(x[,1] != x[,3]),]
x <- x[which(x[,2] != x[,3]),]
x <- x[-which((x[,1] == "Alex" & x[,2] == "John")),]
x <- x[-which((x[,1] == "Alex" & x[,3] == "John")),]
x <- x[-which((x[,2] == "Alex" & x[,3] == "John")),]
x <- x[-which((x[,2] == "Alex" & x[,1] == "John")),]
x <- x[-which((x[,3] == "Alex" & x[,1] == "John")),]
x <- x[-which((x[,3] == "Alex" & x[,2] == "John")),]
Результат:
Var1 Var2 Var3
8 Zoe David Alex
14 David Zoe Alex
20 Zoe Alex David
28 Zoe John David
29 Alex Zoe David
31 John Zoe David
40 Zoe David John
46 David Zoe John
50 David Alex Zoe
53 Alex David Zoe
55 John David Zoe
58 David John Zoe