【问题标题】:Can this R function for calculating a Z-normalization without look-ahead bias be simplified?可以简化用于计算没有前瞻偏差的 Z 归一化的 R 函数吗?
【发布时间】:2021-01-11 11:19:11
【问题描述】:

我是 R 新手,我面临一些初学者问题:

我有向量 ts,它是货币对的每日比率。我现在想计算 z 归一化(?)。 R 中的函数看起来像这样:

znorm <- function(ts){
        ts.mean <- mean(ts)
        ts.dev <- sd(ts)
        (ts - ts.mean)/ts.dev
    }

我可以用它来得到这样的向量:

tsResult <- znorm(ts)

这是我真正不明白的第一件事:该函数似乎没有返回任何内容,而是通过一次操作给定的 ts 创建了一个新向量。如果有人可以额外解释这一点或向我指出很棒的资源。

无论如何,我的主要问题如下:返回的结果包含一些前瞻偏差,所以我创建了自己的 zNorm 函数(它返回一个二维数据框),带有一个窗口参数:

znormNew <- function(ts, window) {
        i = as.integer(0)
        df = data.frame(Count=integer(), RatioN=double())
        
        for(val in ts)
        {
            ratioN = as.integer(0)
            i = i + 1
            if(i >= window) {
                tsnew = ts[(i-window + 1):i]
                mean <- mean(tsnew)
                dev <- sd(tsnew)
                ratioN = (tail(tsnew, n=1) - mean)/dev
                #print(ratioN)
            }
            
            #print(cat(i , " -- " , ratioN))
            df[nrow(df) + 1,] = c(i, ratioN)
        }
        
        return (df)
    }

我费了很大劲才解决这个问题,但我认为从逻辑的角度来看这是正确的。

但我认为这可以通过一些更深入的 R 知识来简化很多。我尝试将 mutate 与 row_number 函数一起使用以使其成为单行,但这不起作用,因为 mutate 中的 row_number 似乎是一个向量(而不是我假设相应的单个 row_number 行是一个索引)。

【问题讨论】:

    标签: r


    【解决方案1】:

    对于您的第一个问题,没有显式 return 语句的函数将返回最后一个操作,即 znorm 中的 (ts - ts.mean)/ts.dev

    如果我正确理解了您的逻辑,则使用第二个函数,对于您想要获取该行的 zscore 与某个回溯期的每一行。 zoo 包有一个rollapply 函数。注意:传递给rollapplyscale 函数是base R 的znorm 等价物。这还将返回回溯期内每一行的 zscore,因此[, window] 确保只选择最后一行。

    library(zoo)
    
    ts <- data.frame(date = as.Date('2020-01-01') + seq(1, 20),
                     value = runif(20, min=0, max=10))
    window <- 7
    ts$zscore <- 0
    
    ts$zscore[window:nrow(ts)] <- rollapply(ts$value, window, by = 1, scale)[, window]
    ts
    
    
             date     value     zscore
    1  2020-01-02 9.0507883  0.0000000
    2  2020-01-03 2.6528930  0.0000000
    3  2020-01-04 5.5656708  0.0000000
    4  2020-01-05 6.9355550  0.0000000
    5  2020-01-06 6.2717404  0.0000000
    6  2020-01-07 9.2230508  0.0000000
    7  2020-01-08 3.6954983 -1.0073333
    8  2020-01-09 8.3742060  0.9598646
    9  2020-01-10 1.5648625 -1.6539315
    10 2020-01-11 7.4289812  0.4505279
    11 2020-01-12 7.5813476  0.4659747
    12 2020-01-13 3.6039318 -0.7940229
    13 2020-01-14 1.9399534 -1.0337345
    14 2020-01-15 6.9610210  0.5576006
    15 2020-01-16 1.1036055 -1.0962716
    16 2020-01-17 3.3193377 -0.4570875
    17 2020-01-18 6.0283668  0.6615867
    18 2020-01-19 6.9119067  1.1092511
    19 2020-01-20 0.7370787 -1.1398406
    20 2020-01-21 4.9342164  0.2478307
    

    【讨论】:

      【解决方案2】:

      我尝试使用“矩阵”和“应用”功能来完成这项任务。 据我所知,使用矩阵运算应该比循环更快。

      znormNew <- function(ts, window) {
      m<-matrix(c(rep(ts,length(ts)),rep(0,length(ts))),ncol=length(ts)+1,byrow=TRUE)
      d<-m[(1:length(ts))<=(length(ts)-window)+1,][,1:window]
      mean_ts<-apply(d,1,mean)
      mean_sd<-apply(d,1,sd)
      RatioN<-(d[,window]-mean_ts)/mean_sd
      data.frame(window:length(ts), RatioN)
      }
      

      【讨论】:

        猜你喜欢
        • 2016-10-12
        • 2021-09-04
        • 2016-03-29
        • 2015-12-17
        • 2016-10-11
        • 2011-09-09
        • 2016-07-28
        • 1970-01-01
        • 2015-04-18
        相关资源
        最近更新 更多