创建一个R函数,标准化多个变量并创建新列。

3
我有一个数据集,其中我使用许多变量的平均中心化和标准化版本。在我的R代码中,我有一个大型的scale()函数列表,适用于所有变量,但我想知道是否有一种方法编写一个简单的函数来优化此过程。
例如:不要像这样拥有一个巨大的列表...
df$Z.ROW1 <- scale(df$ROW1, scale=T)
df$Z.ROW2 <- scale(df$ROW2, scale=T)
df$Z.ROW3 <- scale(df$ROW3, scale=T)
.....

有没有一种方法可以编写一个函数,根据我指定要标准化的变量,在数据框的末尾创建新向量并将它们添加到其中?

我在网上找到了这个 示例

set.seed(212)
df = matrix(rnorm(15), 5, 5))
colnames(df) <- c("ROW1", "ROW2", "ROW3", "ROW4", "ROW5")
df

          ROW1       ROW2       ROW3       ROW4       ROW5
[1,] -0.2391731  0.1544909  0.1503488 -0.2391731  0.1544909
[2,]  0.6769356  1.0368712  0.5096765  0.6769356  1.0368712
[3,] -2.4403360 -0.7796077 -0.7733148 -2.4403360 -0.7796077
[4,]  1.2408845  0.6212641  1.8756660  1.2408845  0.6212641
[5,] -0.3265144  0.2994313  0.7883057 -0.3265144  0.2994313

center.scale <- function(z) {
  scale(z, scale = T)
}
center.scale(df[,c("ROW1", "ROW2")])

         ROW1      ROW2
[1,] -0.01534097 -0.1657064
[2,]  0.63734894  1.1398052
[3,] -1.58357932 -1.5477370
[4,]  1.03913941  0.5249004
[5,] -0.07756806  0.0487378

这个方法接近解决了问题,但是它没有解决创建新向量并将它们附加到现有数据集末尾的问题。理想情况下,我希望只需要更改center.scale()函数中的变量名称即可。谢谢!


3
只需将输出与原始数据进行列合并(cbind)即可? - Dason
3个回答

3

这里是一种不硬编码 scale选项,并允许您选择原始列的子集的版本。它返回一个data.frame,因为这在更多情况下会很有用,但如果您希望,可以轻松修改它以返回一个matrix

add_scaled <- function(data, vars = colnames(data), ...) {
    data.frame(data,
               setNames(data.frame(scale(data[, vars, drop = FALSE],
                                         ...)),
                        paste("Z", vars, sep = ".")))
}

默认情况下,它返回一个所有列都被标准化并附加的data.frame

df = matrix(rnorm(15), 5, 3)
colnames(df) <- paste0("Col", 1:ncol(df))
df
##            Col1       Col2       Col3
## [1,]  1.9659082 -1.2254071  0.1477912
## [2,]  0.2666273 -0.9123931  1.4747579
## [3,]  1.0813351  2.4138457 -1.5569830
## [4,]  0.9618084  1.3076966 -0.8646893
## [5,] -2.0246095  0.3043559 -1.3617747

add_scaled(df)
##         Col1       Col2       Col3     Z.Col1      Z.Col2     Z.Col3
## 1  1.9659082 -1.2254071  0.1477912  1.0040228 -1.05411792  0.4625295
## 2  0.2666273 -0.9123931  1.4747579 -0.1216110 -0.84828629  1.5207917
## 3  1.0813351  2.4138457 -1.5569830  0.4180659  1.33898111 -0.8970361
## 4  0.9618084  1.3076966 -0.8646893  0.3388893  0.61159985 -0.3449285
## 5 -2.0246095  0.3043559 -1.3617747 -1.6393669 -0.04817676 -0.7413566

如果只有某些列需要标准化,您可以选择它们。
add_scaled(df, vars = c("Col1", "Col3"))
##         Col1       Col2       Col3     Z.Col1     Z.Col3
## 1  1.9659082 -1.2254071  0.1477912  1.0040228  0.4625295
## 2  0.2666273 -0.9123931  1.4747579 -0.1216110  1.5207917
## 3  1.0813351  2.4138457 -1.5569830  0.4180659 -0.8970361
## 4  0.9618084  1.3076966 -0.8646893  0.3388893 -0.3449285
## 5 -2.0246095  0.3043559 -1.3617747 -1.6393669 -0.7413566

最后,您可以向 scale 传递参数,这样您就不会失去任何灵活性。

add_scaled(df, vars = "Col1", center = FALSE, scale = TRUE)
##         Col1       Col2       Col3     Z.Col1
## 1  1.9659082 -1.2254071  0.1477912  1.2353890
## 2  0.2666273 -0.9123931  1.4747579  0.1675502
## 3  1.0813351  2.4138457 -1.5569830  0.6795177
## 4  0.9618084  1.3076966 -0.8646893  0.6044064
## 5 -2.0246095  0.3043559 -1.3617747 -1.2722773

add_scaled(df, vars = "Col1", center = TRUE, scale = FALSE)
##         Col1       Col2       Col3     Z.Col1
## 1  1.9659082 -1.2254071  0.1477912  1.5156943
## 2  0.2666273 -0.9123931  1.4747579 -0.1835866
## 3  1.0813351  2.4138457 -1.5569830  0.6311212
## 4  0.9618084  1.3076966 -0.8646893  0.5115945
## 5 -2.0246095  0.3043559 -1.3617747 -2.4748234

运行完美。非常感谢你的时间! - Addison

2

就像 @Dason 所说的,你只需要修改你原始数据中的函数为 cbind,并相应地命名新列即可。

center.scale <- function(z) {

   x <- scale(z, scale = T)

   colnames(x) <- paste0("scale_", colnames(x))

   cbind(z, x)

}

center.scale(df[,c("ROW1", "ROW2")])

结果为:

          ROW1       ROW2  scale_ROW1 scale_ROW2
[1,] -0.2391731  0.1544909 -0.01534097 -0.1657064
[2,]  0.6769356  1.0368712  0.63734894  1.1398052
[3,] -2.4403360 -0.7796077 -1.58357932 -1.5477370
[4,]  1.2408845  0.6212641  1.03913941  0.5249004
[5,] -0.3265144  0.2994313 -0.07756806  0.0487378

1
如果我正确理解了你的问题,你可以像 @Dason 建议的那样将 scale 的输出与原始数据进行 cbind
例如:
> df <- data.frame(ROW1 = c(1,2,1,1), ROW2 = c(1,2,3,4), ROW3 = c(5,8,6,5))
> df
  ROW1 ROW2 ROW3
1    1    1    5
2    2    2    8
3    1    3    6
4    1    4    5
> df <- cbind(df, scale(df, scale = T))
> names(df)[4:6] <- paste0('Z.', names(df)[4:6])
> df
  ROW1 ROW2 ROW3 Z.ROW1     Z.ROW2     Z.ROW3
1    1    1    5   -0.5 -1.1618950 -0.7071068
2    2    2    8    1.5 -0.3872983  1.4142136
3    1    3    6   -0.5  0.3872983  0.0000000
4    1    4    5   -0.5  1.1618950 -0.7071068

2
我不明白。你为什么要用自己的函数替换 scale 函数,而这个函数并没有进行缩放操作?另外,为什么建议使用 apply 函数,而 ?scale 函数本来就是为矩阵设计的呢? - Ista
哦,抱歉我误解了,以为scale是自定义函数。我会更新我的答案。 - C. Braun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接