r - 努力创建差异函数

标签 r function difference

所以我有一个作业问题,我真的很难在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设置为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循环内并查看会发生什么。

因此,这解决了我们的第一个问题。尝试运行代码,看看会得到什么。您会注意到输出的第一个元素是NA。为什么会这样,我们如何解决呢?提示:与i的值有关。

更新#2

因此,现在我们有了正确的答案,让我们看一下由于R而可用的一些技巧和窍门。R具有可用于矢量的一些固有功能。要查看此操作,请运行以下示例:

a <- 1:10
b <- 11:20
a + b
a - b
a * b
a / b


如您所见,R将自动对向量执行所谓的“元素明智”运算。您会注意到,a - b与我们在此处尝试做的非常相似。区别在于ab是两个不同的向量,我们一次只处理一个向量。那么,我们如何设置问题来像这样工作?简单:我们创建两个向量。

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中非常快)。正如注释中所述,我们实际上可以跳过将这些值分配给yz的步骤,而可以直接返回我们想要的内容:

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/

相关文章:

在 Web 浏览器中运行 RStudio 的多个实例

c - 我可以改变指针的功能吗?

c# - 在for循环C#中使用括号和不使用括号的区别

Mysql 计算系统宕机记录的上一次结束时间和当前开始时间之间的分钟数

r - 如何从 Ecdf() 返回值中提取 Ecdf 值?

r - 我们可以为rmarkdown中yaml header 中的biblio-style参数设置哪些选择?

r - R 中的缩放矩阵,使 X %*% t(X) 的对角线元素仅为 1

python - 将 +1 添加到函数内的变量

r - Mutate_if 语法帮助 - 如何在谓词条件下添加函数参数

Java如何以秒为单位获取currentMillis和过去时间戳之间的差异