Получите самые повторяющиеся (x, y) значения в двух столбцах в кадре данных

Я храню значения (x, y) в кадре данных. Я хочу вернуть наиболее часто возникающую комбинацию (x, y).

Вот пример:

> x = c(1, 1, 2, 3, 4, 5, 6)
> y = c(1, 1, 5, 6, 9, 10, 12)
> xy = data.frame(x, y)
> xy
  x  y
1 1  1
2 1  1
3 2  5
4 3  6
5 4  9
6 5 10
7 6 12

Наиболее распространенным значением (x, y) будет (1, 1).

Я попробовал ответить здесь для одного столбца. Он работает для одного столбца, но не работает для совокупности из двух столбцов.

> tail(names(sort(table(xy$x))), 1)
[1] "1"
> tail(names(sort(table(xy$x, xy$y))), 1)
NULL

Как получить наиболее повторяющиеся (x, y) значения в двух столбцах в кадре данных в R?

EDIT: c(1, 2) следует считать отличным от c(2, 1).

Ответ 1

(Несмотря на все плюсы, гибрид @DavidArenburg и мои подходы

res = do.call("paste", c(xy, sep="\r"))
which.max(tabulate(match(res, res)))

может быть простым и эффективным.)

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

x = match(xy[[1]], unique(xy[[1]]))
y = match(xy[[2]], unique(xy[[2]]))

Затем закодируйте комбинацию столбцов с уникальными значениями

v = x + (max(x) - 1L) * y

Индексирование минимизирует диапазон рассматриваемых значений, а кодирование сводит двумерную задачу к одному измерению. Эти шаги уменьшают пространство, необходимое для любой табуляции (как и table() в других ответах) до минимума, не создавая векторов символов.

Если кто-то хотел наиболее распространенное вхождение в одном измерении, тогда можно было индексировать и табулировать v

tbl = tabulate(match(v, v))

и найдите индекс первого вхождения максимального значения (ов), например,

df[which.max(tbl),]

Здесь функция, выполняющая магию

whichpairmax <- function(x, y) {
    x = match(x, unique(x)); y = match(y, unique(y))
    v = x + (max(x) - 1L) * y
    which.max(tabulate(match(v, v)))
}

и несколько тестов

> set.seed(123)
> xy[whichpairmax(xy[[1]], xy[[2]]),]
  x y
1 1 1
> xy1 = xy[sample(nrow(xy)),]
> xy1[whichpairmax(xy1[[1]], xy1[[2]]),]
  x y
1 1 1
> xy1
  x  y
3 2  5
5 4  9
7 6 12
4 3  6
6 5 10
1 1  1
2 1  1

Для произвольного data.frame

whichdfmax <- function(df) {
    v = integer(nrow(df))
    for (col in df) {
        col = match(col, unique(col))
        v = col + (max(col) - 1L) * match(v, unique(v))
    }
    which.max(tabulate(match(v, v)))
}

Ответ 2

Не знаете, как будет выглядеть нужный вывод, но здесь возможно решение

res <- table(do.call(paste, xy))
res[which.max(res)]
# 1 1 
#   2 

Чтобы получить фактические значения, можно было сделать

res <- do.call(paste, xy) 
xy[which.max(ave(seq(res), res, FUN = length)), ]
#   x y
# 1 1 1

Ответ 3

Try

library(data.table)
setDT(xy)[, .N,list(x,y)][which.max(N)]
#   x y N
#1: 1 1 2

Ответ 4

t<-table(xy)
which(t == max(t), arr.ind = TRUE)

Update:

Как указал Дэвид Аренбург, исходный код возвращал только индекс значений из функции table(xy). Если вам нужны значения и, возможно, количество вхождений пары max, вы можете попробовать следующее:

t<-table(xy)
indexes <- which(t == max(t), arr.ind = TRUE)[1,]
x_value <- dimnames(t)$x[indexes["x"]]
y_value <- dimnames(t)$y[indexes["y"]]
rep_number <- max(t)

Теперь я подозреваю, что есть лучший способ написать последние три строки кода, но я все еще новичок в мире R

Ответ 5

library(data.table)
DT <- data.table(xy)
tail(DT[, Count := .N, by = c("x", "y")][ order(Count) ], 1)
    x y Count
 1: 1 1     2

Ответ 6

Как насчет этого?

x = c(1, 1, 2, 3, 4, 5, 6)
y = c(1, 1, 5, 6, 9, 10, 12)
xy = data.frame(x, y)

table(xy)
y
x   1 5 6 9 10 12
1 2 0 0 0  0  0
2 0 1 0 0  0  0
3 0 0 1 0  0  0
4 0 0 0 1  0  0
5 0 0 0 0  1  0
6 0 0 0 0  0  1

Ответ 7

library(dplyr)
xy %>%
  group_by(x, y) %>%
  tally() %>%
  ungroup %>%
  top_n(1)

Ответ 8

С dplyr

library(dplyr)

xy %>% group_by(x, y) %>% summarise(n=n()) %>% 
   ungroup %>% filter(n==max(n)) %>% select(-n)

Ответ 9

Поздняя вечеринка, но здесь тест времени:

x<-sample(1:10,1e5,rep=TRUE)
y<-sample(1:10,1e5,rep=TRUE)


martin  <- function(x, y) {
    x = match(x, unique(x)); y = match(y, unique(y))
    v = x + (max(x) - 1L) * y
    which.max(tabulate(match(v, v)))
}
akrun <-function(x,y) {
    library(data.table)
    xy<-data.frame(x,y)
setDT(xy)[, .N,list(x,y)][which.max(N)]
}
mucio <-function(x,y){
    xy<-data.frame(x,y)
    t<-table(xy)
indexes <- which(t == max(t), arr.ind = TRUE)[1,]
x_value <- dimnames(t)$x[indexes["x"]]
y_value <- dimnames(t)$y[indexes["y"]]
rep_number <- max(t)

}

sam<-function(x,y){
    library(dplyr)
    xy<-data.frame(x,y)
xy %>%
  group_by(x, y) %>%
  tally() %>%
  ungroup %>%
  top_n(1)

}
dimitris<-function(x,y){
    library(dplyr)
xy<-data.frame(x,y)
xy %>% group_by(x, y) %>% summarise(n=n()) %>% 
   ungroup %>% filter(n==max(n)) %>% select(-n)

}

microbenchmark(martin(x,y),akrun(x,y),mucio(x,y),sam(x,y),dimitris(x,y),times=5)

Unit: milliseconds
           expr       min        lq       mean    median         uq
   martin(x, y) 11.727217 14.246913  41.359218 14.384385  82.639796
    akrun(x, y)  4.426462  4.613420   4.866548  4.892432   5.011406
    mucio(x, y) 73.938586 74.037568 103.941459 79.516207 145.232870
      sam(x, y)  8.356426  8.586212   8.919787  8.586521   8.775792
 dimitris(x, y)  8.618394  8.738228   9.252105  9.063965   9.075298
        max neval cld
  83.797780     5  a 
   5.389018     5  a 
 146.982062     5   b
  10.293983     5  a 
  10.764640     5  a

Ответ 10

Использование sqldf:

library(sqldf)    
sqldf('SELECT x, y 
          FROM xy 
          GROUP BY (x||y) 
          ORDER BY COUNT(*) DESC 
          LIMIT 1')
  x y
1 1 1 

Если мы хотим показать частотный столбец, а не одну строку (в случае наличия связей):

x = c(1, 1, 2, 3, 4, 12, 12)
y = c(1, 1, 5, 6, 9, 12, 12)
xy = data.frame(x, y)

sqldf('SELECT x, y, COUNT(*) AS freq
      FROM xy 
      GROUP BY (x||y) 
      ORDER BY COUNT(*) DESC')

   x  y freq
1  1  1    2
2 12 12    2
3  2  5    1
4  3  6    1
5  4  9    1