backtransform`scale()`用于绘图

时间:2012-04-23 20:10:53

标签: r

我有一个使用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

谢谢!

9 个答案:

答案 0 :(得分:50)

看看:

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

答案 1 :(得分:12)

对于数据框或矩阵:

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

答案 2 :(得分:6)

我觉得这应该是一个合适的功能,这是我的尝试:

var jun = moment("2014-06-01T12:00:00Z");
var dec = moment("2014-12-01T12:00:00Z");

jun.tz('America/Los_Angeles').format('ha z');  // 5am PDT **I get 7am** 
dec.tz('America/Los_Angeles').format('ha z');  // 4am PST **I get 6am**

答案 3 :(得分:3)

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)

如何取消缩放

解释

  1. 首先乘以比例因子:

    y = x * sqrt( ( sum( (x - mean(x , na.rm = T))^2) ) / (length(x) - 1))
    
  2. 然后加回平均值:

    y + mean(x , na.rm = T)
    
  3. 显然,你需要知道这个手动方法的原始数据集的平均值真正是有用的,但我把它放在这里是为了概念。

    幸运的是,正如之前的答案所示,“居中”值(即 mean )位于scale对象的属性中,因此这种方法可以简化为:

    如何做R

    unscaled_vals <- xs + attr(xs, 'scaled:scale') + attr(xs, 'scaled:center')
    
    • 其中xs是由scale(x)创建的缩放对象。

答案 4 :(得分:1)

我遇到了这个问题,我想我找到了一个使用线性代数的简单解决方案。

# 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)

答案 5 :(得分:1)

古老的问题,但是为什么不这样做呢?

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))

重要的是,unscale的第二个自变量需要具有'scaled:scale''scaled:center'的属性

答案 6 :(得分:0)

我迟到了。但这是一个有用的工具,可以按数组格式缩放/取消缩放数据。

示例:

> (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

答案 7 :(得分:0)

只是受Fermando的回答启发,但是用更少的代码扩展了行:

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

答案 8 :(得分:0)

我发现反转 scale() 函数的一种简单方法是调用两次 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)