如何计算一个公式,该公式采用名称中具有相同后缀的数据框的不同列并创建一个新列?

时间:2021-01-28 10:37:28

标签: r dataframe

我在 R 中有一个数据框,其中包含以下列结构(规模更大):

  Material_code  actual_202009  actual_202010  actual_202011  pred_202009  pred_202010  pred_202011  
      111              30              44              24            25           52           27
      112              19              70              93            23           68           100

我想向包含相应错误度量的数据帧添加新列:

|actual - pred|/ actual * 100%

获得:

Material_code  actual_202009  actual_202010  actual_202011  pred_202009  pred_202010  pred_202011 MAPE_202009 MAPE_202010 MAPE_202011
      111              30              44              24            25           52          27     16.67%      18.18%       12.5%
      112              19              70              93            23           68          100    21.05%       2.86%        7.52%

我尝试使用 ends_with() 创建新列以选择上一列,但我没有做对。你能帮忙吗?

*** 编辑以包含更简单的方法来生成数据框

df <- data.frame(Material_code = c(111,112),
                    actual_202009 = c(30,19),
                    actual_202010 = c(44,70),
                    actual_202011 = c(24,93), 
                    pred_202009 = c(25,23),
                    pred_202010 = c(52,68),
                    pred_202011 = c(27,100))

3 个答案:

答案 0 :(得分:1)

来自 tidyverse 的更详细:

library(tidyverse)
df %>%
  pivot_longer(cols = -Material_code) %>%
  separate(name, into = c("type", "time"), sep = "_") %>%
  pivot_wider(names_from = type) %>%
  mutate(MAPE = abs(actual - pred)/actual*100) %>%
  pivot_wider(values_from = c(actual, pred, MAPE),
              names_from = time)

给出:

# A tibble: 2 x 10
  Material_code actual_202009 actual_202010 actual_202011 pred_202009 pred_202010 pred_202011 MAPE_202009 MAPE_202010 MAPE_202011
          <int>         <int>         <int>         <int>       <int>       <int>       <int>       <dbl>       <dbl>       <dbl>
1           111            30            44            24          25          52          27        16.7       18.2        12.5 
2           112            19            70            93          23          68         100        21.1        2.86        7.53

答案 1 :(得分:1)

如果您尝试以长格式保存数据,将会对自己有很大帮助:每列都有相同类型的数据。 你的表格是宽格式,对于excel和人类可视化非常有用,但在代码中处理起来非常麻烦。

所以您需要做的第一件事(这就是@deschen 在他们的回答中所做的)是将您的数据转换为 long,然后对其进行操作。您的数据的长版本将采用以下形式

Material_code    Type    Date   Value
          111  actual  202011      30

我将提供一个 data.table 解决方案,它与@deschen 的基本相同。您可能会喜欢它,因为它处理大数据的速度很快。

library(data.table)

setDT(df1)

df1[, melt(.SD, 1)][, 
               c("type", "date") := tstrsplit(variable, "_", fixed = TRUE)][,
                     dcast(.SD, Material_code + date ~ type)][, 
                         mape := 100 * abs(actual - pred) / actual][]
  • melt(.SD, 1) 将您的表格从宽转换为长,只保留第一列作为每条记录的参考。
  • c("type", "date") := tstrsplit(variable, "_", fixed = TRUE) 使用取自 variable 的相应值创建列类型和日期(在 melt 之后,variable 具有以前的列名称)。
  • dcast(.SD, Material_code + date ~ type) 再次将长表转换为宽表。这一次,Material_codedate 将保留在列中,而 type 将被转换为新列 actualpred
  • := 是赋值运算符。它创建变量 mape 并分配结果值。
  • 最后一点,[] 实际上并不需要。有没有所以结果打印到屏幕上。如果您不需要将新表格打印到屏幕上,请忽略它。

答案 2 :(得分:0)

获取所有'actual''pred'列的列名,您可以直接对其进行所有数学计算。

actual_cols <- sort(grep('actual', names(df), value = TRUE))
pred_cols <- sort(grep('pred', names(df), value = TRUE))
new_cols <- sub('pred', 'MAPE', pred_cols)

df[new_cols] <- abs(df[actual_cols] - df[pred_cols])/df[actual_cols] * 100
df

#  Material_code actual_202009 actual_202010 actual_202011 pred_202009
#1           111            30            44            24          25
#2           112            19            70            93          23

#  pred_202010 pred_202011 MAPE_202009 MAPE_202010 MAPE_202011
#1          52          27        16.7       18.18       12.50
#2          68         100        21.1        2.86        7.53

数据

df <- structure(list(Material_code = 111:112, actual_202009 = c(30L, 
19L), actual_202010 = c(44L, 70L), actual_202011 = c(24L, 93L
), pred_202009 = c(25L, 23L), pred_202010 = c(52L, 68L), pred_202011 = c(27L, 
100L)), class = "data.frame", row.names = c(NA, -2L))
相关问题