自定义函数,用于创建结果索引

时间:2011-01-19 11:41:12

标签: function r if-statement

3 个答案:

答案 0 :(得分:8)

你的代码看起来很奇怪,似乎你对R来自另一种编程语言有很多误解。 Gavin和Gillespie已经指出了为什么你得到了warniong。让我为更优化的编码添加一些技巧:

  • [ - 1]并不意味着:放弃最后一个。这意味着“保留除了第一个值之外的所有内容”,这也解释了为什么会出现错误结果。

  • 在开始时计算常见事物,以整理代码。

  • head(x$TradeResult.Currency., n = 1)x$TradeResult.Currency.[1]相同。

  • 密切关注你的向量。代码中的大多数错误都来自忘记你正在使用向量。

  • 如果您需要一个值作为向量中的第一个,请将您使用的任何循环的OUTSIDE置于其中,切勿在函数中添加if子句。

  • 预先定义您的矢量/矩阵,在处理大数据时速度更快,内存更少。

  • 矢量化,矢量化,矢量化。我是否提到矢量化

  • 了解如何使用debug()debugonce()browser()来检查您的功能正在做什么。您可以通过在函数内操作时检查对象来解决许多问题。

这说并考虑到了,你的功能变为:

CalculateIndex <- function(x,accountValueStart){
  # predifine your vector
  indexedValues <- vector("numeric",nrow(x))
  # get your totalAccount calculated FAST. This is a VECTOR!!!
  totalAccount <- cumsum(c(accountValueStart,x$TradeResult.Currency.))
  #adjust length:
  totalAccount <- totalAccount[-(nrow(x)+1)]

  # only once this calculation. This is a VECTOR!!!!
  totRatio <- 1+(((x$Size.Units. * x$EntryPrice)/totalAccount) *
                 x$TradeResult.Percent.)/100

  # and now the calculations
  indexedValues[1] <- 100 * totRatio[1]
  for(i in 2:nrow(x)){
      indexedValues[i] <- indexedValues[i-1]*totRatio[i]
  }
  return(indexedValues)
}

并返回

> CalculateIndex(theData,14000)
[1]  99.97901  99.92081  99.57714 101.46399 102.35708 101.28586 103.31497 
 103.80656 102.33612 104.35856 102.79509 103.56012
[13] 102.90879 103.67281 104.85296 104.60432 102.50553 102.90490 102.71800 
 104.06766

现在你做了:

 invisible(replicate(10,print("I will never forget about vectorization any more!")))

答案 1 :(得分:4)

警告信息来自这一行:

if(x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)){

很容易理解为什么; x$TradeResult.Currency向量,因此与head(x$TradeResult.Currency., n = 1)的比较会产生逻辑的向量。 (顺便说一句,为什么不x$TradeResult.Currency[1]而不是head()来电?)。 if()需要单个逻辑而不是逻辑向量,这就是警告的内容。如果你想根据给出逻辑向量的条件做两件事之一,ifelse()很有用。

实际上,你所做的只是输入语句的if()部分而且只执行一次,因为x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)的第一个元素是TRUE而R忽略了其他

> if(c(TRUE, FALSE)) {
+ print("Hi")
+ } else {
+ print("Bye")
+ }
[1] "Hi"
Warning message:
In if (c(TRUE, FALSE)) { :
  the condition has length > 1 and only the first element will be used
> ifelse(c(TRUE, FALSE), print("Hi"), print("Bye"))
[1] "Hi"
[1] "Bye"
[1] "Hi"  "Bye"

至于解决你的真实问题:

CalculateIndex2 <- function(x, value, start = 100) {
    rowSeq <- seq_len(NROW(x))
    totalAc <- cumsum(c(value, x$TradeResult.Currency.))[rowSeq]
    idx <- numeric(length = nrow(x))
    interm <- (((x$Size.Units. * x$EntryPrice) / totalAc) *
               x$TradeResult.Percent.) / 100
    for(i in rowSeq) {
        idx[i] <- start + (start * interm[i])
        start <- idx[i]
    }
    idx
}

theData上使用时给出:

> CalculateIndex2(theData, 14000)
 [1]  99.97901  99.92081  99.57714 101.46399 102.35708 101.28586 103.31497
 [8] 103.80656 102.33612 104.35856 102.79509 103.56012 102.90879 103.67281
[15] 104.85296 104.60432 102.50553 102.90490 102.71800 104.06766

你想要的是一个递归函数(IIRC);当前索引是前一个索引的一些功能。这些很难用R中的矢量化方式解决,因此就是循环。

答案 2 :(得分:2)

我仍然对你究竟想做什么感到困惑,但希望以下内容会有所帮助。

您的R脚本为第一个值提供与Excel函数相同的答案。你看到了一个区别,因为R没有打印出所有数字。

> tmp = CalculateIndex(thedata)
Warning message:
In if (x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)) { :
  the condition has length > 1 and only the first element will be used
> print(tmp, digits=10)
 [1]  99.97900857  99.94180357  99.65632286 101.88688500 100.89308643
 <snip>

警告消息的原因是因为x$TradeResult.Currency是与单个数字进行比较的向量。

该警告信息也是您的错误所在。在if语句中,从不执行else部分,因为只使用x$TradeResult.Currency的值。如警告消息所述,仅使用x$TradeResult.Currency的第一个元素。