【问题标题】:Perform MAD calculation on two different columns of a dataframe in R对 R 中数据帧的两个不同列执行 MAD 计算
【发布时间】:2021-08-04 18:21:28
【问题描述】:

样本数据

date = seq(as.Date("2019/01/01"), by = "month", length.out = 48)
subproduct=rep("x",48)
actuals <- c(seq(1:29),rep(0,19))
m1 <- c(rep(0,24),seq(1:24))
m2<- c(rep(0,24),rep(10,24))
dfone <- data.frame(date,
                subproduct,
                actuals,m1,m2)

      date subproduct actuals m1 m2

这里是 dfone 的第 24-30 行

 date           subproduct  actuals m1 m2
24 2020-12-01          x      24  0  0
25 2021-01-01          x      25  1 10
26 2021-02-01          x      26  2 10
27 2021-03-01          x      27  3 10
28 2021-04-01          x      28  4 10
29 2021-05-01          x      29  5 10
30 2021-06-01          x       0  6 10

我想要做的是将此公式应用于所有三列中数字不为 0 的行(第 25-29 行)我想在第 25 行取实际值

m1abs1 <- abs(25-1)
m1abs2<- abs(26-2)
m1abs3 <- abs(27-3)
m1abs4 <- abs(28-4)
m1abs5 <- abs(29-5)

m1MAD <- sum(m1abs1,m1abs2,m1abs3,m1abs4,m1abs5)/5
# 24

m2abs1 <- abs(25-10)
m2abs2<- abs(26-10)
m2abs3 <- abs(27-10)
m2abs4 <- abs(28-10)
m2abs5 <- abs(29-10)

m2MAD <- sum(m2abs1,m2abs2,m2abs3,m2abs4,m2abs5)/5
# 17

max(m1MAD,m2MAD)

现在我们有了最大值,从数据框中删除不是最大值的列,在这种情况下是 m2MAD。

问题:有没有办法在 R 中更轻松地做到这一点?

【问题讨论】:

    标签: r data-manipulation


    【解决方案1】:

    我们可以使用if_allfilter 那些列中没有零的行,然后summarise 返回meanmeanmaxabsolute 偏差

    library(dplyr)
    dfone %>% 
        filter(if_all(actuals:m2, ~ . != 0)) %>% 
        summarise(MADmax = max(mean(abs(actuals - m1)), 
              mean(abs(actuals - m2))))
    

    -输出

       MADmax
    1     24
    

    如果我们要删除不是max的列

    dfone %>% 
         filter(if_all(actuals:m2, ~ . != 0)) %>% 
         summarise(nm1 = c('m1', 'm2')[which.max(c(mean(abs(actuals - m1)), 
               mean(abs(actuals - m2))))]) %>%
          pull(nm1) %>% setdiff(names(dfone), .) -> tmp
    dftwo <- dfone %>%
        select(all_of(tmp))
    

    或者另一种选择是

    library(tidyr)
    library(magrittr)
    dfone %>% 
       filter(if_all(c(actuals, matches('^m\\d+')), ~ . != 0))  %>% 
       summarise(across(matches('^m\\d+'), ~ mean(abs(actuals - .)))) %>% 
       pivot_longer(everything()) %>%
       filter(value != max(value)) %$% 
       select(dfone, -all_of(name)) 
    

    或者使用base RsubsetrowSums 来创建一个子集的逻辑向量并获得'MAD'的max

    with(subset(dfone, !rowSums(dfone[c('actuals', 'm1', 'm2')] == 0)), 
           max(mean(abs(actuals - m1)), 
               mean(abs(actuals - m2))))
    [1] 24
    

    【讨论】:

    • @chriswang123456 我更新了问题的第二部分,即删除那些不是最大的
    • @chriswang123456 使用pivot_longer 的解决方案会自动执行此操作,即您可以将actuals:m2 更改为if_all(c(actuals, matches('^m\\d+$'))
    • @chriswang123456 针对 m1 到 m100 的情况进行了更新。关于第二种情况,如果您想单独进行,请将匹配项更改为 matches('^c\\d+$')
    • 是的,这很完美。谢谢你,一如既往的天才!
    • @chriswang123456 然后您可以将正则表达式更改为matches('^m\\d+_\\w+$')^m\\d+_[a-z]+$
    猜你喜欢
    • 2021-07-15
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    相关资源
    最近更新 更多