R'deki veri sütunlarını standartlaştırın


209

spam58 sütun ve spam iletileri ile ilgili yaklaşık 3500 satır içeren bir veri kümesi var .

Gelecekte bu veri kümesinde doğrusal bir regresyon çalıştırmayı planlıyorum, ancak önceden bazı ön işlemler yapmak ve sütunları sıfır ortalama ve birim varyansına sahip olacak şekilde standartlaştırmak istiyorum.

Bu konuda en iyi yolun R ile olduğu söylendi, bu yüzden R ile normalleşmeyi nasıl başarabilirim ? Verileri zaten düzgün bir şekilde yükledim ve sadece bu görevi gerçekleştirmek için bazı paketler veya yöntemler arıyorum.

Yanıtlar:


533

Ortalama 0 ve standart sapma 1 istediğinizi söylemeliyim. Verileriniz bir veri çerçevesinde ve tüm sütunlar sayısalsa, scaleistediğinizi yapmak için verilerdeki işlevi çağırabilirsiniz .

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)

Yerleşik işlevleri kullanmak klastır. Bu kedi gibi:

resim açıklamasını buraya girin


24
Evet hatam 0 demek istedim. Ve bu oldukça klas bir kedi
Hoser

8
Uygulamayı kullanarak +1 kullanmak da bu şişman kedi gibi yavaş olabilir :) (colMeans here)
agstudy

1
@agstudy Yeterince adil. Daha fazla colMeans / colSums kullanma alışkanlığı almalıyım. Sanırım gerçekten önemli bir durum olmadıkça düşünmüyorum ...
Dason

137
bu site daha fazla kediye ihtiyaç duyuyor +1
LoveMeow

35
Uyarı: ölçek ayrıca veri çerçevesini bir matrise dönüştürür
Julian Karls

89

Sorunun eski olduğunu ve bir cevabın kabul edildiğini fark ederek, referans için başka bir cevap vereceğim.

scaletüm değişkenleri ölçeklendirmesi ile sınırlıdır . Aşağıdaki çözüm, diğer değişkenleri değiştirmeden korurken yalnızca belirli değişken adlarının ölçeklendirilmesine izin verir (ve değişken adları dinamik olarak oluşturulabilir):

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

hangi bana bunu verir:

> 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

ve

> 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) : Julian'ın scaleyorumuna hitap etti : çıktısı Nx1 matrisidir, bu yüzden ideal as.vectorolarak matris tipini vektör tipine dönüştürmek için bir eklememiz gerekir . Teşekkürler Julian!

EDIT 2 (2019) : Alıntı Duccio A.'nın yorumu: En son dplyr (sürüm 0.8) için dplyr :: funcs with list,dat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))

EDIT 3 (2020) : @mj_whales sayesinde: eski çözüm kullanımdan kaldırıldı ve şimdi kullanmamız gerekiyor mutate_at.


Bu yöntem, özellikle kategorik ve sayısal değişkenlerin kombinasyonuna sahip olduğumda mükemmel çalışır. Sadece bir sorum var bu operatör "%>%" ne anlama geliyor?
nooshinha

9
@ weber85, bir "boru" operatörüdür (fonksiyonel programlamadan). f(g(x))Biri yazmak yerine yazmak yerine daha güzel görünecektir x %>% g %>% f. Başka bir deyişle, dat %>% mutate_each_(funs(scale),vars=c("y","z"))sadece mutate_each_(dat,funs(scale),vars=c("y","z")). Bir zincir çok uzun olduğunda operatör çok yardımcı f(g(h(i(j(x)))))olabilir çünkü okunması çok zor olabilir.
Ahmed

Bu yaklaşım kullanılarak ölçeğin uygulandığı sütunlar vektörden (sınıf sayısal) Nx1 matrislerine aktarılır. Bu (ve benim durumumda) bir data.frame her sütunun bir vektör olduğunu varsayar paketleri bazı hatalara neden olabilir.
Julian Karls

2
Son İçin dplyr(0.8 versiyonu) Eğer değişime ihtiyaç dplyr::funcsile listolduğu gibi,dat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))
Duccio A

2
mutate_each_()artık kullanımdan kaldırıldı. Bunun mutate_at()yerine kullanabilirsiniz . Bunu yapmanın yeni yolu şöyle olurdu:dat2 <- dat %>% mutate_at(c("y", "z"), scale)
mj_whales

60

Bu 3 yaşında. Yine de, aşağıdakileri eklemem gerektiğini hissediyorum:

En yaygın normalleştirme, ortalamayı çıkarttığınız ve değişkeninizin standart sapmasına bölündüğünüz z-dönüşümüdür . Sonuç ortalama = 0 ve sd = 1 olacaktır.

Bunun için herhangi bir pakete ihtiyacınız yok.

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

Bu kadar.


Bunu yapmanın tamamen basit bir yolu. Teşekkürler
Pedro Neves

Ve bunu kullanarak markaları çok daha kolay dplyr: mutate(var = (var - mean(var))/sd(var)).
RobertMyles

Ancak bu, iki değişken için z skorunu elde etmek için kullanılabilir mi?
lf_araujo

denormalize etmek myVar <- (zVar * sd(zVar)) + mean(zVar), değil mi?
Artur_Indio

4
Neredeyse @Artur_Indio: newVar <- (zVar * sd(myVar)) + mean(myVar). Orijinal ortalama / sd'yi kullanmalısınız. sd(zVar)=1mean(zVar)=0
Yazdıkça

24

'Caret' paketi, verileri ön işleme yöntemleri (örn. Merkezleme ve ölçeklendirme) sağlar. Aşağıdaki kodu da kullanabilirsiniz:

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

Daha fazla detay: http://www.inside-r.org/node/86978


17

Dason tarafından belirtilen çözümü kullandığımda, sonuç olarak bir veri çerçevesi elde etmek yerine, bir sayı vektörü aldım (df'nin ölçeklenmiş değerleri).

Birisi aynı sorunu yaşıyorsa, koda as.data.frame () eklemeniz gerekir, şöyle:

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

Umarım bu aynı sorunu olan ppl için yararlı olacaktır!


Güzel çözüm! Birisi bir sütunun ölçeklendirilmesini istemezse bunu şu şekilde yapabilirsiniz: train_dt[-24] <- scale(train_dt[-24]) burada "24" hariç tutulacak sütun numarasıdır
NetEmmanuel

13

ClusterSim paketindeki normalleştirme işlevi ile verileri kullanarak verileri kolayca normalleştirebilirsiniz. Farklı veri normalleştirme yöntemi sağlar.

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

Argümanlar

x
vektör, matris veya veri kümesi tipi
normalleştirme türü: n0 - normalleştirme olmadan

n1 - standardizasyon ((x-ortalama) / sd)

n2 - konumsal standardizasyon ((x-medyan) / deli)

n3 - birimleştirme ((x-ortalama) / aralık)

n3a - konumsal birimleştirme ((x-medyan) / aralık)

n4 - sıfır minimum ((x-min) / aralık) ile birimizasyon

n5 - <-1,1> aralığında normalleştirme ((x-ortalama) / maks (abs (x-ortalama)))

n5a - <-1,1> aralığında konumsal normalleştirme ((x-medyan) / maks (abs (x-medyan)))

n6 - bölüm dönüşümü (x / sd)

n6a - konumsal bölüm dönüşümü (x / deli)

n7 - bölüm dönüşümü (x / aralık)

n8 - bölüm dönüşümü (x / maks)

n9 - bölüm dönüşümü (x / ortalama)

n9a - konumsal bölüm dönüşümü (x / medyan)

n10 - bölüm dönüşümü (x / toplam)

n11 - bölüm dönüşümü (x / sqrt (SSQ))

n12 - normalleştirme ((x-ortalama) / sqrt (toplam ((x-ortalama) ^ 2)))

n12a - konumsal normalleştirme ((x-medyan) / sqrt (toplam ((x-medyan) ^ 2)))

n13 - sıfırın merkezi nokta olduğu normalleştirme ((x-orta kademe) / (aralık / 2))

normalleştirme
"sütun" - değişken ile normalleştirme, "satır" - nesneye göre normalleştirme


bu paket R sürüm 3.4.3 için mevcut değildir
JdP

11

İle dplyrv0.7.4 tüm değişkenler kullanılarak ölçeklenebilir 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

Belirli değişkenler aşağıdakiler kullanılarak hariç tutulabilir 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

2018-04-24 tarihinde reprex paketi (v0.2.0) tarafından oluşturuldu .


9

Yine, bu eski bir soru olsa da, çok alakalı! Ve herhangi bir pakete ihtiyaç duymadan belirli sütunları normalleştirmenin basit bir yolunu buldum:

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

Örneğin

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 ve z sütunlarının normalleştirildiğini göreceksiniz. Paket gerekmez :-)


8

Ölçek hem tam veri çerçevesi hem de belirli sütunlar için kullanılabilir. Belirli sütunlar için aşağıdaki kod kullanılabilir:

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

Tam veri çerçevesi

trainingSet <- scale(trainingSet)

3

dplyrPaket Bunun için, iki fonksiyona sahiptir.

> require(dplyr)

Bir veri tablosunun belirli sütunlarını değiştirmek için işlevi kullanabilirsiniz mutate_at(). Tüm sütunları değiştirmek için kullanabilirsiniz mutate_all.

Aşağıda, verileri standartlaştırmak için bu işlevlerin kullanımına ilişkin kısa bir örnek verilmiştir.

Belirli sütunları değiştir:

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üm sütunları değiştir:

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

Bu konuyu bulamadan önce aynı sorunu yaşadım. Kullanıcıya bağlı sütun türleri vardı, bu yüzden foronları üzerinden geçen ve gerekli sütunları elde bir döngü yazdım scale'd. Muhtemelen bunu yapmanın daha iyi yolları vardır, ancak bu sorunu iyi çözdü:

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

as.vectorO döndü, çünkü bir gerekli bir parçasıdır scaleyapar rownames x 1aşağıdaki konularda olmasını istediğiniz genellikle ne değildir matrisi data.frame.


0

"Recommenderlab" paketini kullanın. Paketi indirin ve yükleyin. Bu paket yerleşik "Normalize" komutuna sahiptir. Ayrıca, normalleştirme için 'merkez' veya 'Z-puanı' gibi birçok yöntemden birini seçmenize izin verir Aşağıdaki örneği izleyin:

## 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
Bu cevap soruyu ele almıyor.
f0nzie

0

Normalleştirmek o NA değerlerle başa beri BBMisc paketinden işlevi benim için doğru bir araç oldu.

İşte nasıl kullanılır:

Aşağıdaki veri kümesi göz önüne alındığında,

    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

normalize edilmiş değerler şu şekilde elde edilebilir:

> 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

burada hesaplanan yöntem sadece NA içeren colmunları göz ardı eder:

> 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

(normalleştirilmişİnsan NA'ların bir listesi haline getirilir ...)

hesaplama için belirli sütunların seçimiyle ilgili olarak, aşağıdaki gibi genel bir yöntem kullanılabilir:

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 hemen hemen en iyi cevabı verdi, ancak daha kısa yapılabilir. Henüz kimse gelmedi şaşırdım.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.