首页 > 解决方案 > 错误条件超过 1 个函数 if else [编辑:rowwise]

问题描述

TL;DR:我的函数不是向量化的吗?如何使用许多 if & else 语句对调用其他函数的函数进行矢量化?非常感谢!

编辑:该功能在控制台中一次手动执行一棵树时起作用,或者在使用时使用 dplyr-styledplyr::rowwise

我正在编写一个包含很多 if 和 'else' 的函数。

该函数根据提供(或缺少)哪些参数来决定使用哪个函数来计算树的体积。

我想像这样使用它,dplyr 风格,在一个包含许多案例的巨大数据表上。

tree_data %>% mutate(volume = tree.volume(dbh.cm = dbh.cm, height.m= height, species.latin=species.latin, latitude= latitude)

缺少crown.base.height.m 和double.bark.mm 是很常见的(有没有这些参数的体积函数)。

tree.volume <- function(dbh.cm,height.m,crown.base.height.m,double.bark.mm,species.latin,latitude){
  if(grepl("^Pinus", ignore.case=TRUE, species.latin)){
    pinus_spp_vol(species.latin = species.latin,
                  dbh.cm = dbh.cm,
                  height.m = height.m,
                  latitude = latitude,
                  double.bark.mm = double.bark.mm,
                  crown.base.height.m = crown.base.height.m)
  } else if(grepl("^Picea|^Abies",ignore.case = TRUE, species.latin)){
    picea_spp_vol(dbh.cm = dbh.cm,
                  height.m = height.m,
                  latitude = latitude,
                  crown.base.height.m = crown.base.height.m)
  } else if(grepl("^Larix", ignore.case = TRUE, species.latin)){
    larix_sibirica_vol_carbonnier_1954(dbh.cm = dbh.cm,
                                       height.m = height.m,
                                       double.bark.mm = double.bark.mm,
                                       crown.base.height.m = crown.base.height.m)
  }

}

我收到警告消息:

1: 在 if (grepl("^Pinus", ignore.case = TRUE, species.latin)) { :
条件长度 > 1 并且只使用第一个元素

2: 在 if (species.latin == "Pinus contorta") { : 条件长度 > 1 并且只使用第一个元素

3: 在 if (dbh.cm >= 4.5) { : 条件长度 > 1 并且只使用第一个元素

4: 在 if (latitude >= 60) { : 条件长度 > 1 并且只使用第一个元素

我把它读成函数一次不处理我的data.frame中的一行......因此认为我的所有行都与第一行处于相同的“类别”下?

附:读取导致错误的 if 语句的第一个函数:

pinus_spp_vol <- function(species.latin, dbh.cm, height.m, crown.base.height.m, double.bark.mm, latitude){
  if(!missing(crown.base.height.m)){
    if(!missing(double.bark.mm)){
      if(species.latin!="Pinus contorta"){
        if(dbh.cm >= 4.5){ #Brandel, 1990 function 100-4. for Pines above 4.5 cm dbh.
          if(latitude >= 60){
            (10^-1.12715)*(dbh.cm^2.13211)*((dbh.cm+20)^-0.13543)*(height.m^1.58121)*((height.m-1.3)^-0.73435)*(crown.base.height.m^0.06595)*(double.bark.mm^-0.10998)
          } else {
            (10^-1.20042)*(dbh.cm^2.10263)*((dbh.cm+20)^-0.07366)*(height.m^1.99751)*((height.m-1.3)^-1.11357)*(crown.base.height.m^0.06420)*(double.bark.mm^-0.14963)
          }
        } else { #Andersson,1954 for small trees.
          if(latitude >= 60){
            0.22 + 0.08786 * (dbh.cm^2) + 0.03045 * (dbh.cm^2) * height.m + 0.002809 * dbh.cm * (height.m^2)
          } else {
            0.22 + 0.1066 * (dbh.cm^2) + 0.02085 * (dbh.cm^2) * height.m + 0.008427 * dbh.cm * (height.m^2)
          }
        }
      }
    }
  } else {
    if(species.latin== "Pinus contorta"){ #Eriksson 1973
      0.1121*(dbh.cm^2) + 0.02870*(dbh.cm^2)*height.m - 0.000061*(dbh.cm^2)*(height.m^2) - 0.09176*dbh.cm*height.m + 0.01249*dbh.cm*(height.m^2)
    } else {
      if(dbh.cm >= 4.5){#Brandel 1990, 100-01
        if(latitude >= 60){
          (10^-1.20914)*(dbh.cm^1.94740)*((dbh.cm+20)^-0.05947)*(height.m^1.40958)*((height.m-1.3)^-0.45810)
        } else {
          (10^-1.38903)*(dbh.cm^1.84493)*((dbh.cm+20)^0.06563)*(height.m^2.02122)*((height.m-1.3)^-1.01095)
        }
      } else { #Andersson,1954 for small trees.
        if(latitude >= 60){
          0.22 + 0.08786 * (dbh.cm^2) + 0.03045 * (dbh.cm^2) * height.m + 0.002809 * dbh.cm * (height.m^2)
        } else {
          0.22 + 0.1066 * (dbh.cm^2) + 0.02085 * (dbh.cm^2) * height.m + 0.008427 * dbh.cm * (height.m^2)
        }
      }
    }
  }
}

标签: rfunctiondplyrvectorization

解决方案


您将 non-vectorizedif () ... else ...与 vectorized混淆了ifelse

if () ... else ... 接受单个 (!!) 条件并对条件是否为TRUE或执行操作FALSE。如果您改为为条件传递(逻辑)向量,则仅选择向量的第一个元素来决定要执行的操作。作为通知,R 将发出警告。但是,除此之外,您通常会得到错误或非预期的结果。

ifelse另一方面是矢量化的,即检查两个条件并按元素采取行动。对于所有TRUE元素,TRUE选择动作,对于所有FALSE元素,FALSE选择动作。

一个简单的例子可以很好地看出这一点:

power2 <- function(x) x^2
power3 <- function(x) x^3

myfun_warning <- function(cyl) {
  if (cyl == 4) {
    power2(cyl)
  } else {
    power3(cyl)
  }
}

myfun_no_warning <- function(cyl) {
  ifelse(cyl == 4, power2(cyl), power3(cyl))
}

# Warning and incorrect result
myfun_warning(mtcars$cyl)
#> Warning in if (cyl == 4) {: the condition has length > 1 and only the first
#> element will be used
#>  [1] 216 216  64 216 512 216 512  64  64 216 216 512 512 512 512 512 512  64  64
#> [20]  64  64 512 512 512 512  64  64  64 512 216 512  64

# No warning and correct result
myfun_no_warning(mtcars$cyl)
#>  [1] 216 216  16 216 512 216 512  16  16 216 216 512 512 512 512 512 512  16  16
#> [20]  16  16 512 512 512 512  16  16  16 512 216 512  16

推荐阅读