Упорядочить по нескольким условиям в R - PullRequest
3 голосов
/ 23 мая 2019

Имеет следующий набор данных:

test <- data.frame(name= c("A", "B", "C", "D", "E"), v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))

  name v1 v2
    A  2  3
    B  4  4
    C  1  2
    D  1  1
    E  2  5

Я хочу проверить концепцию доминирования актера / узла, что означает, что для каждой строки / записи я хочу увидеть, имеет ли она самое высокое значение в наборе данных. Например, B выше, чем A, C и D для v1 и v2. Так что он «доминирует» над всеми остальными рядами. Например, E только выше, чем A, C и D, поэтому он доминирует над этими 3 строками.

Говоря математически, я ищу: i >= j, for v1_i >= v1_j and v2_i >= v2_j.

Организация или сортировка по столбцам не работает, потому что она не показывает, как одна строка будет навязывать другую, поскольку она сортируется сначала по одному столбцу, а затем по другому.

РЕДАКТИРОВАТЬ: просто чтобы добавить пример, конечный результат будет:

B dominates A, C, D
E dominates A, D, C
C dominates D
A dominates C, D

Не имеет значения, как это будет выглядеть. Если это в форме направленной сети / матрицы или таблицы с переменной со всеми буквами.

Ответы [ 5 ]

2 голосов
/ 23 мая 2019

У меня есть выход, надеюсь, это поможет:)

 c$v3= rowSums(x = c[,-1])
 c = c[order(c$v3,decreasing = T),]
 k = length(c$name)
 for (i in 1:k ) {
   if (i == k) {

   }else {
    a = c$name[i+1:k]
    a = as.character(a[!is.na(a)])
    b = c$name[i]
    b  = as.character(b[!is.na(b)])

   cat(b,"greater than ", a,"\n",sep=" ") 
 }

}

, поэтому ваш вывод будет

 B greater than  E A C D 
 E greater than  A C D 
 A greater than  C D 
 C greater than  D 
2 голосов
/ 23 мая 2019

for петля очень неэффективна в R .Пожалуйста, избегайте их!Вы можете просто сделать это с помощью apply:

# Names column
names = c("A", "B", "C", "D", "E")
# Dataframe
test <- data.frame(name= names, v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))

# Display function
findLowerValues <- function(row, test, names) {
  rep <- test$v1 <= row["v1"] & test$v2 <= row["v2"] & test$name != row["name"]
  cat(row["name"], 'dominates', names[rep], "\n")
}

# Apply the display function
# axis : row
# Extra args: the full dataset and names
apply(test, 1, findLowerValues, test=test, names=names)
# A dominates C D 
# B dominates A C D 
# C dominates D 
# D dominates  
# E dominates A C D 
# NULL
1 голос
/ 24 мая 2019

Если вы не возражаете против решения data.table, возможно использование неравных объединений следующим образом:

library(data.table)
setDT(test)
test[test, on=.(v1<=v1, v2<=v2), .(actor=i.name, node=x.name), by=.EACHI, allow.cartesian=TRUE][ 
    actor!=node, .(actor, node)]

вывод:

   actor node
1:     A    C
2:     A    D
3:     B    A
4:     B    C
5:     B    D
6:     C    D
7:     E    A
8:     E    C
9:     E    D
1 голос
/ 23 мая 2019

Сначала split мы помещаем каждую строку в список строк и передаем ее mapply, rep съедаем каждую строку nrow(test) раз, сравниваем их со всем фреймом данных test и выбираем name, который имеет все значения больше этой строки. Поскольку это также будет сопоставлять строки с самим собой, мы используем setdiff, чтобы удалить эти name значения.

mapply(function(x, y) setdiff(
   test$name[rowSums(x[rep(1, nrow(test)),] >= test[-1]) == ncol(test) - 1], y), 
   split(test[-1], test$name), test$name)

#$A
#[1] "C" "D"

#$B
#[1] "A" "C" "D"

#$C
#[1] "D"

#$D
#character(0)

#$E
#[1] "A" "C" "D"

Данные

test <- data.frame(name= c("A", "B", "C", "D", "E"), v1 = c(2, 4, 1, 1, 2),
                   v2 = c(3, 4, 2, 1, 5), stringsAsFactors = FALSE)
1 голос
/ 23 мая 2019

Вот предложение.Это, наверное, не самое элегантное решение.У нас может быть функция compare, которая проверяет, доминирует ли одна буква над другой (если это не идентичная буква), а затем использует два вложенных sapply s.

my_letters <- c("A", "B", "C", "D", "E")
test <- data.frame(name= my_letters, v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))

get_row<-function(letter){
  test[test$name==letter,2:ncol(test)]
}

compare<-function(letter,i){
  if(letter!=i){
    if(!sum(get_row(letter) < get_row(i))){
      return(i)     
    }
  }
}

result <- sapply(my_letters, function(let) unlist(sapply(my_letters, compare, letter=let)))

приводит к списку:

$A
  C   D 
"C" "D" 

$B
  A   C   D 
"A" "C" "D" 

$C
  D 
"D" 

$D
NULL

$E
  A   C   D 
"A" "C" "D" 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...