У меня есть фрейм данных, который выглядит так:

id   value1  value2   value3   value4
A      14       24       22        9
B      51       25       29       33
C       4       16        8       10
D       1        4        2        4       

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

Так, например, для идентификатора D это будут A, B и C. Для C это будет B, для A это B, а для B нет строки.

Я пытался сделать это, просматривая строки и сравнивая каждый столбец, но на это уходит много времени. Исходный набор данных содержит около 5000 строк и 20 столбцов для сравнения. Я уверен, что есть способ сделать это более эффективно. Спасибо за вашу помощь!

1
Afoy 17 Фев 2016 в 17:08

3 ответа

Лучший ответ

Я не знаю простой функции для выполнения этой задачи. Вот как бы я поступил.

library(dplyr)

DF <- data.frame(
  id = c("A", "B", "C", "D"),
  value1 = c(14, 51, 4, 1),
  value2 = c(24, 25, 16, 4),
  value3 = c(22, 29, 8, 2),
  value4 = c(9, 33, 10, 4),
  stringsAsFactors = FALSE)

# get the order for each value
tmp <- lapply(select(DF, -id), function(x) DF$id[order(x)]) 

# find a set of "biggers" for each id 
tmp <- lapply(tmp, function(x) data.frame(
    id = rep(x, rev(seq_along(x))-1), 
    bigger = x[lapply(seq_along(x), function(i)
      which(seq_along(x) > i)) %>% unlist()],
    stringsAsFactors = FALSE)) 

# inner_join all, this keeps "biggers" in all columns
out <- NULL
for (v in tmp) {
  if (is.null(out)) {
    out <- v
  } else {
    out <- inner_join(out, v, by = c("id", "bigger"))
  }
}

Это дает вам:

out
#  id bigger
#1  D      C
#2  D      A
#3  D      B
#4  C      B
#5  A      B
1
Kota Mori 17 Фев 2016 в 14:59

Я думаю, это прекрасно работает:

ind <- which(names(df) == "id")
apply(df[,-ind],1,function(x) df$id[!rowSums(!t(x < t(df[,-ind])))] )
# [[1]]
# [1] "B"
# 
# [[2]]
# character(0)
# 
# [[3]]
# [1] "B"
# 
# [[4]]
# [1] "A" "B" "C"
1
Laterow 17 Фев 2016 в 15:03

Вот подход, который возвращает результаты в формате фрейма данных.

library(tidyr)
library(dplyr)

# reshape data to long format
td <- d %>% gather(key, value, value1:value4)

# create a copy w/ different names for merging
td2 <- td %>% select(id2 = id, key, value2 = value)

# full outer join to produce one row per pair of IDs
dd <- merge(td, td2, by = "key", all = TRUE)

# the result
dd %>%
  filter(id != id2) %>% 
  group_by(id, id2) %>%
  summarise(all_less = !any(value >= value2)) %>%
  filter(all_less)

результаты (id меньше id2)

     id    id2 all_less
  (fctr) (fctr)    (lgl)
1      A      B     TRUE
2      C      B     TRUE
3      D      A     TRUE
4      D      B     TRUE
5      D      C     TRUE

данные

d <- structure(list(
  id = structure(1:4, .Label = c("A", "B", "C", "D"), class = "factor"), 
  value1 = c(14L, 51L, 4L, 1L), 
  value2 = c(24L, 25L, 16L, 4L), 
  value3 = c(22L, 29L, 8L, 2L), value4 = c(9L, 33L, 10L, 4L)
), 
.Names = c("id", "value1", "value2", "value3", "value4"), 
class = "data.frame", row.names = c(NA, -4L)
)
1
davechilders 17 Фев 2016 в 15:00