1

データの区分的線形変換を実行しようとしています。変換を説明する表の例を次に示します。

dat <- data.frame(x.low = 0:2, x.high = 1:3, y.low=c(0, 2, 3), y.high=c(2, 3, 10))
dat
#   x.low x.high y.low y.high
# 1     0      1     0      2
# 2     1      2     2      3
# 3     2      3     3     10

を定義x <- c(1.75, 2.5)した場合、変換された値は 2.75 と 6.5 になると予想されます (私の要素はdatそれぞれ の 2 行目と 3 行目に一致します)。

forこの問題をループで解決し、行を反復してdat対応する値を変換する方法を知っています。

pw.lin.trans <- function(x, m) {
  out <- rep(NA, length(x))
  for (i in seq(nrow(m))) {
    matching <- x >= m$x.low[i] & x <= m$x.high[i]
    out[matching] <- m$y.low[i] + (x[matching] - m$x.low[i]) /
      (m$x.high[i] - m$x.low[i]) * (m$y.high[i] - m$y.low[i])
  }
  out
}
pw.lin.trans(x, dat)
# [1] 2.75 6.50

xこれは機能しますが、値を の行に一致させてからdat、すべての補間を 1 回の計算で実行する、より良いアプローチがあるはずです。誰かforがこの問題の非ループ解決策を教えてくれませんか?

4

1 に答える 1

4

試してくださいapprox

(xp <- unique(c(dat$x.low, dat$x.high)))
## [1] 0 1 2 3
(yp <- unique(c(dat$y.low, dat$y.high)))
## [1]  0  2  3 10
x <- c(1.75, 2.5)
approx(xp, yp, x)
## $x
## [1] 1.75 2.50
## 
## $y
## [1] 2.75 6.50

またはapproxfun(新しい関数を返します):

f <- approxfun(xp, yp)
f(x)
## [1] 2.75 6.50

いくつかのベンチマーク:

set.seed(123L)
x <- runif(10000, min(xp), max(yp))
library(microbenchmark)
microbenchmark(
  pw.lin.trans(x, dat),
  approx(xp, yp, x)$y,
  f(x)
)
## Unit: microseconds
##                  expr      min       lq    median        uq      max neval
##  pw.lin.trans(x, dat) 3364.241 3395.244 3614.0375 3641.7365 6170.268   100
##   approx(xp, yp, x)$y  359.080  379.669  424.0895  453.6800  522.756   100
##                  f(x)  202.899  209.168  217.8715  232.3555  293.499   100
于 2014-05-13T18:26:48.880 に答える