scale()
応答変数を予測するために使用されるを使用して中央に配置された説明変数があります。
d <- data.frame(
x=runif(100),
y=rnorm(100)
)
d <- within(d, s.x <- scale(x))
m1 <- lm(y~s.x, data=d)
予測値をプロットしたいのですがx
、中央のスケールではなく、の元のスケールを使用しています。逆変換または逆スケールを並べ替える方法はありs.x
ますか?
ありがとう!
scale()
応答変数を予測するために使用されるを使用して中央に配置された説明変数があります。
d <- data.frame(
x=runif(100),
y=rnorm(100)
)
d <- within(d, s.x <- scale(x))
m1 <- lm(y~s.x, data=d)
予測値をプロットしたいのですがx
、中央のスケールではなく、の元のスケールを使用しています。逆変換または逆スケールを並べ替える方法はありs.x
ますか?
ありがとう!
を見てみましょう:
attributes(d$s.x)
属性を使用してスケーリングを解除できます。
d$s.x * attr(d$s.x, 'scaled:scale') + attr(d$s.x, 'scaled:center')
例えば:
> x <- 1:10
> s.x <- scale(x)
> s.x
[,1]
[1,] -1.4863011
[2,] -1.1560120
[3,] -0.8257228
[4,] -0.4954337
[5,] -0.1651446
[6,] 0.1651446
[7,] 0.4954337
[8,] 0.8257228
[9,] 1.1560120
[10,] 1.4863011
attr(,"scaled:center")
[1] 5.5
attr(,"scaled:scale")
[1] 3.02765
> s.x * attr(s.x, 'scaled:scale') + attr(s.x, 'scaled:center')
[,1]
[1,] 1
[2,] 2
[3,] 3
[4,] 4
[5,] 5
[6,] 6
[7,] 7
[8,] 8
[9,] 9
[10,] 10
attr(,"scaled:center")
[1] 5.5
attr(,"scaled:scale")
[1] 3.02765
データフレームまたはマトリックスの場合:
set.seed(1)
x = matrix(sample(1:12), ncol= 3)
xs = scale(x, center = TRUE, scale = TRUE)
x.orig = t(apply(xs, 1, function(r)r*attr(xs,'scaled:scale') + attr(xs, 'scaled:center')))
print(x)
[,1] [,2] [,3]
[1,] 4 2 3
[2,] 5 7 1
[3,] 6 10 11
[4,] 9 12 8
print(x.orig)
[,1] [,2] [,3]
[1,] 4 2 3
[2,] 5 7 1
[3,] 6 10 11
[4,] 9 12 8
次のような関数を使用する場合は注意してくださいidentical()
。
print(x - x.orig)
[,1] [,2] [,3]
[1,] 0 0 0.000000e+00
[2,] 0 0 8.881784e-16
[3,] 0 0 0.000000e+00
[4,] 0 0 0.000000e+00
identical(x, x.orig)
# FALSE
私はこれが適切な機能であるべきだと感じました、これが私の試みでした:
#' Reverse a scale
#'
#' Computes x = sz+c, which is the inverse of z = (x - c)/s
#' provided by the \code{scale} function.
#'
#' @param z a numeric matrix(like) object
#' @param center either NULL or a numeric vector of length equal to the number of columns of z
#' @param scale either NULL or a a numeric vector of length equal to the number of columns of z
#'
#' @seealso \code{\link{scale}}
#' mtcs <- scale(mtcars)
#'
#' all.equal(
#' unscale(mtcs),
#' as.matrix(mtcars),
#' check.attributes=FALSE
#' )
#'
#' @export
unscale <- function(z, center = attr(z, "scaled:center"), scale = attr(z, "scaled:scale")) {
if(!is.null(scale)) z <- sweep(z, 2, scale, `*`)
if(!is.null(center)) z <- sweep(z, 2, center, `+`)
structure(z,
"scaled:center" = NULL,
"scaled:scale" = NULL,
"unscaled:center" = center,
"unscaled:scale" = scale
)
}
tl; dr:
unscaled_vals <- xs + attr(xs, 'scaled:scale') + attr(xs, 'scaled:center')
xs
によって作成されたスケーリングされたオブジェクトはどこですかscale(x)
これについて少し理解しようとしている人のためだけに:
Rのスケーリング方法:
このscale
関数は、デフォルトでスケーリングとセンタリングの両方を実行します。
centering
最初に実行されます。センタリングは、デフォルトで!is.na
、各値からすべての入力値の平均を引くことによって実現されます。
data - mean(data, rm.na = T)
スケーリングは、次の方法で実現されます。
sqrt( ( sum(x^2) ) / n - 1)
ここで、はスケーリングするx
すべての値のセットであり、 =です。!is.na
n
length(x)
ただし、重要なのは、にある場合center =T
、元のデータセットscale
でx
はなく、すでに中央に配置されているデータです。
したがって、center = T
(デフォルト)の場合、スケーリング関数は実際に次のように計算しています。
sqrt( ( sum( (data - mean(data, rm.na = T))^2) ) / n - 1)
center = T
]これは標準偏差を取るのと同じです:sd(data)
。スケールを解除する方法:
説明:
最初にスケーリング係数を掛けます:
y = x * sqrt( ( sum( (x - mean(x , na.rm = T))^2) ) / (length(x) - 1))
次に、平均を追加します。
y + mean(x , na.rm = T)
明らかに、この手動アプローチが本当に役立つためには、元のデータセットの平均を知る必要がありますが、概念的な目的でここに配置します。
幸い、以前の回答が示しているように、「センタリング」値(つまり、平均)はscale
オブジェクトの属性にあるため、このアプローチは次のように簡略化できます。
Rで行う方法:
unscaled_vals <- xs + attr(xs, 'scaled:scale') + attr(xs, 'scaled:center')
xs
はによって作成されたスケーリングされたオブジェクトですscale(x)
。私はこの問題に遭遇し、線形代数を使用したより簡単な解決策を見つけたと思います。
# create matrix like object
a <- rnorm(1000,5,2)
b <- rnorm(1000,7,5)
df <- cbind(a,b)
# get center and scaling values
mean <- apply(df, 2, mean)
sd <- apply(df, 2, sd)
# scale data
s.df <- scale(df, center = mean, scale = sd)
#unscale data with linear algebra
us.df <- t((t(s.df) * sd) + mean)
古い質問ですが、なぜあなたはこれをしないのですか?
plot(d$x, predict(m1, d))
スケーリングされたオブジェクトの属性を手動で使用するよりも簡単な方法として、DMwRには次の機能がありますunscale
。それはこのように動作します:
d <- data.frame(
x=runif(100)
)
d$y <- 17 + d$x * 12
s.x <- scale(d$x)
m1 <- lm(d$y~s.x)
library(DMwR)
unsc.x <- unscale(d$x, s.x)
plot(unsc.x, predict(m1, d))
重要なのは、の2番目の引数には、とunscale
の属性を持つものが必要です。'scaled:scale'
'scaled:center'
私はパーティーに遅れています。ただし、ここに配列形式でデータをスケーリング/スケール解除するための便利なツールがあります。
例:
> (data <- array(1:8, c(2, 4))) # create data
[,1] [,2] [,3] [,4]
[1,] 1 3 5 7
[2,] 2 4 6 8
> obj <- Scale(data) # create object
> (data_scaled <- obj$scale(data)) # scale data
[,1] [,2] [,3] [,4]
[1,] -0.7071068 -0.7071068 -0.7071068 -0.7071068
[2,] 0.7071068 0.7071068 0.7071068 0.7071068
> (obj$unscale(data_scaled)) # unscale scaled data
[,1] [,2] [,3] [,4]
[1,] 1 3 5 7
[2,] 2 4 6 8
## scale or unscale another dataset
## using the same mean/sd parameters
> (data2 <- array(seq(1, 24, 2), c(3, 4))) # create demo data
[,1] [,2] [,3] [,4]
[1,] 1 7 13 19
[2,] 3 9 15 21
[3,] 5 11 17 23
> (data2_scaled <- obj$scale(data2)) # scale data
[,1] [,2] [,3] [,4]
[1,] -0.7071068 4.949747 10.60660 16.26346
[2,] 2.1213203 7.778175 13.43503 19.09188
[3,] 4.9497475 10.606602 16.26346 21.92031
> (obj$unscale(data2_scaled)) # unscale scaled data
[,1] [,2] [,3] [,4]
[1,] 1 7 13 19
[2,] 3 9 15 21
[3,] 5 11 17 23
機能 Scale()
:
Scale <- function(data, margin=2, center=TRUE, scale=TRUE){
stopifnot(is.array(data), is.numeric(data),
any(mode(margin) %in% c("integer", "numeric")),
length(margin) < length(dim(data)),
max(margin) <= length(dim(data)),
min(margin) >= 1,
!any(duplicated(margin)),
is.logical(center), length(center)==1,
is.logical(scale), length(scale)==1,
!(isFALSE(center) && isFALSE(scale)))
margin <- as.integer(margin)
m <- if(center) apply(data, 2, mean, na.rm=TRUE) else NULL
s <- if(scale) apply(data, 2, sd, na.rm=TRUE) else NULL
ldim <- length(dim(data))
cdim <- dim(data)[margin]
data <- NULL # don't store the data
Scale <- function(data){
stopifnot(is.array(data), is.numeric(data),
length(dim(data)) == ldim,
dim(data)[margin] == cdim)
if(center)
data <- sweep(data, margin, m, `-`)
if(scale)
data <- sweep(data, margin, s, `/`)
data
}
Unscale <- function(data){
stopifnot(is.array(data), is.numeric(data),
length(dim(data)) == ldim,
dim(data)[margin] == cdim)
if(scale)
data <- sweep(data, margin, s, `*`)
if(center)
data <- sweep(data, margin, m, `+`)
data
}
list(scale=Scale, unscale=Unscale, mean=m, sd=s)
}
注:
data.frame
sはまだサポートされていません。
フェルマンドの答えに触発されただけですが、コードが少ない非スケーリング行:
set.seed(1)
x = matrix(sample(1:12), ncol= 3)
xs = scale(x, center = TRUE, scale = TRUE)
center <- attr(xs,"scaled:center")
scale <- attr(xs,"scaled:scale")
x.orig <- t(t(xs) * scale + center) # code is less here
print(x)
[1,] 9 2 6
[2,] 4 5 11
[3,] 7 3 12
[4,] 1 8 10
print(x.orig)
[1,] 9 2 6
[2,] 4 5 11
[3,] 7 3 12
[4,] 1 8 10
attr(,"scaled:center")
[1] 5.25 4.50 9.75
attr(,"scaled:scale")
[1] 3.50 2.65 2.63
関数を元に戻す簡単な方法は、scale()
関数を2回呼び出すことscale()
です。
X_scaled <- scale(X,center=TRUE,scale=TRUE)
X_reversed <- scale(X_scaled,center=FALSE,scale=1/attr(X_scaled,'scaled:scale'))
X_reversed <- scale(X_reversed,center=-attr(X_scaled,'scaled:center'),scale=FALSE)
関数の引数内で関数を呼び出すことを気にしない場合(私は気にします)、次の解決策が得られる可能性があります。
X_scaled <- scale(X,center=TRUE,scale=TRUE)
X_reversed <- scale(scale(X_scaled,center=FALSE,scale=1/attr(X_scaled,'scaled:scale')),
center=-attr(X_scaled,'scaled:center'),scale=FALSE)