#r #sequence #sapply
#r #последовательность #sapply
Вопрос:
Недавно я использовал следующую строку кода, ожидая получить ошибку. К моему удивлению, мне был выдан вывод:
> outer(1:5,5:10,c=1:3,function(a,b,c) 10*a 100*b 1000*c)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1510 3610 2710 1810 3910 3010
[2,] 2520 1620 3720 2820 1920 4020
[3,] 3530 2630 1730 3830 2930 2030
[4,] 1540 3640 2740 1840 3940 3040
[5,] 2550 1650 3750 2850 1950 4050
Похоже, что код оценивается outer(1:5,5:10,function(a,b) 10*a 100*b) 1000*(1:3)
. Почему это так? И в качестве продолжения, есть ли какая-либо четкая причина, по которой это не выдает предупреждения? На мой взгляд, пользователь, который ввел подобный код, вероятно, ожидал вывода, охватывающего все значения a, b и c.
Ответ №1:
Это ожидаемое поведение, основанное на правилах утилизации R. Это не имеет ничего общего с outer
как таковым, хотя это может быть сюрпризом, если вы думаете outer
, что каким-то образом применяет функцию к полям.
Вместо outer
этого принимает два вектора X
и Y
в качестве первых двух аргументов. Он принимает X
и rep
лицензирует его length(Y)
раз. Аналогично, он принимает Y
и rep
лицензирует его length(X)
раз. Затем он просто запускает вашу функцию FUN
для этих двух длинных векторов, передавая long X
в качестве первого аргумента и long Y
в качестве второго аргумента. Любые другие аргументы FUN
должны передаваться непосредственно в качестве аргументов outer via ...
(как вы сделали с c = 1:3
).
Результатом является один длинный вектор, который превращается в матрицу путем записи его dim
атрибута в качестве исходных значений length(X)
by length(Y)
.
Теперь, в конкретном примере, который вы привели, X
имеет 5 элементов (1: 5) и Y
6 (5: 10). Поэтому ваша анонимная функция вызывается для двух векторов длиной 30 и одного вектора длиной 3. Правила R по переработке диктуют, что если переработанный вектор аккуратно вписывается в более длинный вектор без частичной переработки, предупреждение не выдается.
Чтобы увидеть это, возьмите свою анонимную функцию и попробуйте ее снаружи outer
с двумя векторами длиной 30 и одним вектором длиной 3:
f <- function(a, b, c) 10*a 100*b 1000*c
f(1:30, 1:30, 1:3)
#> [1] 1110 2220 3330 1440 2550 3660 1770 2880 3990 2100 3210 4320 2430
#> [14] 3540 4650 2760 3870 4980 3090 4200 5310 3420 4530 5640 3750 4860
#> [27] 5970 4080 5190 6300
3 перерабатывается в 30, поэтому предупреждения нет.
И наоборот, если произведение длины двух векторов, которые вы передаете outer
, не кратно 3, вы получите предупреждение:
outer(1:5,6:10,c=1:3,function(a,b,c) 10*a 100*b 1000*c)
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1610 3710 2810 1910 4010
#> [2,] 2620 1720 3820 2920 2020
#> [3,] 3630 2730 1830 3930 3030
#> [4,] 1640 3740 2840 1940 4040
#> [5,] 2650 1750 3850 2950 2050
#> Warning message:
#> In 10 * a 100 * b 1000 * c :
#> longer object length is not a multiple of shorter object length
Комментарии:
1. Если X и Y расширяются на
rep
, то почему это выглядит так, как будтоouter
применяется функция над полями?rep(1:3,4)
выдаетc(1,2,3,1,2,3,1,2,3,1,2,3)
иrep(4:7,3)
выдаетc(4,5,6,7,4,5,6,7,4,5,6,7)
. Суммирование этих результатов даетc(5,7,9,8,6,8,7,9,7,6,8,10)
, что явно не соответствует результату изouter(1:3,4:7," ")
.2. @J.Mini на самом деле это было
rep(1:3, 4)
бы иrep(4:7, each = 3)
(обратите внимание наeach
)