2013-03-04 1 views
1

Рассмотрим следующий пример:Как функции, которые одновременно работают над векторами и их элементами, работают в R?

boltzmann <- function(x, t=0.1) { exp(x/t)/sum(exp(x/t)) } 
z=rnorm(10,mean=1,sd=0.5) 
exp(z[1]/t)/sum(exp(z/t)) 
[1] 0.0006599707 
boltzmann(z)[1] 
[1] 0.0006599707 

Оказывается, что exp в функции boltzmann работает над элементами и векторами и знает, когда делать правильные вещи. Является ли sum «разворачиванием» входного вектора и применением выражения для значений? Может кто-нибудь объяснить, как это работает в R?

Редактировать: Спасибо за все комментарии, разъяснения и терпение с помощью R n00b. Таким образом, причина, по которой это работает, не была сразу очевидна для меня, исходя из других языков. Возьмем, например, python. Сначала вы вычислили сумму, а затем вычислили значение для каждого элемента в векторе.

denom = sum([exp(v/t) for v in x]) 
vals = [exp(v/t)/denom for v in x] 

В то время как это R sum(exp(x/t)) может быть вычислена в линию.

+1

Я не совсем понимаю этот вопрос, в основном, потому что я не уверен, что вы ожидали. (Кстати, обратите внимание на то, что в R не существует такой вещи, как «элемент», число - это просто вектор длины 1. Например, попробуйте «x = 2; print (x [1]); print (x [ 1] [1]) '). –

+0

@DavidRobinson Извините, я новичок в R. Другой способ описать это - то, что в числителе x обрабатывается элементом по элементу и в знаменателе, он агрегируется для получения суммы. Как так? – drsnyder

ответ

3

Это может быть яснее, если вы оценили числитель и знаменатель отдельно:

x = rnorm(10,mean=1,sd=0.5) 
t = .1 
exp(x/t) 
# [1] 1.845179e+05 6.679273e+03 4.379369e+06 1.852623e+06 9.960374e+02 
# [6] 1.359676e+09 6.154045e+03 1.777027e+01 1.070003e+04 6.217397e+04 
sum(exp(x/t)) 
# [1] 2984044296 

Поскольку числитель представляет собой вектор длиной 10, а знаменатель представляет собой вектор длины 1, деление возвращает вектор длины 10.

Поскольку вы хотите сравнить это с Python, представьте себе следующие два правила были добавлены в Python (кстати, это похоже на использование массивов в numpy):

  1. Если разделить список рядом, он будет делить все элементы в списке по номеру:

    [2, 4, 6, 8]/2 
    # [1, 2, 3, 4] 
    
  2. функция exp в Python является «векторизованной», что означает, что, когда он применяется к списку будет применяться к каждому в списке. Однако сумма по-прежнему работает так, как вы ожидаете.

    exp([1, 2, 3]) => [exp(1), exp(2), exp(3)] 
    

В таком случае, представьте, как этот код будет оцениваться в Python:

t = .1 
x = [1, 2, 3, 4] 
exp(x/t)/sum(exp(x/t)) 

Он будет следовать следующие упрощения, используя эти два простых правила:

exp([v/t for v in x])/sum(exp([v/t for v in x])) 
[exp(v/t) for v in x]/sum([exp(v/t) for v in x]) 

Теперь вы видите, как он знает разницу?

+0

Спасибо, это имеет для меня смысл как объяснение. По-прежнему остается загадкой, как R знает, как обрабатывать x в отличие от x в числителе. Вычисляется ли сумма один раз или для каждого элемента в x? – drsnyder

+0

@drsnyder: Причина в том, что 'sum' не является векторизованным, а' exp' -. Таким образом, 'sum' работает на полном векторе, а не на каждом элементе. (Как «сумма» вычислялась один раз для каждого элемента в 'x'? Это будет поддерживать вектор точно так же - не очень полезная функция.) –

+0

@drsnyder: Положите другой путь: что вы ожидаете от результата' sum (1: 5) 'быть? Вы ожидаете, что это будет '15', или' c (1, 2, 3, 4, 5) '(потому что это« сумма »каждого отдельного элемента)? –

4

Это объясняется в An Introduction to R, Section 2.2: Vector arithmetic.

Векторы могут использоваться в арифметических выражениях, и в этом случае операции выполняются по элементам. Векторы, встречающиеся в , должны иметь одинаковые выражения одинаковой длины. Если это не так, значение выражения представляет собой вектор с той же длиной, что и самый длинный вектор , который встречается в выражении. Более короткие векторы в выражении : перерабатывают так часто, как нужно (возможно, дословно) , пока они не совпадут с длиной самого длинного вектора. В частности, константа просто повторяется. Таким образом, с указанными выше назначений команда

x <- c(10.4, 5.6, 3.1, 6.4, 21.7) 
y <- c(x, 0, x) 
v <- 2*x + y + 1 

генерирует новый вектор V длины 11, построенный путем сложения, поэлементно, 2 * х повторяется в 2,2 раза, у повторяется только один раз, и 1 повторяли 11 раз ,

+0

Это не объясняет, что происходит с 'sum' в функции. В числителе x обрабатывается элементом по элементу, но в знаменателе он перебирается для вычисления суммы. – drsnyder

+0

@drsnyder: Это не имеет смысла. 'x' не обрабатывается по-разному. 'x/t' возвращает вектор, потому что' t' перерабатывается вдоль 'x'. 'exp' также возвращает вектор. 'sum' возвращает вектор с длиной = 1, который затем перерабатывается вдоль числителя, то же, что и' x/t'. –

+0

Это имеет смысл для вас, но не сразу для меня, исходящих с других языков :). Необычно, что ценность магически переработана. См. Также мои комментарии ниже к Дэвиду. – drsnyder

1

Векторизация имеет несколько слегка разные значения в R.

Это может означать, принимая вектор ввод, преобразование каждого элемента, и возвращает вектор (например, exp делает).

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

sum соответствует второму поведению, но также имеет третье поведение векторизации, в котором он будет создавать сводную статистику по входам. Попробуйте, например, sum(1, 2:3, 4:6).

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