Есть ли короткий способ проверить неэквивалентность каждой переменной друг от друга в R? - PullRequest
0 голосов
/ 14 июня 2019

Пытаясь решить следующую логическую проблему в R, я столкнулся с такой ситуацией:

Пять спортсменов (с номерами рубашек 1,2,3,4,5) участвуют в гонке, и онизаданные баллы, которые умножают номер их рубашки на ранг, в котором они закончили гонку;то есть, если спортсмен с футболкой № 2 финиширует 5-м, он получает 2 * 5 = 10 баллов.
Спортсмен с футболкой № 1 не финишировал в гонке 4-м и 5-м.
Сумма общего количества очков этих5 спортсменов после гонки - 41.
Найдите ранг каждого спортсмена, закончившего гонку.

Я закончил задачу с помощью следующего кода и заметил, что в случае, если один сталкивается с более чем 5 переменными, проверка неэквивалентности всех их друг от друга может быть очень громоздкой.Например, в 10 переменных это требует C (10,2) = 45 сравнений.

for (o in as.integer(1:5)) {
  for (t in as.integer(1:5)) {
    for (th in as.integer(1:5)) {
      for (f in as.integer(1:5)) {
         for (fi in as.integer(1:5)) {
if (o+2*t+3*th+4*f+5*fi == 41 && 
(o != 4 && o != 5) && 
# To check the following way in more complex cases is non-useful
((o!=t) && (o!=th) && (o!=f) && (o!=fi) && (t!=th) && (t!=f) && (t!=fi) && (th!=f) && (th!=fi) && (f!=fi))) {print(c(o,t,th,f,fi))}  
    }}}}}
#     o t th f fi
# [1] 2 5 4 3 1

Есть ли короткий способ проверить неэквивалентность каждой переменной друг другу в R?

Источник (исходной задачи): Мехмет Эмрехан ХАЛИЧИ, "Brain Sport 1", 2019 (на турецком языке)

Ответы [ 4 ]

3 голосов
/ 14 июня 2019

Это может быть не самый эффективный способ памяти, так как я ищу все возможные комбинации, но вот моя первоначальная мысль о том, как бы я подошел к этому

#Get all possible combinations of ranks that can be taken
#Player 1 can take any place from 1:3, rest all can take any place from 1:5
df1 <- expand.grid(1:3, 1:5, 1:5, 1:5, 1:5)

#Find combinations where after multiplying by the scores sum of it is 41

df2 <- df1[colSums(t(df1) * 1:5) == 41, ]
#Or
#df2 <- df1[rowSums(t(t(df1) * 1:5)) == 41, ]

#Keep only the rows which have only unique combination of ranks
df2[!apply(df2, 1, anyDuplicated), ]

#    Var1 Var2 Var3 Var4 Var5
#209    2    5    4    3    1
2 голосов
/ 14 июня 2019

Существует пакет permute, который вы можете использовать:

library("permute")
d <- rbind(1:5, allPerms(5))
df <- as.data.frame(d)
names(df) <- c("o", "t", "th", "f", "fi")
subset(df, (o+2*t+3*th+4*f+5*fi == 41) &  (o != 4 & o != 5))

#> subset(df, (o+2*t+3*th+4*f+5*fi == 41) &  (o != 4 & o != 5))
#   o t th f fi
#48 2 5  4 3  1

Вот вариант (можно использовать для других значений n):

n <- 5
d <- rbind(1:n, allPerms(n))
df <- as.data.frame(d)
names(df) <- paste0("r", 1:n)
subset(df, (d %*% (1:n) == 41) &  (r1 != 4 & r1 != 5))

или

n <- 5
df <- as.data.frame(rbind(1:n, allPerms(n)))
df <- subset(df, V1 < 4)
subset(df, as.matrix(df) %*% (1:n) == 41)
1 голос
/ 14 июня 2019

Мое решение состояло бы в том, чтобы сделать мою собственную функцию перестановки, поэтому в действительности, вероятно, проще (и более эффективно / безопаснее) использовать пакет permute, который предложил jogo.

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

perm <- function(n, perm){
    pos=seq(n)
    res=integer(n)
    x=rev(seq(n))-1
    for(i in seq(n)){
        y  = 1 + perm%/%factorial(x[i])
        res[i] = pos[y]
        pos=pos[-y]
        perm = perm - factorial(x[i])*(y-1)
    }
    return(res)
}
ord = list()
for(i in seq(factorial(5))-1)
{
    p = perm(5,i)
    if(sum(p*1:5)==41 & p[1] < 4) ord =  append(ord,list(p))
}

ord
## [[1]]
## [1] 2 5 4 3 1

Это решение использует вложенные циклы for, поэтому оно действительно не очень хорошо подходит для R, но, возможно, интересно с алгоритмической точки зрениязрения.

0 голосов
/ 14 июня 2019

Решение Аарона Хеймана:

for (o in as.integer(1:5)) {
  for (t in as.integer(1:5)) {
    for (th in as.integer(1:5)) {
      for (f in as.integer(1:5)) {
         for (fi in as.integer(1:5)) {
if (o+2*t+3*th+4*f+5*fi == 41 && 
(o != 4 && o != 5) && 
( all( (1:5) %in% c(o,t,th,f,fi)) )) { # Trick
print(c(o,t,th,f,fi))}  
    }}}}}
# [1] 2 5 4 3 1

Это решение работало хорошо, так как с возможными значениями переменных (то есть, 1,2,3,4,5) легко работать, и проверка была легко выполнена с помощью all( (1:5) %in% c(o,t,th,f,fi)).

...