Nat*_*lie 4 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))
Run Code Online (Sandbox Code Playgroud)
我似乎无法让函数减去它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.在下一迭代中,我== 2.因此,这将设置X.val为-3,因为X[2]是2和X[1]5.
要解决此问题,您需要循环索引X.你可以通过使用for (i in 1:length(X))where length(X)来给你一个等于中的元素数量的数字X.
你发现的下一个问题是你得到一个额外的号码.重要的是要考虑输出中应该有多少数字,以及这i应该从哪里开始.提示:你真的应该从1开始吗?
最后,X.val在每次迭代中覆盖.令我感到惊讶的是,你在结果中得到了一个额外的数字,因为你应该只收到NA最后一个数字是8并且没有8个元素X.不过,您需要重写代码,以便不覆盖X.val,而是在每次迭代时附加代码.
我希望有所帮助.
如下面的评论中所述,您的代码现在看起来像这样:
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))
Run Code Online (Sandbox Code Playgroud)
我们现在非常非常接近最终解决方案.我们只需解决一个快速问题.
问题是我们现在凌驾于X的价值上面,这很糟糕.由于我们的数字c(5,2,9,4,8)作为变量传递给函数X,因此该行将X[i] <- X[i] - X[i-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 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)
}
Run Code Online (Sandbox Code Playgroud)
现在,对于每次迭代,没有任何东西被覆盖,我们的价值观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)
}
Run Code Online (Sandbox Code Playgroud)
请注意,X.val在我们进入for循环之前发生了分配.作为练习,您应该考虑为什么会这样,然后尝试将其移动到for循环内部并查看会发生什么.
所以这,解决了我们的第一个问题.尝试运行代码,看看你得到了什么.您会注意到输出的第一个元素是NA.为什么会出现这种情况,我们该如何解决?提示:它与价值有关i.
所以现在我们有了正确的答案,让我们看一下可用的一些提示和技巧,这要归功于R.R有一些固有的功能可以用在矢量上.要查看此操作,请运行以下示例:
a <- 1:10
b <- 11:20
a + b
a - b
a * b
a / b
Run Code Online (Sandbox Code Playgroud)
如您所见,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
Run Code Online (Sandbox Code Playgroud)
你应该注意到,y - z现在我们从函数中得到了我们想要的答案.我们可以将它应用于我们的difference函数,如下所示:
difference <- function(X) {
y <- X[2:length(X)]
z <- X[1:(length(X)-1)]
return(y-z)
}
Run Code Online (Sandbox Code Playgroud)
使用这个技巧,我们不再需要使用for循环,这在R中可能非常慢,而是使用向量化操作,这在R中非常快.正如评论中所述,我们实际上可以跳过赋值的步骤那些价值观y和z而且可以直接返回我们想要的东西:
difference <- function(X) {
return(X[2:length(X)] - X[1:(length(X)-1)])
}
Run Code Online (Sandbox Code Playgroud)
我们现在刚刚成功创建了一个完成我们希望做的单行函数.让我们看看我们是否能让它更清洁.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
Run Code Online (Sandbox Code Playgroud)
最后两个对我们想做的事情来说是最重要的.在我们difference看到的最新版本中X[2:length(X)],这是另一种说法" X除了第一个元素之外的所有元素".我们也在看X[1:(length(X)-1)],这是另一种说" X除最后一个元素之外的所有元素"的方式.让我们清理一下:
difference <- function(X) {
return(tail(X, -1) - head(X, -1))
}
Run Code Online (Sandbox Code Playgroud)
如您所见,这是一种更清晰的定义功能的方式.
所以这些都是技巧.我们来看几个提示.首先是放弃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)
Run Code Online (Sandbox Code Playgroud)
在difference_1你会发现没有任何回报.这是因为该命令是一个赋值命令.您可以使用该return命令强制它返回值.
下一个提示是你暂时不需要的东西,但它很重要.让我们回到当前版本difference,我们有(代码你使用现在,没有什么我已经在本次更新中提到),我们分配值X.val,这会导致它"长大"随着时间的推移.要查看这意味着什么,请运行以下代码:
x.val <- numeric()
length(x)
x.val[1] <- 1
length(x)
x.val[2] <- 2
length(x)
Run Code Online (Sandbox Code Playgroud)
你会看到长度不断增长.这通常是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)
}
Run Code Online (Sandbox Code Playgroud)
在我们当前的代码中,这并没有真正的区别.但是,如果您将来处理非常大的数据,这可能需要数小时甚至数天的计算时间.
我希望这一切都能帮助你更好地理解R中的一些功能.祝你好运!
| 归档时间: |
|
| 查看次数: |
100 次 |
| 最近记录: |