19

基本的に次のようなRコードがあります。

compute.quantiles <- function(mu, type) {

  ## 'mu' and 'type' are vectors of the same length

  var <- ifelse(type=='a', 6.3523 * mu^2,
         ifelse(type=='b', 234.23 * mu,
         ifelse(type=='c', {s <- 9.8 * ((mu-0.3)/3)^(6/7)+0.19; mu + mu^2/s},
         ifelse(type=='d', 56.345 * mu^1.5,
         ifelse(type=='e', 0.238986 * mu^2,
         ifelse(type=='f', mu + 1.1868823 * mu^2,
         NA ))))))

  # ...then do something with var...
}

いくつかのサンプル入力と出力:

print(compute.quantiles(2:4, c('c','d','e')))
[1]   2.643840 292.777208   3.823776

それは正しく機能しますが、深いネストではちょっと醜いので、もっとうまく機能する別のイディオムがあるかどうか疑問に思います。誰か提案がありますか?ベクトルを最初の引数として受け入れた場合switch()、それはうまく機能しますが、スカラーを使用するだけです。

4

5 に答える 5

7

私は私がもっと好きなものを思いついたと思います:

## Vector-switch
vswitch <- function(EXPR, ...) {
    vars <- cbind(...)
    vars[cbind(seq_along(EXPR), match(EXPR, names(list(...))))]
}

compute.quantiles <- function(mu, type) {
  stopifnot(length(mu) == length(type))

  vswitch( type,
    a = 6.3523 * mu^2,
    b = 234.23 * mu,
    c = mu + mu^2/(9.8 * ((mu-0.3)/3)^(6/7)+0.19),
    d = 56.345 * mu^1.5,
    e = 0.238986 * mu^2,
    f = mu + 1.1868823 * mu^2)
}

たった2行のマトリックスインデックスコードで、私はあまりにも賢いコードのしきい値で大丈夫だと思います。=)

于 2012-05-07T20:21:39.610 に答える
5

別のアプローチは次のとおりです。

library(data.table)
# Case selection table:
dtswitch <- data.table(type=letters[1:6],
                      result=c("6.3523 * mu^2",
                               "234.23 * mu",
                               "{s <- 9.8 * ((mu-0.3)/3)^(6/7)+0.19; mu + mu^2/s}",
                               "56.345 * mu^1.5",
                               "0.238986 * mu^2",
                               "mu + 1.1868823 * mu^2"),
                      key="type")

# Data to which you want the cases applied:
compute <- data.table(type=letters[3:5],mu=2:4,key="type")

# Join the data table with the case selection table, and evaluate the results:
dtswitch[compute,list(mu,result=eval(parse(text=result)))]
#>   type mu     result
#>1:    c  2   2.643840
#>2:    d  3 292.777208
#>3:    e  4   3.823776

Rコードでdtswitchテーブルを作成するのではなく、外部のスプレッドシートまたはデータベースに保存してからRにロードすることができます。さまざまなケースが多数ある場合や頻繁に変更されてからそれらを制御したい場合に便利です。中央の場所。

于 2013-08-16T17:10:37.347 に答える
3

Ken Williamsのの実装はvswitch、一部のタイプの入力ではうまく機能しません。これはもっと柔軟だと思います:

vswitch <- function(expr, ...) {
  lookup <- list(...)
  vec <- as.character(expr)
  vec[is.na(vec)] <- "NA"
  unname(do.call(c, lookup[vec]))
}

数値ルックアップ値で使用するには、それらを引用符または逆引用符で囲む必要があります。

num_vec <- c(1, 3, 2, 2, 1)
vswitch(num_vec, `1` = 10, `2` = 25, `3` = 50)
## [1] 10 50 25 25 10

文字ルックアップの場合:

char_vec <- letters[num_vec]
vswitch(char_vec, a = "Albert", b = "Bertrand", c = "Charles")
## [1] "Albert"   "Charles"  "Bertrand" "Bertrand" "Albert"
于 2014-09-23T07:55:48.193 に答える
1

たぶん、このようなものは実行可能です:

compute.quantiles <- function(mu, type) {
  stopifnot(length(mu) == length(type))

  vars <- cbind(
    a = 6.3523 * mu^2,
    b = 234.23 * mu,
    c = mu + mu^2/(9.8 * ((mu-0.3)/3)^(6/7)+0.19),
    d = 56.345 * mu^1.5,
    e = 0.238986 * mu^2,
    f = mu + 1.1868823 * mu^2)

  vars[cbind(seq_along(mu), match(type, colnames(vars)))]
}

しかし、それが将来の読者(私を含む)にとってあまりにも「高度」に見えるかどうかはわかりません。

于 2012-05-07T19:20:56.477 に答える
0

まったく異なるアプローチで別の答えを追加することに抵抗できませんでした。ここにあります。

## Sort of a cross between tapply() and ave()
tswitch <- function(x, INDEX, ...) {
  l <- substitute(list(...))
  s <- split(x, INDEX)
  pf <- parent.frame()
  split(x, INDEX) <- lapply(names(s), function(n) 
    eval(l[[n]], list(x=s[[n]]), pf)
  )
  x
}

compute.quantiles <- function(mu, type) {
  stopifnot(length(mu) == length(type))

  tswitch(mu, type,
    a = 6.3523 * x^2,
    b = 234.23 * x,
    c = x + x^2/(9.8 * ((x-0.3)/3)^(6/7)+0.19),
    d = 56.345 * x^1.5,
    e = 0.238986 * x^2,
    f = x + 1.1868823 * x^2)
}

そして、サンプルの入力と出力:

> compute.quantiles(2:4, c('c','d','e'))
[1]   2.643840 292.777208   3.823776

この実装の利点は、計算length(mu)が必要な特定の値のみを計算することです。対照的に、上記の方法では値がvswitch計算されます。ここで、はスイッチの「ケース」の数です。したがって、計算にコストがかかる場合、またはデータが大きい場合は、このバージョンが適している可能性があります。length(mu) * MM

于 2012-05-14T18:13:18.040 に答える