所以我有一个作业问题,我真的很难在R中编写代码。
这是问题所在:编写一个函数difference()
,该函数将向量X作为参数并返回该向量的向量。
每个元素和下一个元素之间的区别:X[2]-X[1], X[3]-X[2], X[4]-X[3]
等
因此difference(c(5,2,9,4,8))
将返回c(-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]
的函数,并且返回的数字比运行该函数时多。谁能帮我?
最佳答案
您的代码有几个问题。由于这是家庭作业,因此我将不提供正确的代码,但是我将帮助您突出显示您出了错的地方,以帮助您更进一步。我没有提供答案的唯一原因是因为这些都是很好的学习经验。如果您用更新的尝试发表评论,我将继续更新答案以指导您。
问题是您使用的是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
。令您惊讶的是,由于最后一个数字是8,而NA
中没有8个元素,因此您应该只收到X
,结果中又得到了一个额外的数字。但是,您将需要重写代码,以免覆盖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
设置为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第2步:
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
循环内并查看会发生什么。因此,这解决了我们的第一个问题。尝试运行代码,看看会得到什么。您会注意到输出的第一个元素是
NA
。为什么会这样,我们如何解决呢?提示:与i
的值有关。更新#2
因此,现在我们有了正确的答案,让我们看一下由于R而可用的一些技巧和窍门。R具有可用于矢量的一些固有功能。要查看此操作,请运行以下示例:
a <- 1:10
b <- 11:20
a + b
a - b
a * b
a / b
如您所见,R将自动对向量执行所谓的“元素明智”运算。您会注意到,
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
的步骤,而可以直接返回我们想要的内容: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)]
,这是另一种说法:“ X
中的所有元素,除第一个元素外”。我们还查看了X[1:(length(X)-1)]
,这是“除了最后一个元素之外,X
中的所有元素”的另一种说法。让我们清理一下:difference <- function(X) {
return(tail(X, -1) - head(X, -1))
}
如您所见,这是定义函数的一种更简洁的方法。
因此,这些就是窍门。让我们看一些技巧。首先是从这样的简单函数中删除
return
。如果不是函数,R将自动返回最后一个命令。要查看实际效果,请尝试运行两个不同的功能: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
命令强制其返回值。下一个技巧是您暂时不需要的东西,但这很重要。回到当前的
difference
版本(您正在使用的代码,而不是我在此更新中提到的任何内容),我们为X.val
分配值,这会导致它随着时间的推移“增长” 。要了解这意味着什么,请运行以下代码: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 - 努力创建差异函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36509821/