【问题标题】:How to apply a custom function to nested dataframes?如何将自定义函数应用于嵌套数据框?
【发布时间】:2020-06-01 14:53:18
【问题描述】:

我正在尝试将自定义函数应用于嵌套数据框

我想应用机器学习算法来预测 NA 值

上网查了一下,好像地图功能在这里最适用

我有一段代码嵌套数据框,然后将数据拆分为测试 (data3) 和训练 (data2) 集 - 测试数据集包含要预测的列的所有空值,而训练包含用于训练 ML 模型的所有非 null 值

dmaExtendedDataNA2 <- dmaExtendedDataNA %>%
                  group_by(dma) %>%
                  nest() %>%
                  mutate(data2 = map(data, ~filter(., !(is.na(mean_night_flow)))),
                         data3 = map(data, ~filter(., is.na(mean_night_flow))))

这是我打算使用的功能:

    my_function (test,train) {
             et  <- extraTrees(x = train, y = train[, "mean_night_flow"], na.action = "fuse", ntree = 1000, nodesize = 2, mtry = ncol(train) * 0.9 )
             test1 <- test
             test1[ , "mean_night_flow"] <- 0
             pred  <- predict(et, newdata = test1[, "mean_night_flow"])
             test1[ , "mean_night_flow"] <- pred
             return(test1)

我尝试了以下代码,但它不起作用:

dmaExtendedDataNA2 <- dmaExtendedDataNA %>%
                      group_by(dma) %>%
                      nest() %>%
                      mutate(data2 = map(data, ~filter(., !(is.na(mean_night_flow)))),
                             data3 = map(data, ~filter(., is.na(mean_night_flow))),
                             data4 = map(data3, data2, ~my_function(.x,.y)))

它给出了以下错误:

Error: Index 1 must have length 1, not 33

这表明它需要一列而不是整个数据框。我怎样才能让它工作?

非常感谢

【问题讨论】:

  • 您好 MGJ,如果您至少提供数据样本dput(dmaExtendedDataNA)dput(dmaExtendedDataNA[1:20,]) 会更容易提供帮助。您可以编辑您的问题并粘贴输出。您可以用三个反引号 (```) 将其括起来以获得更好的格式。请参阅How to make a reproducible example 了解更多信息。
  • lapply( data, function ) 用于将函数应用于嵌套列表。

标签: r dplyr purrr broom


【解决方案1】:

如果没有对您的数据进行测试,我认为您使用了错误的 map 函数。 purrr::map 作用于 one 参数(一个列表,一个向量,等等)并返回一个列表。您正在向它传递两个值(data3data2),所以我们需要使用:

dmaExtendedDataNA2 <- dmaExtendedDataNA %>%
                      group_by(dma) %>%
                      nest() %>%
                      mutate(data2 = map(data, ~filter(., !(is.na(mean_night_flow)))),
                             data3 = map(data, ~filter(., is.na(mean_night_flow))),
                             data4 = map2(data3, data2, ~my_function(.x,.y)))

如果您发现自己需要两个以上,则需要pmap。您可以将pmap 用于 1 或 2 个参数,实际上是相同的。从map 迁移到pmap 时最大的两个区别是:

  • 您的参数需要包含在一个列表中,所以

    map2(data3, data12, ...)
    

    变成

    pmap(list(data3, data12), ...)
    
  • 你用双点号位置,..1..2..3等来引用它们,所以

    ~ my_function(.x, .y)
    

    变成

    ~ my_function(..1, ..2)
    

一种可以稍微简化整体流程的替代方案。

my_function (test, train = NULL, fld = "mean_night_flow") {
  if (is.null(train)) {
    train <- test[ !is.na(test[[fld]]),, drop = FALSE ]
    test <- test[ is.na(test[[fld]]),, drop = FALSE ]
  }
  et  <- extraTrees(x = train, y = train[, fld], na.action = "fuse", ntree = 1000, nodesize = 2, mtry = ncol(train) * 0.9 )
  test1 <- test
  test1[ , fld] <- 0
  pred  <- predict(et, newdata = test1[, fld])
  test1[ , fld] <- pred
  return(test1)
}

它会根据您的字段的缺失自动填充train。 (我还对其进行了参数化,以防您需要在不同的领域进行训练/测试。)这将您的使用更改为

dmaExtendedDataNA2 <- dmaExtendedDataNA %>%
                      group_by(dma) %>%
                      nest() %>%
                      mutate(data4 = map(data, ~ my_function(.x, fld = "mean_night_flow")))

(命名fld= 很重要,否则会与train 混淆。)

如果您计划稍后在管道或分析中重用data2 和/或data3,那么此步骤不一定是您需要的。

注意:我怀疑您的功能测试不足或不完整。您将所有0 分配给test1[,"mean_night_flow"],然后在调用predict 时使用这些零,这一事实似乎令人怀疑。我可能会遗漏一些东西,但我可能会期待

  test1 <- test
  pred  <- predict(et, newdata = test1)
  test1[ , fld] <- pred
  return(test1)

(尽管使用tibbledata.frame 复制到test1 基本上是不必要的,因为它是就地复制的并且原始框架没有受到影响;如果您使用data.table 类,我会更加谨慎) .

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 2017-01-28
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    • 2021-08-07
    • 2021-09-20
    • 2018-12-20
    • 1970-01-01
    相关资源
    最近更新 更多