【问题标题】:Calculate errors from two data matrices using loops使用循环计算两个数据矩阵的误差
【发布时间】:2021-09-19 23:51:15
【问题描述】:

我有两个相同维度的数据矩阵,让一个矩阵用A表示,另一个用B表示,维度为24*365 其中 24 表示小时,365 表示天数(意味着每个矩阵具有一年的每小时数据)。假设我选择一天,例如星期日,假设它位于两个矩阵的第三列。同样,我从两个矩阵中选择星期日的所有剩余列,因此我从星期日的每个矩阵 AB 中获得两个子矩阵。然后我将每个子矩阵作为一个向量,并从这两个向量中计算均方误差和均方误差百分比。类似地,对于一周中的剩余几天重复相同的过程。我的问题是,任何人都可以使用循环来完成整个过程,即从矩阵 AB 中选择每天子矩阵的循环。然后将每个子矩阵作为一个向量,分别计算每天的均方误差和均方误差百分比。 我尝试以采用 CD 表示的任意两个矩阵的示例手动解释我的问题,但由于我的原始数据矩阵的维数很大,因此还有更多子矩阵,这使得我们手动执行此操作非常耗时。

C <- matrix(16:155, ncol=14, byrow=T)
D<- matrix(50:189,ncol=14, byrow=T)
sub_C1 <- C[,c(1+(0:6)*2)]
sub_D1 <- D[,c(1+(0:6)*2)]
sub_C2 <-  C[,c(2+(0:6)*2)]
sub_D2 <-  D[,c(2+(0:6)*2)]
sub_C3 <-  C[,c(1+(0:4)*3)]
sub_D3 <-  D[,c(1+(0:4)*3)]
################mean square error################
mse_1 <- mean(abs(as.vector(sub_C1)-as.vector(sub_D1)))
mse_2 <- mean(abs(as.vector(sub_C2)-as.vector(sub_D2)))
mse_3 <- mean(abs(as.vector(sub_C3)-as.vector(sub_D3)))
################## mean percentage absolute error############
mape_1 <- mean(abs(as.vector(sub_C1)-as.vector(sub_D1))/as.vector(sub_C1))
mape_2 <- mean(abs(as.vector(sub_C2)-as.vector(sub_D2))/as.vector(sub_C2))
mape_3 <- mean(abs(as.vector(sub_C3)-as.vector(sub_D3))/as.vector(sub_C3))
#############################################################

有人可以通过循环从每个矩阵CD中选择相同的子矩阵,并分别计算每个子矩阵的误差吗?

【问题讨论】:

    标签: r loops iteration partitioning


    【解决方案1】:

    由于许多自称作者/开发者经常说as R is vectorised, loops in R are mostly avoidable。这里也不需要使用循环。还有一件事——+- 等二元运算已经向量化,因此您无需将矩阵显式转换为向量 as.vector

    我认为您可以使用purrr::map_df,如下所述,它将为您提供一个类似数据框结构的所有 7 天。然而,第一行将对应于一年中的第一天(矩阵)。

    策略解释 -

    • 将所需的n 存储在变量n 中。在这里你想要7 分区,所以我存储了n &lt;- 7
    • 生成一个从 0 到 n-1 的序列所以我使用了 seq(n) - 1 作为第一个参数。
    • 现在对列号%% 使用模除以在每次迭代中获取每个nth 行。例如8 %% 7 提供 1 并且类似地 15 %% 7 也提供 1 所以每个 7th 行将进入各自的分区。
    • 对于分区,我们分别对CD 使用C[, seq(ncol(C)) %% n == .x] 表达式/公式。 .xmap 函数中的第一个参数。这将生成 7 个分区。
    • 检查一下
    C[, seq(ncol(C)) %% 7 == 2]
         [,1] [,2]
     [1,]   17   24
     [2,]   31   38
     [3,]   45   52
     [4,]   59   66
     [5,]   73   80
     [6,]   87   94
     [7,]  101  108
     [8,]  115  122
     [9,]  129  136
    [10,]  143  150
    
    • 您会注意到第 2 行和第 8 行已按该表达式进行了分区。
    • 将这些中间分区存储在临时变量中(在 {} 内)x1x2(每个矩阵一个)
    • 在另外两个中间变量中,y1y2 根据给定公式计算 msemape(此处使用 x1 和 x2)
    • 由于我们生成数据帧作为输出,我们需要在这里setNames,最后在{}

    我希望语法现在很清楚了。

    library(tidyverse)
    
    C <- matrix(16:155, ncol=14, byrow=T)
    D <- matrix(50:189,ncol=14, byrow=T)
    
    #number of partitions you desire
    n <- 7 # every 7th column
    
    purrr::map_df(seq(n) - 1, ~{x1 <- C[, seq(ncol(C)) %% n == .x]; x2 <- D[, seq(ncol(D)) %% n == .x];
    y1 <- mean(abs(x1 - x2)); y2 <- mean(abs(x1 - x2)/x1); 
    setNames(c(.x+1, y1, y2), c('day', 'mse', 'mape'))})
    
    #> # A tibble: 7 x 3
    #>     day   mse  mape
    #>   <dbl> <dbl> <dbl>
    #> 1     1    34 0.520
    #> 2     2    34 0.604
    #> 3     3    34 0.588
    #> 4     4    34 0.572
    #> 5     5    34 0.558
    #> 6     6    34 0.545
    #> 7     7    34 0.532
    

    但是,如果您只想使用 baseR,您可以将以下列表作为输出,其中包含七个元素,每天 1 个。语法解释。

    • 策略与purrr再次相似。这里公式和输入向量参数已经交换了位置(根据这些函数的设计)。
    • 由于我们生成列表作为输出,因此我们将在 {} 之外使用 `setNames(),即函数/公式参数。
    C <- matrix(16:155, ncol=14, byrow=T)
    D <- matrix(50:189,ncol=14, byrow=T)
    
    #number of partitions you desire
    n <- 7 # every 7th column
    
    Map(\(.x) {x1 <- C[, seq(ncol(C)) %% n == .x]; x2 <- D[, seq(ncol(D)) %% n == .x];
    y1 <- mean(abs(x1 - x2)); y2 <- mean(abs(x1 - x2)/x1); 
    setNames(c( y1, y2), c('mse', 'mape'))}, seq(n) - 1) |> setNames(paste0('Day', seq(n)))
    
    #> $Day1
    #>        mse       mape 
    #> 34.0000000  0.5202581 
    #> 
    #> $Day2
    #>        mse       mape 
    #> 34.0000000  0.6044914 
    #> 
    #> $Day3
    #>        mse       mape 
    #> 34.0000000  0.5878023 
    #> 
    #> $Day4
    #>      mse     mape 
    #> 34.00000  0.57236 
    #> 
    #> $Day5
    #>        mse       mape 
    #> 34.0000000  0.5580051 
    #> 
    #> $Day6
    #>        mse       mape 
    #> 34.0000000  0.5446064 
    #> 
    #> $Day7
    #>        mse       mape 
    #> 34.0000000  0.5320546
    

    请注意 - 作为1 %% 7 = 1 (and not 0),第二列将被视为第 1 天,第七列将被视为第 1 天,第一列将被视为第 7 天

    【讨论】:

    • 谢谢,AnilGoyal 的回复,我有一个简单的问题要理解,正如我在代码中提到的,每个子矩阵是通过不同的系列选择的,例如,星期一子矩阵是由一个不同的系列选择的其他日子,所以请帮助我在你的代码中输入不同的系列。
    • 正如我在代码中提到的,我有两个相同维度的矩阵,数据矩阵的每一列代表一天,我想计算一周中每一天的误差。例如对于星期日,假设它在两个矩阵的第 3 列,所以我以子矩阵的形式从两个矩阵中提取所有剩余的星期日,然后将两个子矩阵作为向量并计算 mse地图。同样,我们以同样的方式处理一周中的其余日子。
    • 知道我的问题是通过循环从两个矩阵中选择每天的子矩阵并分别计算每天的误差。然后在同一循环中重复一周中的其他日子的过程。通过计算误差。
    • 是的,您已经完成了与我的问题密切相关的出色工作,但我对您的代码有一个简单的问题,即它将如何为一周中的不同日子选择不同的子矩阵,这意味着我做了什么改变在您的代码中用于不同的子矩阵。
    • @user243550,我已经编辑了我的答案以包含完整的策略。我使用%%modulo division 收集每第n 列。每隔 n 行分区一次。如果它达到目的,请接受它和upvote。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-25
    • 2011-11-25
    • 2016-10-31
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多