2014-02-12 2 views
5

Я обнаружил удивительное поведение apply, что я задаюсь вопросом, может ли кто-нибудь объяснить. Давайте возьмем простую матрицу:Неожиданное поведение функции применения в R

> (m = matrix(1:8,ncol=4)) 
    [,1] [,2] [,3] [,4] 
[1,] 1 3 5 7 
[2,] 2 4 6 8 

Мы можем перевернуть его вертикально, таким образом:

> apply(m, MARGIN=2, rev) 
    [,1] [,2] [,3] [,4] 
[1,] 2 4 6 8 
[2,] 1 3 5 7 

Это применяет функцию rev() вектор разворота итеративно для каждого столбца. Но когда мы пытаемся применить обороты по строке, мы получаем:

> apply(m, MARGIN=1, rev) 
    [,1] [,2] 
[1,] 7 8 
[2,] 5 6 
[3,] 3 4 
[4,] 1 2 

.. 90 градусов против часовой стрелки вращения! Применить тот же результат, используя FUN=function(v) {v[length(v):1]}, так что это определенно не ошибка вина.

Любые объяснения для этого?

ответ

2

В документации говорится, что

Если каждый вызов FUN возвращает вектор длины п, а затем применить возвращает массив размерности с (п, тусклый (X) [MARGIN]), если п> 1 .

С этой точки зрения это поведение не является ошибкой, так оно и должно работать.

Можно задаться вопросом, почему это выбрано как настройка по умолчанию, а не для сохранения структуры исходной матрицы. Рассмотрим следующий пример:

> apply(m, 1, quantile) 
    [,1] [,2] 
0% 1.0 2.0 
25% 2.5 3.5 
50% 4.0 5.0 
75% 5.5 6.5 
100% 7.0 8.0 

> apply(m, 2, quantile) 
    [,1] [,2] [,3] [,4] 
0% 1.00 3.00 5.00 7.00 
25% 1.25 3.25 5.25 7.25 
50% 1.50 3.50 5.50 7.50 
75% 1.75 3.75 5.75 7.75 
100% 2.00 4.00 6.00 8.00 

> all(rownames(apply(m, 2, quantile)) == rownames(apply(m, 1, quantile))) 
[1] TRUE 

В соответствии? Действительно, почему мы ожидаем чего-нибудь еще?

+0

Спасибо за объяснение как механики, так и причины. Если последующий консенсус не идет на ответ Мэтью (казалось бы, одинаково правильный), я думаю, что вы прибили его. – geotheory

+0

Спасибо за комментарий, оцените его. – tonytonov

2

Когда вы передаете вектор строки в rev, он возвращает вектор-столбец.

t(c(1,2,3,4)) 

    [,1] [,2] [,3] [,4] 
[1,] 1 2 3 4 

rev(t(c(1,2,3,4))) 
[1] 4 3 2 1 

, который не то, что вы ожидали

 [,1] [,2] [,3] [,4] 
[1,] 4 3 2 1 

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

t(apply(m, MARGIN=1, rev)) 
    [,1] [,2] [,3] [,4] 
[1,] 7 5 3 1 
[2,] 8 6 4 2 
+0

Я вижу, что 't' заставляет матричную ориентацию, но можно сказать, что' vec' возвращает вертикальную или горизонтальную ориентацию? 'same (1:10, rev (t (10: 1)))' TRUE. – geotheory

+0

Возможно, более четко, «идентично» (rev (t (t (1:10))), rev (t (1:10))) 'is TRUE .. – geotheory

4

Это происходит потому, что apply возвращает которая определяется по столбцу, и вы повторяете строки.

В первой заявке apply представлена ​​каждая строка, которая затем является столбцом в результате.

Представляя функцию print показывает, что передается в rev на каждой итерации:

x <- apply(m, 1, print) 
[1] 1 3 5 7 
[1] 2 4 6 8 

То есть, каждый вызов печати передается вектор. Два вызова и c(1,3,5,7) и c(2,4,6,8) передаются функции.

Обратный вывод дает c(7,5,3,1) и c(8,6,4,2), то они используются как столбцы матрицы возврата, давая результат, который вы видите.

+0

Спасибо, Мэтью, я думаю, что вы на месте, но я думаю ответ принадлежит тонитонову для артикуляции с точки зрения документации и иллюстрации основополагающей философии. Кстати, печатная вещь освещала: «apply (m, 1, FUN = function (v) {print (« done »)))' (confusingly) дает как печатные, так и объектные отчеты, которые нужно что-то помнить :) – geotheory

+0

@ geotheory Вот почему я присвоил результат переменной. Это предотвращает печать возвращаемого объекта. В случае экспериментирования с 'print', нам нужны только аргументы, а не возвращаемое значение. Обтекание выражения в 'invisible()' также предотвращает печать окончательного результата, но при назначении переменной меньше нажатий клавиш. –

Смежные вопросы