努力创建差异函数
Struggling creating a difference function
所以我有一个家庭作业问题,我真的很难用 R 编写代码。
这就是问题所在:编写一个函数 difference()
以向量 X 作为参数,returns 是向量 X
每个元素和下一个元素之间的区别:
X[2]-X[1], X[3]-X[2], X[4]-X[3]
,等等
因此difference(c(5,2,9,4,8))
会returnc(-3,7,-5,4)
到目前为止我有这个:
difference<-function(X) {
for (i in X)
X.val<-X[i]-X[i-1]
return(X.val)
}
difference(c(5,2,9,4,8))
我似乎无法获得减去 X[2]-X[1]
的函数,而且它 return 比我 运行 该函数时应该多一个数。谁能帮帮我?
您的代码有几个问题。由于这是家庭作业,我不会提供正确的代码,但我会帮助突出显示您出错的地方,以帮助您更接近。我没有提供答案的唯一原因是因为这些都是很好的学习经历。如果您对更新的尝试发表评论,我会继续更新我的答案来指导您。
问题是您使用的是 for (i in X)
,它实际上会遍历 X
的值而不是它的索引。因此,在您的示例中,i
将等于 5,然后是 2,然后是 9,然后是 4,然后是 8。如果我们从 i == 5 开始,代码就是这样做的:X.val <- X[5] - X[5 - 1]
。此时您将 X.val
指定为 4,因为 X[5]
等于 8 而 X[4]
等于 4。在下一次迭代中,i == 2。所以这将设置X.val
到 -3 因为 X[2]
是 2 而 X[1]
是 5.
要解决此问题,您需要循环遍历 X
的索引。您可以使用 for (i in 1:length(X))
来完成此操作,其中 length(X)
将为您提供一个等于 X
中元素数量的数字。
您发现的下一个问题是您获得了一个额外的号码。重要的是要考虑输出中应该有多少数字,以及这对 i
应该从哪里开始意味着什么。提示:你真的应该从 1 开始吗?
最后,您在每次迭代中覆盖 X.val
。令我惊讶的是,你在结果中得到了一个额外的数字,因为你应该只收到 NA
,因为最后一个数字是 8 而 X
中没有 8 个元素。然而,您需要重写代码,这样您就不会覆盖 X.val
,而是在每次迭代时附加到它。
希望对您有所帮助。
更新 #1
如以下评论所述,您的代码现在如下所示:
difference <- function(X) {
for (i in 2:length(X)) {
X[i] <- X[i] - X[i-1]
}
return(X)
}
difference(c(5, 2, 9, 4, 8))
我们现在非常非常接近最终解决方案。我们只需要快速解决一个问题。
问题是我们现在覆盖了 X 的值,这很糟糕。由于我们的数字 c(5,2,9,4,8)
作为变量 X
传递到函数中,行 X[i] <- X[i] - X[i-1]
将开始覆盖我们的值。因此,一次进行一次迭代,我们得到以下结果:
步骤1:
i
设置为 2
X[2]
目前等于 2
- 然后我们 运行 行
X[i] <- X[i] - X[i-1]
,它的计算如下: X[2] <- X[2] - X[1]
--> X[2] <- 2 - 5
--> X[2] <- -3
X[2]
现在设置为 -3
第2步:
i
设置为 3
X[3]
目前等于 9
- 然后我们 运行
X[i] <- X[i] - X[i-1]
,它的计算方式如下: X[3] <- X[3] - X[2]
--> X[3] <- 9 - -3
--> X[3] <- 12
X[3]
现在设置为 12
正如您从前两次迭代中看到的那样,我们正在覆盖我们的 X
变量,这直接影响我们在 运行 函数时获得的差异。
为了解决这个问题,我们只需回到使用 X.val
,就像我们以前一样。因为这个变量没有值,所以没有什么可以被覆盖。我们的函数现在看起来像这样:
difference <- function(X) {
for (i in 2:length(X)) {
X.val[i] <- X[i] - X[i-1]
}
return(X.val)
}
现在,对于每次迭代,没有任何内容被覆盖,我们 X
的值保持不变。但是,我们将遇到两个问题。如果我们 运行 这个新代码,我们将得到一个错误,告诉我们 x.diff
不存在。早些时候,我告诉过您可以索引您正在创建的变量,这是事实。我们只需要先告诉 R 我们正在创建的变量是一个变量。有几种方法可以做到这一点,但第二个最好的方法是创建一个与我们预期输出具有相同 class
的变量。因为我们知道我们希望我们的输出是一个数字列表,所以我们可以让 X.val
成为一个 numeric
向量。我们的代码现在看起来像这样:
difference <- function(X) {
X.val <- numeric()
for (i in 2:length(X)) {
X.val[i] <- X[i] - X[i-1]
}
return(X.val)
}
注意 X.val
的赋值发生在我们进入 for
循环之前。作为练习,您应该考虑为什么会这样,然后尝试将它移到 for
循环中,看看会发生什么。
这样,就解决了我们的第一个问题。尝试 运行ning 代码,看看你得到了什么。您会注意到输出的第一个元素是 NA
。为什么会出现这种情况,我们该如何解决?提示:与i
.
的值有关
更新#2
现在我们有了正确的答案,让我们看一下 R 提供的一些提示和技巧。R 有一些可以在向量上使用的固有特性。要查看此操作,运行 以下示例:
a <- 1:10
b <- 11:20
a + b
a - b
a * b
a / b
如您所见,R 会自动对向量执行所谓的 "element wise" 运算。您会注意到 a - b
与我们在这里尝试做的非常相似。区别在于 a
和 b
是两个不同的向量,我们一次处理一个向量。那么我们如何设置我们的问题来像这样工作呢?简单:我们创建两个向量。
x <- c(5, 2, 9, 4, 8)
y <- x[2:length(x)]
z <- x[1:(length(x)-1)]
y - z
你应该注意到 y - z
现在给了我们我们想要从函数中得到的答案。我们可以像这样将其应用于我们的 difference
函数:
difference <- function(X) {
y <- X[2:length(X)]
z <- X[1:(length(X)-1)]
return(y-z)
}
使用这个技巧,我们不再需要使用 for
循环,这在 R 中可能非常慢,而是使用向量化操作,这在 R 中非常快。如注释,我们实际上可以跳过将这些值分配给 y
和 z
的步骤,而是直接 return 我们想要的:
difference <- function(X) {
return(X[2:length(X)] - X[1:(length(X)-1)])
}
我们现在刚刚成功创建了一个单行函数来完成我们希望做的事情。让我们看看我们是否可以让它更干净。 R 有两个非常方便查看数据的函数:head()
和 tail()
。 head
允许您查看前 n 个元素,tail
允许您查看最后 n 个元素。让我们看一个例子。
a <- 1:50
head(a) # defaults to 6 elements
tail(a) # defaults to 6 elements
head(a, n=20) # we can change how many elements to return
tail(a, n=20)
head(a, n=-1) # returns all but the last element
tail(a, n=-1) # returns all but the first element
最后两个对于我们想要做的事情来说是最重要的。在我们最新版本的 difference
中,我们正在查看 X[2:length(X)]
,这是 "all elements in X
except the first element" 的另一种说法。我们还查看了 X[1:(length(X)-1)]
,这是 "all elements in X
except the last element" 的另一种说法。让我们清理一下:
difference <- function(X) {
return(tail(X, -1) - head(X, -1))
}
如您所见,这是定义我们函数的更简洁的方法。
这就是技巧。让我们看一些提示。第一个是从像这样的简单函数中删除 return
。如果函数不是赋值,R 将自动 return 最后一个命令。要查看实际效果,请尝试 运行 使用两个不同的函数:
difference_1 <- function(X) {
x.diff <- tail(X, -1) - head(X, -1)
}
difference_1(1:10)
difference_2 <- function(X) {
tail(X, -1) - head(X, -1)
}
difference_2(1:10)
在 difference_1
中,您会注意到 return 没有任何内容。这是因为该命令是赋值命令。您可以使用 return
命令将其强制为 return 一个值。
下一个提示是您暂时不需要的,但它很重要。回到我们拥有的 difference
的当前版本(您现在使用的代码,而不是我在本次更新中提到的任何内容),我们将值分配给 X.val
,这导致它 "grow"随着时间的推移。要查看这意味着什么,运行 下面的代码:
x.val <- numeric()
length(x)
x.val[1] <- 1
length(x)
x.val[2] <- 2
length(x)
你会看到长度在不断增长。这通常是 R 代码中 巨大 减速的一个点。正确的方法是创建 x.val
,其长度等于我们需要的长度。这要快得多,并且会在将来为您省去一些痛苦。它的工作原理如下:
difference <- function(X) {
x.val <- numeric(length=(length(X) - 1))
for (i in 2:length(X)) {
x.val[i-1] <- X[i] - X[i-1]
}
return(x.val)
}
在我们当前的代码中,这并没有真正的区别。但是,如果您将来要处理非常大的数据,这可能需要数小时甚至数天的计算时间。
我希望这一切能帮助您更好地理解 R 中的一些功能。祝一切顺利!
所以我有一个家庭作业问题,我真的很难用 R 编写代码。
这就是问题所在:编写一个函数 difference()
以向量 X 作为参数,returns 是向量 X
每个元素和下一个元素之间的区别:
X[2]-X[1], X[3]-X[2], X[4]-X[3]
,等等
因此difference(c(5,2,9,4,8))
会returnc(-3,7,-5,4)
到目前为止我有这个:
difference<-function(X) {
for (i in X)
X.val<-X[i]-X[i-1]
return(X.val)
}
difference(c(5,2,9,4,8))
我似乎无法获得减去 X[2]-X[1]
的函数,而且它 return 比我 运行 该函数时应该多一个数。谁能帮帮我?
您的代码有几个问题。由于这是家庭作业,我不会提供正确的代码,但我会帮助突出显示您出错的地方,以帮助您更接近。我没有提供答案的唯一原因是因为这些都是很好的学习经历。如果您对更新的尝试发表评论,我会继续更新我的答案来指导您。
问题是您使用的是 for (i in X)
,它实际上会遍历 X
的值而不是它的索引。因此,在您的示例中,i
将等于 5,然后是 2,然后是 9,然后是 4,然后是 8。如果我们从 i == 5 开始,代码就是这样做的:X.val <- X[5] - X[5 - 1]
。此时您将 X.val
指定为 4,因为 X[5]
等于 8 而 X[4]
等于 4。在下一次迭代中,i == 2。所以这将设置X.val
到 -3 因为 X[2]
是 2 而 X[1]
是 5.
要解决此问题,您需要循环遍历 X
的索引。您可以使用 for (i in 1:length(X))
来完成此操作,其中 length(X)
将为您提供一个等于 X
中元素数量的数字。
您发现的下一个问题是您获得了一个额外的号码。重要的是要考虑输出中应该有多少数字,以及这对 i
应该从哪里开始意味着什么。提示:你真的应该从 1 开始吗?
最后,您在每次迭代中覆盖 X.val
。令我惊讶的是,你在结果中得到了一个额外的数字,因为你应该只收到 NA
,因为最后一个数字是 8 而 X
中没有 8 个元素。然而,您需要重写代码,这样您就不会覆盖 X.val
,而是在每次迭代时附加到它。
希望对您有所帮助。
更新 #1
如以下评论所述,您的代码现在如下所示:
difference <- function(X) {
for (i in 2:length(X)) {
X[i] <- X[i] - X[i-1]
}
return(X)
}
difference(c(5, 2, 9, 4, 8))
我们现在非常非常接近最终解决方案。我们只需要快速解决一个问题。
问题是我们现在覆盖了 X 的值,这很糟糕。由于我们的数字 c(5,2,9,4,8)
作为变量 X
传递到函数中,行 X[i] <- X[i] - X[i-1]
将开始覆盖我们的值。因此,一次进行一次迭代,我们得到以下结果:
i
设置为 2X[2]
目前等于 2- 然后我们 运行 行
X[i] <- X[i] - X[i-1]
,它的计算如下:X[2] <- X[2] - X[1]
-->X[2] <- 2 - 5
-->X[2] <- -3
X[2]
现在设置为 -3
i
设置为 3X[3]
目前等于 9- 然后我们 运行
X[i] <- X[i] - X[i-1]
,它的计算方式如下:X[3] <- X[3] - X[2]
-->X[3] <- 9 - -3
-->X[3] <- 12
X[3]
现在设置为 12
正如您从前两次迭代中看到的那样,我们正在覆盖我们的 X
变量,这直接影响我们在 运行 函数时获得的差异。
为了解决这个问题,我们只需回到使用 X.val
,就像我们以前一样。因为这个变量没有值,所以没有什么可以被覆盖。我们的函数现在看起来像这样:
difference <- function(X) {
for (i in 2:length(X)) {
X.val[i] <- X[i] - X[i-1]
}
return(X.val)
}
现在,对于每次迭代,没有任何内容被覆盖,我们 X
的值保持不变。但是,我们将遇到两个问题。如果我们 运行 这个新代码,我们将得到一个错误,告诉我们 x.diff
不存在。早些时候,我告诉过您可以索引您正在创建的变量,这是事实。我们只需要先告诉 R 我们正在创建的变量是一个变量。有几种方法可以做到这一点,但第二个最好的方法是创建一个与我们预期输出具有相同 class
的变量。因为我们知道我们希望我们的输出是一个数字列表,所以我们可以让 X.val
成为一个 numeric
向量。我们的代码现在看起来像这样:
difference <- function(X) {
X.val <- numeric()
for (i in 2:length(X)) {
X.val[i] <- X[i] - X[i-1]
}
return(X.val)
}
注意 X.val
的赋值发生在我们进入 for
循环之前。作为练习,您应该考虑为什么会这样,然后尝试将它移到 for
循环中,看看会发生什么。
这样,就解决了我们的第一个问题。尝试 运行ning 代码,看看你得到了什么。您会注意到输出的第一个元素是 NA
。为什么会出现这种情况,我们该如何解决?提示:与i
.
更新#2
现在我们有了正确的答案,让我们看一下 R 提供的一些提示和技巧。R 有一些可以在向量上使用的固有特性。要查看此操作,运行 以下示例:
a <- 1:10
b <- 11:20
a + b
a - b
a * b
a / b
如您所见,R 会自动对向量执行所谓的 "element wise" 运算。您会注意到 a - b
与我们在这里尝试做的非常相似。区别在于 a
和 b
是两个不同的向量,我们一次处理一个向量。那么我们如何设置我们的问题来像这样工作呢?简单:我们创建两个向量。
x <- c(5, 2, 9, 4, 8)
y <- x[2:length(x)]
z <- x[1:(length(x)-1)]
y - z
你应该注意到 y - z
现在给了我们我们想要从函数中得到的答案。我们可以像这样将其应用于我们的 difference
函数:
difference <- function(X) {
y <- X[2:length(X)]
z <- X[1:(length(X)-1)]
return(y-z)
}
使用这个技巧,我们不再需要使用 for
循环,这在 R 中可能非常慢,而是使用向量化操作,这在 R 中非常快。如注释,我们实际上可以跳过将这些值分配给 y
和 z
的步骤,而是直接 return 我们想要的:
difference <- function(X) {
return(X[2:length(X)] - X[1:(length(X)-1)])
}
我们现在刚刚成功创建了一个单行函数来完成我们希望做的事情。让我们看看我们是否可以让它更干净。 R 有两个非常方便查看数据的函数:head()
和 tail()
。 head
允许您查看前 n 个元素,tail
允许您查看最后 n 个元素。让我们看一个例子。
a <- 1:50
head(a) # defaults to 6 elements
tail(a) # defaults to 6 elements
head(a, n=20) # we can change how many elements to return
tail(a, n=20)
head(a, n=-1) # returns all but the last element
tail(a, n=-1) # returns all but the first element
最后两个对于我们想要做的事情来说是最重要的。在我们最新版本的 difference
中,我们正在查看 X[2:length(X)]
,这是 "all elements in X
except the first element" 的另一种说法。我们还查看了 X[1:(length(X)-1)]
,这是 "all elements in X
except the last element" 的另一种说法。让我们清理一下:
difference <- function(X) {
return(tail(X, -1) - head(X, -1))
}
如您所见,这是定义我们函数的更简洁的方法。
这就是技巧。让我们看一些提示。第一个是从像这样的简单函数中删除 return
。如果函数不是赋值,R 将自动 return 最后一个命令。要查看实际效果,请尝试 运行 使用两个不同的函数:
difference_1 <- function(X) {
x.diff <- tail(X, -1) - head(X, -1)
}
difference_1(1:10)
difference_2 <- function(X) {
tail(X, -1) - head(X, -1)
}
difference_2(1:10)
在 difference_1
中,您会注意到 return 没有任何内容。这是因为该命令是赋值命令。您可以使用 return
命令将其强制为 return 一个值。
下一个提示是您暂时不需要的,但它很重要。回到我们拥有的 difference
的当前版本(您现在使用的代码,而不是我在本次更新中提到的任何内容),我们将值分配给 X.val
,这导致它 "grow"随着时间的推移。要查看这意味着什么,运行 下面的代码:
x.val <- numeric()
length(x)
x.val[1] <- 1
length(x)
x.val[2] <- 2
length(x)
你会看到长度在不断增长。这通常是 R 代码中 巨大 减速的一个点。正确的方法是创建 x.val
,其长度等于我们需要的长度。这要快得多,并且会在将来为您省去一些痛苦。它的工作原理如下:
difference <- function(X) {
x.val <- numeric(length=(length(X) - 1))
for (i in 2:length(X)) {
x.val[i-1] <- X[i] - X[i-1]
}
return(x.val)
}
在我们当前的代码中,这并没有真正的区别。但是,如果您将来要处理非常大的数据,这可能需要数小时甚至数天的计算时间。
我希望这一切能帮助您更好地理解 R 中的一些功能。祝一切顺利!