Как отсортировать матрицу по всем столбцам

Предположим, что

arr = 2 1 3
      1 2 3
      1 1 2

Как я могу отсортировать это в ниже?

arr = 1 1 2
      1 2 3
      2 1 3

То есть сначала по столбцу один, затем по столбцу два и т.д.

Ответ 1

Это будет работать:

arr[do.call(order, lapply(1:NCOL(arr), function(i) arr[, i])), ]

Что он делает:

arr[order(arr[, 1], arr[, 2], arr[ , 3]), ]

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

Ответ 2

Функция, за которой вы находитесь, - order (как я пришел к такому выводу - моя первая мысль была "хорошо, сортировка, а что насчет sort?". Пробовал sort(arr), который выглядит как сортирует arr в качестве вектора вместо строки. Посмотрев ?sort, я вижу в разделе "См. также: order для сортировки или переупорядочения переменных несколько.)).

Глядя на ?order, я вижу, что order(x,y,z, ...) будет упорядочиваться на x, разбивая связи на y, разбивая дальнейшие связи на z и т.д. Отлично - все, что мне нужно сделать, это передать в каждом столбце от arr до order для этого. (Для примера есть пример в разделе примеров ?order):

order( arr[,1], arr[,2], arr[,3] ) 
# gives 3 2 1: row 3 first, then row 2, then row 1.
# Hence:
arr[ order( arr[,1], arr[,2], arr[,3] ), ]
#     [,1] [,2] [,3]
#[1,]    1    1    2
#[2,]    1    2    3
#[3,]    2    1    3

Отлично!


Но это немного раздражает, что я должен написать arr[,i] для каждого столбца в arr - что, если я не знаю, сколько столбцов оно имеет заранее?

Ну, примеры показывают, как вы можете это сделать: используя do.call. В основном, вы делаете:

do.call( order, args )

где args - список аргументов в order. Поэтому, если вы можете составить список из каждого столбца arr, вы можете использовать его как args.

Один из способов сделать это - преобразовать arr в кадр данных, а затем в список - это автоматически поместит по одному столбцу на элемент списка:

arr[ do.call( order, as.list(as.data.frame(arr)) ), ]

as.list(as.data.frame бит kludgy - есть, конечно, другие способы создания списка, чтобы list[[i]] был i -й столбец arr, но это всего лишь один.

Ответ 3

Я написал эту небольшую функциональность, которая также уменьшает порядок cols позволяет выбирать столбцы для заказа и порядок

ord.mat = function(M, decr = F, cols = NULL){
    if(is.null(cols))
      cols = 1: ncol(M)
    out = do.call( "order", as.data.frame(M[,cols]))
    if (decr)
      out = rev(out)
    return(M[out,])
}

Ответ 4

У меня была аналогичная проблема, и решение кажется простым и элегантным:

t(apply(t(yourMatrix),2,sort))