1

举个例子:

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

似乎expboltzmann函数中对元素和向量进行操作,并且知道何时做正确的事情。是否sum“展开”输入向量并将表达式应用于值?有人可以解释这在 R 中是如何工作的吗?

编辑:感谢您对 R n00b 的所有评论、澄清和耐心。总之,这个工作的原因对于来自其他语言的我来说并不是很明显。以python为例。您将首先计算总和,然后计算向量中每个元素的值。

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

而 Rsum(exp(x/t))可以内联计算。

4

3 回答 3

4

这在R 简介第 2.2 节:向量算术中进行了解释。

向量可以在算术表达式中使用,在这种情况下,操作是逐个元素执行的。出现在同一表达式中的向量不必都具有相同的长度。如果不是,则表达式的值是一个与表达式中出现的最长向量具有相同长度的向量。表达式中较短的向量会根据需要(可能是部分地)循环使用,直到它们与最长向量的长度相匹配。特别是简单地重复一个常数。因此,通过上述任务,命令

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

生成一个长度为 11 的新向量 v,该向量通过逐个元素相加构成,2*x 重复 2.2 次,y 仅重复一次,1 重复 11 次。

于 2013-03-04T15:57:32.570 回答
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. Python 中的函数exp是“矢量化的”,这意味着当它应用于列表时,它将应用于列表中的每个项目。但是, sum 仍然按您期望的方式工作。

    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])

现在你明白它是怎么知道区别的了吗?

于 2013-03-04T15:58:50.960 回答
1

向量化在 R 中有几个稍微不同的含义。

它可能意味着接受一个向量输入,转换每个元素,并返回一个向量(就像exp做的那样)。

它也可能意味着接受向量输入并计算一些汇总统计量,然后返回一个标量值(就像这样mean做)。

sum符合第二种行为,但也有第三种向量化行为,它将创建跨输入的汇总统计。sum(1, 2:3, 4:6)例如,尝试。

于 2013-03-04T15:58:10.600 回答