Chuẩn hóa các cột dữ liệu trong R


209

Tôi có một bộ dữ liệu được gọi spamchứa 58 cột và khoảng 3500 hàng dữ liệu liên quan đến tin nhắn rác.

Tôi dự định chạy một số hồi quy tuyến tính trên bộ dữ liệu này trong tương lai, nhưng tôi muốn thực hiện một số tiền xử lý trước và chuẩn hóa các cột để có giá trị trung bình và phương sai đơn vị bằng không.

Tôi đã được cho biết cách tốt nhất để giải quyết vấn đề này là với R, vì vậy tôi muốn hỏi làm thế nào tôi có thể đạt được sự bình thường hóa với R ? Tôi đã tải dữ liệu đúng cách và tôi chỉ tìm kiếm một số gói hoặc phương thức để thực hiện tác vụ này.

Câu trả lời:


533

Tôi phải giả sử rằng bạn muốn nói rằng bạn muốn có giá trị trung bình là 0 và độ lệch chuẩn là 1. Nếu dữ liệu của bạn nằm trong một khung dữ liệu và tất cả các cột là số, bạn chỉ cần gọi scalehàm trên dữ liệu để làm những gì bạn muốn.

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)

Sử dụng các chức năng được xây dựng là sang trọng. Giống như con mèo này:

nhập mô tả hình ảnh ở đây


24
Có sai lầm của tôi tôi có nghĩa là 0 có nghĩa. Và đó là một con mèo khá sang trọng
Hoser

8
+1 sử dụng áp dụng cũng có thể chậm như con mèo béo này :) (colMeans here)
agstudy

1
@agstudy Hội chợ đủ rồi. Tôi nên có thói quen sử dụng colMeans / colSums nhiều hơn. Tôi đoán tôi không nghĩ về điều đó trừ khi tôi ở trong một tình huống thực sự quan trọng ...
Dason

137
trang web này cần nhiều mèo hơn +1
LoveMeow

35
Cảnh báo: scale cũng biến khung dữ liệu thành ma trận
Julian Karls

88

Nhận ra rằng câu hỏi đã cũ và một câu trả lời được chấp nhận, tôi sẽ cung cấp một câu trả lời khác để tham khảo.

scalebị giới hạn bởi thực tế là nó quy mô tất cả các biến . Giải pháp bên dưới chỉ cho phép chia tỷ lệ tên biến cụ thể trong khi vẫn giữ nguyên các biến khác (và tên biến có thể được tạo động):

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

cung cấp cho tôi điều này:

> 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

EDIT 1 (2016) : Nhận xét của Julian được đánh địa chỉ: đầu ra của scalema trận Nx1 vì vậy lý tưởng nhất là chúng ta nên thêm một as.vectorđể chuyển đổi loại ma trận trở lại thành một loại vectơ. Cảm ơn Julian!

EDIT 2 (2019) : Trích dẫn nhận xét của Duccio A .: Đối với dplyr mới nhất (phiên bản 0.8), bạn cần thay đổi dplyr :: funcs với danh sách, nhưdat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))

EDIT 3 (2020) : Nhờ @mj_whales: giải pháp cũ không được chấp nhận và bây giờ chúng tôi cần sử dụng mutate_at.


Phương pháp này hoạt động hoàn hảo, đặc biệt khi tôi có sự kết hợp của các biến phân loại và số. Tôi chỉ có một câu hỏi toán tử này có nghĩa là gì "%>%"?
nooshinha

9
@ weber85, nó là toán tử "pipe" (từ lập trình chức năng). Thay vì viết f(g(x))nó sẽ đẹp hơn nếu người ta viết x %>% g %>% f. Nói cách khác, dat %>% mutate_each_(funs(scale),vars=c("y","z"))chỉ là mutate_each_(dat,funs(scale),vars=c("y","z")). Toán tử giúp rất nhiều khi một chuỗi rất dài vì f(g(h(i(j(x)))))có thể rất khó đọc.
akhmed

Sử dụng phương pháp này, các cột trên thang đo được áp dụng được chuyển từ vectơ (số lớp) sang ma trận Nx1. Điều này có thể (và trong trường hợp của tôi đã làm) gây ra một số lỗi trong các gói giả sử mỗi cột của data.frame là một vectơ.
Julian Karls

2
Đối với các mới nhất dplyr(phiên bản 0.8), bạn cần phải thay đổi dplyr::funcsvới list, giống nhưdat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))
Duccio Một

2
mutate_each_()bây giờ không được dùng nữa Bạn có thể sử dụng mutate_at()thay thế. Cách mới để làm điều đó sẽ là:dat2 <- dat %>% mutate_at(c("y", "z"), scale)
mj_whales

60

Đây là 3 tuổi. Tuy nhiên, tôi cảm thấy tôi phải thêm vào như sau:

Chuẩn hóa phổ biến nhất là phép biến đổi z , trong đó bạn trừ giá trị trung bình và chia cho độ lệch chuẩn của biến. Kết quả sẽ có giá trị trung bình = 0 và sd = 1.

Đối với điều đó, bạn không cần bất kỳ gói.

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

Đó là nó.


Hoàn toàn là một cách đơn giản để thực hiện điều này. Cảm ơn
Pedro Neves

Và làm cho việc sử dụng nó dplyr dễ dàng hơn nhiều : mutate(var = (var - mean(var))/sd(var)).
RobertMyles

Nhưng điều này có thể được sử dụng để có được điểm z cho hai biến không?
lf_araujo

để không chuẩn hóa myVar <- (zVar * sd(zVar)) + mean(zVar), phải không?
Artur_Indio

4
@Artur_Indio Hầu như : newVar <- (zVar * sd(myVar)) + mean(myVar). Bạn phải sử dụng trung bình / sd ban đầu. Khi bạn viết nó, bạn sẽ nhân lên sd(zVar)=1và thêm vào mean(zVar)=0, vì vậy sẽ không có gì thay đổi :)
Random_forest_fanatic

24

Gói 'Caret' cung cấp các phương thức để xử lý trước dữ liệu (ví dụ: định tâm và chia tỷ lệ). Bạn cũng có thể sử dụng mã sau đây:

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

Thêm chi tiết: http://www.inside-r.org/node/86978


17

Khi tôi sử dụng giải pháp được nêu bởi Dason, thay vì lấy khung dữ liệu, tôi nhận được một vectơ số (các giá trị tỷ lệ của df của tôi).

Trong trường hợp ai đó gặp rắc rối tương tự, bạn phải thêm as.data.frame () vào mã, như thế này:

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

Tôi hy vọng điều này sẽ hữu ích cho ppl có cùng một vấn đề!


Giải pháp tốt đẹp! Trong trường hợp ai đó muốn loại trừ một cột khỏi tỷ lệ, bạn có thể làm như thế này: train_dt[-24] <- scale(train_dt[-24]) trong đó "24" là số cột cần loại trừ
NetEmmanuel

13

Bạn cũng có thể dễ dàng bình thường hóa dữ liệu bằng cách sử dụng chức năng data. Chuẩn hóa trong gói clusterSim. Nó cung cấp phương pháp bình thường hóa dữ liệu khác nhau.

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

Tranh luận

x
vector, ma trận hoặc loại dữ liệu loại
chuẩn hóa: n0 - không chuẩn hóa

n1 - tiêu chuẩn hóa ((trung bình x) / sd)

n2 - tiêu chuẩn hóa vị trí ((x-median) / mad)

n3 - đơn vị hóa ((x-mean) / phạm vi)

n3a - đơn vị vị trí ((x-median) / phạm vi)

n4 - đơn vị hóa với mức tối thiểu bằng không ((x-min) / phạm vi)

n5 - chuẩn hóa trong phạm vi <-1,1> ((x-mean) / max (abs (x-mean)))

n5a - chuẩn hóa vị trí trong phạm vi <-1,1> ((x-median) / max (abs (x-median)))

n6 - biến đổi thương số (x / sd)

n6a - chuyển đổi thương số vị trí (x / mad)

n7 - biến đổi thương số (x / phạm vi)

n8 - biến đổi thương số (x / max)

n9 - biến đổi thương số (x / trung bình)

n9a - chuyển đổi thương số vị trí (x / trung vị)

n10 - biến đổi thương số (x / tổng)

n11 - chuyển đổi thương số (x / sqrt (SSQ))

n12 - chuẩn hóa ((x-mean) / sqrt (sum ((x-mean) ^ 2)))

n12a - chuẩn hóa vị trí ((x-median) / sqrt (sum ((x-median) ^ 2)))

n13 - chuẩn hóa với 0 là điểm trung tâm ((x-midrange) / (phạm vi / 2))

chuẩn hóa
"cột" - chuẩn hóa theo biến, "hàng" - chuẩn hóa theo đối tượng


gói này không có sẵn cho phiên bản R 3.4.3
JdP

11

Với dplyrv0.7.4, tất cả các biến có thể được thu nhỏ bằng cách sử dụng 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

Các biến cụ thể có thể được loại trừ bằng cách sử dụng 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

Được tạo vào ngày 2018-04-24 bởi gói reprex (v0.2.0).


9

Một lần nữa, mặc dù đây là một câu hỏi cũ, nó rất phù hợp! Và tôi đã tìm thấy một cách đơn giản để bình thường hóa các cột nhất định mà không cần bất kỳ gói nào:

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

Ví dụ

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)

Bạn sẽ thấy các cột y và z đã được chuẩn hóa. Không có gói cần thiết :-)


8

Tỷ lệ có thể được sử dụng cho cả khung dữ liệu đầy đủ và các cột cụ thể. Đối với các cột cụ thể, mã sau có thể được sử dụng:

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

Khung dữ liệu đầy đủ

trainingSet <- scale(trainingSet)

3

Các dplyrgói có hai chức năng mà làm điều này.

> require(dplyr)

Để thay đổi các cột cụ thể của bảng dữ liệu, bạn có thể sử dụng hàm mutate_at(). Để thay đổi tất cả các cột, bạn có thể sử dụng mutate_all.

Sau đây là một ví dụ ngắn gọn để sử dụng các chức năng này để chuẩn hóa dữ liệu.

Đột biến các cột cụ thể:

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 

Đột biến tất cả các cột:

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 

1

Trước khi tôi tình cờ tìm thấy chủ đề này, tôi đã có cùng một vấn đề. Tôi có các loại cột phụ thuộc người dùng, vì vậy tôi đã viết một forvòng lặp đi qua chúng và nhận các cột cần thiết scale'd. Có lẽ có nhiều cách tốt hơn để làm điều đó, nhưng điều này đã giải quyết vấn đề tốt:

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

as.vectorlà một phần cần thiết, bởi vì nó bật ra scalelàm rownames x 1ma trận mà thường không phải là những gì bạn muốn có trong bạn data.frame.


0

Sử dụng gói "recommenderlab". Tải về và cài đặt gói. Gói này có lệnh "Bình thường hóa" được xây dựng. Nó cũng cho phép bạn chọn một trong nhiều phương pháp để chuẩn hóa là 'centre' hoặc 'Z-points' Thực hiện theo ví dụ sau:

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

1
Câu trả lời này không giải quyết câu hỏi.
f0nzie

0

Hàm chuẩn hóa từ gói BBMisc là công cụ phù hợp với tôi vì nó có thể xử lý các giá trị NA.

Đây là cách sử dụng nó:

Cho tập dữ liệu sau,

    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

giá trị chuẩn hóa có thể thu được như thế này:

> 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

trong đó phương pháp tính toán tay chỉ bỏ qua colmun chứa NA:

> 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 được tạo một danh sách các NA ...)

liên quan đến việc lựa chọn các cột cụ thể để tính toán, một phương pháp chung có thể được sử dụng như thế này:

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)

0

@BBKim khá nhiều đã đưa ra câu trả lời tốt nhất, nhưng nó chỉ có thể được thực hiện ngắn hơn. Tôi ngạc nhiên khi không có ai nghĩ ra nó.

dat <- data.frame(x = rnorm(10, 30, .2), y = runif(10, 3, 5)) dat <- apply(dat, 2, function(x) (x - mean(x)) / sd(x))

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.