标准化R中的数据列

我有一个名为spam的数据集,其中包含58列和约3500行与垃圾邮件相关的数据。

我计划将来在这个数据集上运行一些线性回归,但我想事先做一些预处理,并将列标准化,使其具有零平均值和单位方差。

我被告知最好的方法是用R,所以我想问如何用R实现归一化?我已经正确加载了数据,我只是在寻找一些包或方法来执行这个任务。

611627 次浏览

我假设你想要的是均值为0,标准差为1。如果你的数据在一个数据框架中,并且所有的列都是数值的,你可以简单地调用数据上的scale函数来做你想做的事情。

dat <- data.frame(x = rnorm(10, 30, .2), y = runif(10, 3, 5))
scaled.dat <- scale(dat)


# check that we get mean of 0 and sd of 1
colMeans(scaled.dat)  # faster version of apply(scaled.dat, 2, mean)
apply(scaled.dat, 2, sd)

使用内置函数是有品位的。比如这只猫:

enter image description here

'插入'包提供了预处理数据的方法(例如居中和缩放)。你也可以使用下面的代码:

library(caret)
# Assuming goal class is column 10
preObj <- preProcess(data[, -10], method=c("center", "scale"))
newData <- predict(preObj, data[, -10])

更多详细信息:http://www.inside-r.org/node/86978

意识到这个问题已经很老了,一个答案已经被接受了,我将提供另一个答案供参考。

scale受到它扩展所有的变量的限制。下面的解决方案只允许缩放特定的变量名,同时保持其他变量不变(变量名可以动态生成):

library(dplyr)


set.seed(1234)
dat <- data.frame(x = rnorm(10, 30, .2),
y = runif(10, 3, 5),
z = runif(10, 10, 20))
dat


dat2 <- dat %>% mutate_at(c("y", "z"), ~(scale(.) %>% as.vector))
dat2

这给了我这个:

> dat
x        y        z
1  29.75859 3.633225 14.56091
2  30.05549 3.605387 12.65187
3  30.21689 3.318092 13.04672
4  29.53086 3.079992 15.07307
5  30.08582 3.437599 11.81096
6  30.10121 4.621197 17.59671
7  29.88505 4.051395 12.01248
8  29.89067 4.829316 12.58810
9  29.88711 4.662690 19.92150
10 29.82199 3.091541 18.07352

而且

> dat2 <- dat %>% mutate_at(c("y", "z"), ~(scale(.) %>% as.vector))
> dat2
x          y           z
1  29.75859 -0.3004815 -0.06016029
2  30.05549 -0.3423437 -0.72529604
3  30.21689 -0.7743696 -0.58772361
4  29.53086 -1.1324181  0.11828039
5  30.08582 -0.5946582 -1.01827752
6  30.10121  1.1852038  0.99754666
7  29.88505  0.3283513 -0.94806607
8  29.89067  1.4981677 -0.74751378
9  29.88711  1.2475998  1.80753470
10 29.82199 -1.1150515  1.16367556

编辑1 (2016):解决了Julian的评论:scale的输出是Nx1矩阵,所以理想情况下,我们应该添加as.vector来将矩阵类型转换回向量类型。谢谢朱利安!

编辑2 (2019):引用Duccio A。对于最新的dplyr(0.8版本),您需要更改dplyr::funcs with list,如dat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))

编辑3 (2020):感谢@mj_whales:旧的解决方案已弃用,现在我们需要使用mutate_at

使用" recommderlab "包。下载并安装软件包。 这个包内置了一个命令“Normalize”。它还允许你从众多归一化方法中选择一种即"中心"或" z分数" 示例如下:

. sh

. sh
## create a matrix with ratings
m <- matrix(sample(c(NA,0:5),50, replace=TRUE, prob=c(.5,rep(.5/6,6))),nrow=5, ncol=10, dimnames = list(users=paste('u', 1:5, sep=&rdquo;), items=paste('i', 1:10, sep=&rdquo;)))


## do normalization
r <- as(m, "realRatingMatrix")
#here, 'centre' is the default method
r_n1 <- normalize(r)
#here "Z-score" is the used method used
r_n2 <- normalize(r, method="Z-score")


r
r_n1
r_n2


## show normalized data
image(r, main="Raw Data")
image(r_n1, main="Centered")
image(r_n2, main="Z-Score Normalization")

您还可以使用数据轻松地将数据规范化。clusterSim包中的归一化函数。它提供了不同的数据规范化方法。

    data.Normalization (x,type="n0",normalization="column")

参数

< p > x < br > 向量,矩阵或数据集 类型< br > 归一化类型: N0 -未归一化

N1 -标准化((x-mean)/sd)

N2 -位置标准化((x-median)/mad)

N3 -单元化((x-mean)/range)

N3a -位置单元化(x-median /range)

N4 -最小值为零的单元化((x-min)/范围)

N5 -归一化范围<-1,1> ((x-mean)/max(abs(x-mean)))

N5a -范围<-1,1>的位置归一化((x-median)/max(abs(x-median)))

N6 -商变换(x/sd)

N6a -位置商变换(x/mad)

N7 -商变换(x/range)

N8 -商变换(x/max)

N9 -商数变换(x/mean)

N9a -位置商变换(x/median)

N10 -商变换(x/sum)

n11 -商变换(x/√(SSQ))

N12 -归一化((x-mean)/根号(sum((x-mean)^2))

N12a -位置归一化((x-median)/平方根(sum(x-median)^2))

N13 -归一化,中心点为0 ((x-midrange)/(range/2))

< br > < p >正常化 "column" -由变量归一化,"row" -由对象归一化

这是三年前的。不过,我还是觉得有必要补充以下几点:

最常见的归一化是z变换,其中减去平均值并除以变量的标准偏差。结果将是mean=0, sd=1。

为此,你不需要任何包装。

zVar <- (myVar - mean(myVar)) / sd(myVar)

就是这样。

当我使用Dason提出的解决方案时,而不是得到一个数据帧作为结果,我得到了一个数字向量(我的df的缩放值)。

为了防止有人遇到同样的问题,你必须在代码中添加as.data.frame(),就像这样:

df.scaled <- as.data.frame(scale(df))

我希望这对有同样问题的人有用!

在我碰巧发现这条线索之前,我也有同样的问题。我有用户依赖的列类型,所以我写了一个for循环遍历它们并获得所需的列__abc1d。也许有更好的方法,但这个方法很好地解决了问题:

 for(i in 1:length(colnames(df))) {
if(class(df[,i]) == "numeric" || class(df[,i]) == "integer") {
df[,i] <- as.vector(scale(df[,i])) }
}

as.vector是一个必要的部分,因为它原来是scalerownames x 1矩阵,这通常不是你想要在你的data.frame

Scale可以用于完整的数据帧和特定的列。 对于特定的列,可以使用以下代码:

trainingSet[, 3:7] = scale(trainingSet[, 3:7]) # For column 3 to 7
trainingSet[, 8] = scale(trainingSet[, 8]) # For column 8

全数据帧

trainingSet <- scale(trainingSet)

dplyr v0.7.4中,所有变量都可以通过使用mutate_all()来缩放:

library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#>     filter, lag
#> The following objects are masked from 'package:base':
#>
#>     intersect, setdiff, setequal, union
library(tibble)


set.seed(1234)
dat <- tibble(x = rnorm(10, 30, .2),
y = runif(10, 3, 5),
z = runif(10, 10, 20))


dat %>% mutate_all(scale)
#> # A tibble: 10 x 3
#>         x      y       z
#>     <dbl>  <dbl>   <dbl>
#>  1 -0.827 -0.300 -0.0602
#>  2  0.663 -0.342 -0.725
#>  3  1.47  -0.774 -0.588
#>  4 -1.97  -1.13   0.118
#>  5  0.816 -0.595 -1.02
#>  6  0.893  1.19   0.998
#>  7 -0.192  0.328 -0.948
#>  8 -0.164  1.50  -0.748
#>  9 -0.182  1.25   1.81
#> 10 -0.509 -1.12   1.16

可以使用mutate_at()排除特定变量:

dat %>% mutate_at(scale, .vars = vars(-x))
#> # A tibble: 10 x 3
#>        x      y       z
#>    <dbl>  <dbl>   <dbl>
#>  1  29.8 -0.300 -0.0602
#>  2  30.1 -0.342 -0.725
#>  3  30.2 -0.774 -0.588
#>  4  29.5 -1.13   0.118
#>  5  30.1 -0.595 -1.02
#>  6  30.1  1.19   0.998
#>  7  29.9  0.328 -0.948
#>  8  29.9  1.50  -0.748
#>  9  29.9  1.25   1.81
#> 10  29.8 -1.12   1.16

reprex包 (v0.2.0)于2018-04-24创建。

再说一次,尽管这是一个老问题,但它非常相关!我发现了一个简单的方法来规范化某些列,而不需要任何包:

normFunc <- function(x){(x-mean(x, na.rm = T))/sd(x, na.rm = T)}

例如

x<-rnorm(10,14,2)
y<-rnorm(10,7,3)
z<-rnorm(10,18,5)
df<-data.frame(x,y,z)


df[2:3] <- apply(df[2:3], 2, normFunc)

您将看到y和z列已经规范化。不需要软件包:-)

dplyr包有两个函数可以做到这一点。

> require(dplyr)

要改变数据表的具体的列,可以使用函数mutate_at()。要改变所有列,可以使用mutate_all

下面是使用这些函数来标准化数据的简单示例。

改变特定的列:

dt = data.table(a = runif(3500), b = runif(3500), c = runif(3500))
dt = data.table(dt %>% mutate_at(vars("a", "c"), scale)) # can also index columns by number, e.g., vars(c(1,3))


> apply(dt, 2, mean)
a             b             c
1.783137e-16  5.064855e-01 -5.245395e-17


> apply(dt, 2, sd)
a         b         c
1.0000000 0.2906622 1.0000000

改变所有列:

dt = data.table(a = runif(3500), b = runif(3500), c = runif(3500))
dt = data.table(dt %>% mutate_all(scale))


> apply(dt, 2, mean)
a             b             c
-1.728266e-16  9.291994e-17  1.683551e-16


> apply(dt, 2, sd)
a b c
1 1 1

BBMisc包中的正常化函数对我来说是合适的工具,因为它可以处理NA值。

下面是如何使用它:

给定以下数据集,

    ASR_API     <- c("CV",  "F",    "IER",  "LS-c", "LS-o")
Human       <- c(NA,    5.8,    12.7,   NA, NA)
Google      <- c(23.2,  24.2,   16.6,   12.1,   28.8)
GoogleCloud <- c(23.3,  26.3,   18.3,   12.3,   27.3)
IBM     <- c(21.8,  47.6,   24.0,   9.8,    25.3)
Microsoft   <- c(29.1,  28.1,   23.1,   18.8,   35.9)
Speechmatics    <- c(19.1,  38.4,   21.4,   7.3,    19.4)
Wit_ai      <- c(35.6,  54.2,   37.4,   19.2,   41.7)
dt     <- data.table(ASR_API,Human, Google, GoogleCloud, IBM, Microsoft, Speechmatics, Wit_ai)
> dt
ASR_API Human Google GoogleCloud  IBM Microsoft Speechmatics Wit_ai
1:      CV    NA   23.2        23.3 21.8      29.1         19.1   35.6
2:       F   5.8   24.2        26.3 47.6      28.1         38.4   54.2
3:     IER  12.7   16.6        18.3 24.0      23.1         21.4   37.4
4:    LS-c    NA   12.1        12.3  9.8      18.8          7.3   19.2
5:    LS-o    NA   28.8        27.3 25.3      35.9         19.4   41.7

规范化的值可以这样得到:

> dtn <- normalize(dt, method = "standardize", range = c(0, 1), margin = 1L, on.constant = "quiet")
> dtn
ASR_API      Human     Google GoogleCloud         IBM  Microsoft Speechmatics      Wit_ai
1:      CV         NA  0.3361245   0.2893457 -0.28468670  0.3247336  -0.18127203 -0.16032655
2:       F -0.7071068  0.4875320   0.7715885  1.59862532  0.1700986   1.55068347  1.31594762
3:     IER  0.7071068 -0.6631646  -0.5143923 -0.12409420 -0.6030768   0.02512682 -0.01746131
4:    LS-c         NA -1.3444981  -1.4788780 -1.16064578 -1.2680075  -1.24018782 -1.46198764
5:    LS-o         NA  1.1840062   0.9323361 -0.02919864  1.3762521  -0.15435044  0.32382788

手工计算方法忽略包含NAs的列:

> dt %>% mutate(normalizedHuman = (Human - mean(Human))/sd(Human)) %>%
+ mutate(normalizedGoogle = (Google - mean(Google))/sd(Google)) %>%
+ mutate(normalizedGoogleCloud = (GoogleCloud - mean(GoogleCloud))/sd(GoogleCloud)) %>%
+ mutate(normalizedIBM = (IBM - mean(IBM))/sd(IBM)) %>%
+ mutate(normalizedMicrosoft = (Microsoft - mean(Microsoft))/sd(Microsoft)) %>%
+ mutate(normalizedSpeechmatics = (Speechmatics - mean(Speechmatics))/sd(Speechmatics)) %>%
+ mutate(normalizedWit_ai = (Wit_ai - mean(Wit_ai))/sd(Wit_ai))
ASR_API Human Google GoogleCloud  IBM Microsoft Speechmatics Wit_ai normalizedHuman normalizedGoogle
1      CV    NA   23.2        23.3 21.8      29.1         19.1   35.6              NA        0.3361245
2       F   5.8   24.2        26.3 47.6      28.1         38.4   54.2              NA        0.4875320
3     IER  12.7   16.6        18.3 24.0      23.1         21.4   37.4              NA       -0.6631646
4    LS-c    NA   12.1        12.3  9.8      18.8          7.3   19.2              NA       -1.3444981
5    LS-o    NA   28.8        27.3 25.3      35.9         19.4   41.7              NA        1.1840062
normalizedGoogleCloud normalizedIBM normalizedMicrosoft normalizedSpeechmatics normalizedWit_ai
1             0.2893457   -0.28468670           0.3247336            -0.18127203      -0.16032655
2             0.7715885    1.59862532           0.1700986             1.55068347       1.31594762
3            -0.5143923   -0.12409420          -0.6030768             0.02512682      -0.01746131
4            -1.4788780   -1.16064578          -1.2680075            -1.24018782      -1.46198764
5             0.9323361   -0.02919864           1.3762521            -0.15435044       0.32382788

(normalizedHuman是一个NAs列表…)

对于计算具体列的选择,可以采用通用的方法,如下所示:

data_vars <- df_full %>% dplyr::select(-ASR_API,-otherVarNotToBeUsed)
meta_vars <- df_full %>% dplyr::select(ASR_API,otherVarNotToBeUsed)
data_varsn <- normalize(data_vars, method = "standardize", range = c(0, 1), margin = 1L, on.constant = "quiet")
dtn <- cbind(meta_vars,data_varsn)

@BBKim给出了最好的答案,但它可以做得更短。我很惊讶居然还没人想到。

< p > <代码> - data.frame(x = rnorm(10, 30, .2), y = runif(10, 3, 5)) - apply(date, 2, function(x) (x - mean(x)) / sd(x)) < /代码> < / p >

崩溃包提供了最快的扩展函数——使用Welfords在线算法在c++中实现:

dat <- data.frame(x = rnorm(1e6, 30, .2),
y = runif(1e6, 3, 5),
z = runif(1e6, 10, 20))


library(collapse)
library(microbenchmark)
microbenchmark(fscale(dat), scale(dat))


Unit: milliseconds
expr       min       lq      mean    median        uq      max neval cld
fscale(dat)  27.86456  29.5864  38.96896  30.80421  43.79045 313.5729   100  a
scale(dat) 357.07130 391.0914 489.93546 416.33626 625.38561 793.2243   100   b

此外:fscale是S3通用的向量,矩阵和数据帧,也支持分组和/或加权缩放操作,以及缩放到任意均值和标准偏差。

下面的代码可能是实现这一目标的最短方法。

dataframe <- apply(dataframe, 2, scale)