Standardisieren Sie Datenspalten in R.


209

Ich habe einen Datensatz namens, spamder 58 Spalten und ungefähr 3500 Datenzeilen enthält, die sich auf Spam-Nachrichten beziehen.

Ich habe vor, in Zukunft eine lineare Regression für diesen Datensatz durchzuführen, möchte jedoch vorher eine Vorverarbeitung durchführen und die Spalten so standardisieren, dass sie einen Mittelwert von Null und eine Einheitsvarianz aufweisen.

Mir wurde gesagt, dass der beste Weg, dies zu tun, R ist. Ich möchte also fragen, wie ich mit R eine Normalisierung erreichen kann . Ich habe die Daten bereits richtig geladen und suche nur nach Paketen oder Methoden, um diese Aufgabe auszuführen.

Antworten:


533

Ich muss davon ausgehen, dass Sie sagen wollten, dass Sie einen Mittelwert von 0 und eine Standardabweichung von 1 wollten. Wenn sich Ihre Daten in einem Datenrahmen befinden und alle Spalten numerisch sind, können Sie einfach die scaleFunktion für die Daten aufrufen, um das zu tun, was Sie wollen.

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)

Die Verwendung von integrierten Funktionen ist klassisch. Wie diese Katze:

Geben Sie hier die Bildbeschreibung ein


24
Ja mein Fehler ich meinte 0 bedeuten. Und das ist eine ziemlich noble Katze
Hoser

8
+1 mit anwenden kann auch wie diese fette Katze langsam sein :) (colMeans here)
agstudy

1
@agstudy Fair genug. Ich sollte mir angewöhnen, colMeans / colSums mehr zu verwenden. Ich denke, ich denke nicht daran, es sei denn, ich bin in einer Situation, in der es wirklich darauf ankommt ...
Dason

137
Diese Seite braucht mehr Katzen +1
LoveMeow

35
Warnung: Skala wandelt auch den
Julian Karls

88

Da ich feststelle, dass die Frage alt ist und eine Antwort akzeptiert wird, werde ich eine andere Antwort als Referenz geben.

scalewird durch die Tatsache begrenzt, dass es alle Variablen skaliert . Mit der folgenden Lösung können nur bestimmte Variablennamen skaliert werden, während andere Variablen unverändert bleiben (und die Variablennamen können dynamisch generiert werden):

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

was mir folgendes gibt:

> 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

und

> 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) : Adressiert Julians Kommentar: Die Ausgabe von scaleist eine Nx1-Matrix, daher sollten wir idealerweise eine hinzufügen as.vector, um den Matrixtyp wieder in einen Vektortyp umzuwandeln. Danke Julian!

EDIT 2 (2019) : Zitiert den Kommentar von Duccio A.: Für das neueste dplyr (Version 0.8) müssen Sie dplyr :: funcs mit list ändern, wie zdat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))

EDIT 3 (2020) : Dank @mj_whales: Die alte Lösung ist veraltet und jetzt müssen wir verwenden mutate_at.


Diese Methode funktioniert perfekt, besonders wenn ich eine Kombination aus kategorialen und numerischen Variablen habe. Ich habe nur eine Frage, was dieser Operator "%>%" bedeutet.
Nooshinha

9
@ weber85, es ist ein "Pipe" -Operator (aus der funktionalen Programmierung). Anstatt zu schreiben f(g(x)), würde es schöner aussehen, wenn man schreibt x %>% g %>% f. Mit anderen Worten, dat %>% mutate_each_(funs(scale),vars=c("y","z"))ist gerecht mutate_each_(dat,funs(scale),vars=c("y","z")). Der Bediener hilft sehr, wenn eine Kette sehr lang ist, da f(g(h(i(j(x)))))sie sehr schwer zu lesen ist.
Akhmed

Mit diesem Ansatz werden die Spalten, auf die die Skalierung angewendet wird, von Vektoren (klassennumerisch) auf Nx1-Matrizen übertragen. Dies könnte (und in meinem Fall) einige Fehler in Paketen verursachen, die davon ausgehen, dass jede Spalte eines data.frame ein Vektor ist.
Julian Karls

2
Für die neueste dplyr(Version 0.8) müssen Sie Änderung dplyr::funcsmit list, wiedat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))
Duccio A

2
mutate_each_()ist jetzt veraltet. Sie können mutate_at()stattdessen verwenden. Der neue Weg, dies zu tun, wäre:dat2 <- dat %>% mutate_at(c("y", "z"), scale)
mj_whales

60

Das ist 3 Jahre alt. Trotzdem muss ich Folgendes hinzufügen:

Die häufigste Normalisierung ist die Z-Transformation , bei der Sie den Mittelwert subtrahieren und durch die Standardabweichung Ihrer Variablen dividieren. Das Ergebnis hat Mittelwert = 0 und sd = 1.

Dafür brauchen Sie kein Paket.

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

Das ist es.


Ganz einfach, um dies durchzuführen. Vielen Dank
Pedro Neves

Und macht die Verwendung von dplyr viel einfacher : mutate(var = (var - mean(var))/sd(var)).
RobertMyles

Aber kann dies verwendet werden, um den Z-Score für zwei Variablen zu erhalten?
lf_araujo

zu denormalisieren myVar <- (zVar * sd(zVar)) + mean(zVar), richtig?
Artur_Indio

4
@Artur_Indio Fast : newVar <- (zVar * sd(myVar)) + mean(myVar). Sie müssen den ursprünglichen Mittelwert / sd verwenden. Wie Sie es geschrieben haben, werden Sie mit multiplizieren sd(zVar)=1und hinzufügen mean(zVar)=0, damit sich nichts ändert :)
random_forest_fanatic

24

Das 'Caret'-Paket bietet Methoden zur Vorverarbeitung von Daten (z. B. Zentrieren und Skalieren). Sie können auch den folgenden Code verwenden:

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

Weitere Details: http://www.inside-r.org/node/86978


17

Als ich die von Dason angegebene Lösung verwendete, erhielt ich anstelle eines Datenrahmens einen Vektor von Zahlen (die skalierten Werte meines df).

Wenn jemand die gleichen Probleme hat, müssen Sie dem Code as.data.frame () wie folgt hinzufügen:

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

Ich hoffe, dies ist nützlich für Leute, die das gleiche Problem haben!


Schöne Lösung! Wenn jemand eine Spalte von der Skalierung ausschließen möchte, können Sie dies folgendermaßen tun: train_dt[-24] <- scale(train_dt[-24]) wobei "24" die auszuschließende
Spaltennummer ist

13

Sie können die Daten auch mit data.Normalization-Funktion im clusterSim-Paket problemlos normalisieren. Es bietet verschiedene Methoden zur Datennormalisierung.

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

Argumente

x
Vektor-, Matrix- oder Datensatztyp
Normalisierungstyp: n0 - ohne Normalisierung

n1 - Standardisierung ((x-Mittelwert) / sd)

n2 - Positionsstandardisierung ((x-Median) / verrückt)

n3 - Einheit ((x-Mittelwert) / Bereich)

n3a - Positionseinheit ((x-Median) / Bereich)

n4 - Einheit mit Null Minimum ((x-min) / Bereich)

n5 - Normalisierung im Bereich <-1,1> ((x-Mittelwert) / max (abs (x-Mittelwert)))

n5a - Positionsnormalisierung im Bereich <-1,1> ((x-Median) / max (abs (x-Median)))

n6 - Quotiententransformation (x / sd)

n6a - Positionsquotiententransformation (x / mad)

n7 - Quotiententransformation (x / Bereich)

n8 - Quotiententransformation (x / max)

n9 - Quotiententransformation (x / Mittelwert)

n9a - Positionsquotiententransformation (x / Median)

n10 - Quotiententransformation (x / Summe)

n11 - Quotiententransformation (x / sqrt (SSQ))

n12 - Normalisierung ((x-Mittelwert) / sqrt (Summe ((x-Mittelwert) ^ 2)))

n12a - Positionsnormalisierung ((x-Median) / sqrt (Summe ((x-Median) ^ 2)))

n13 - Normalisierung mit Null als Mittelpunkt ((x-Mittelbereich) / (Bereich / 2))

Normalisierung
"Spalte" - Normalisierung nach Variable, "Zeile" - Normalisierung nach Objekt


Dieses Paket ist nicht verfügbar für R Version 3.4.3
JdP

11

Mit dplyrv0.7.4 können alle Variablen skaliert werden mit 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

Bestimmte Variablen können ausgeschlossen werden mit 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

Erstellt am 24.04.2018 durch das reprex-Paket (v0.2.0).


9

Auch wenn dies eine alte Frage ist, ist sie sehr relevant! Und ich habe einen einfachen Weg gefunden, um bestimmte Spalten zu normalisieren, ohne dass Pakete erforderlich sind:

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

Beispielsweise

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)

Sie werden sehen, dass die Spalten y und z normalisiert wurden. Keine Pakete benötigt :-)


8

Die Skalierung kann sowohl für den vollständigen Datenrahmen als auch für bestimmte Spalten verwendet werden. Für bestimmte Spalten kann folgender Code verwendet werden:

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

Voller Datenrahmen

trainingSet <- scale(trainingSet)

3

Das dplyrPaket hat zwei Funktionen, die dies tun.

> require(dplyr)

Um bestimmte Spalten einer Datentabelle zu mutieren , können Sie die Funktion verwenden mutate_at(). Um alle Spalten zu mutieren , können Sie verwenden mutate_all.

Das Folgende ist ein kurzes Beispiel für die Verwendung dieser Funktionen zum Standardisieren von Daten.

Mutieren Sie bestimmte Spalten:

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 

Mutieren Sie alle Spalten:

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

Bevor ich diesen Thread gefunden habe, hatte ich das gleiche Problem. Ich hatte benutzerabhängige Spaltentypen, also schrieb ich eine forSchleife, die sie durchlief und die benötigten Spalten scaleabrief. Es gibt wahrscheinlich bessere Möglichkeiten, aber dies hat das Problem ganz gut gelöst:

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

as.vectorTeil ist eine notwendige, denn es stellte sich heraus , scaletut rownames x 1Matrix , die in der Regel nicht , was Sie in Ihrem haben wollen data.frame.


0

Verwenden Sie das Paket "recommenderlab". Laden Sie das Paket herunter und installieren Sie es. In diesem Paket ist der Befehl "Normalisieren" eingebaut. Sie können auch eine der vielen Methoden zur Normalisierung auswählen, nämlich 'Mitte' oder 'Z-Score'. Befolgen Sie das folgende Beispiel:

## 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
Diese Antwort geht nicht auf die Frage ein.
f0nzie

0

Die Normalisierungsfunktion aus dem BBMisc-Paket war das richtige Werkzeug für mich, da sie mit NA-Werten umgehen kann.

So verwenden Sie es:

Angesichts des folgenden Datensatzes

    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

normalisierte Werte können wie folgt erhalten werden:

> 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

wobei die von Hand berechnete Methode nur Colmuns ignoriert, die NAs enthalten:

> 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 wird eine Liste von NAs erstellt ...)

In Bezug auf die Auswahl bestimmter Spalten für die Berechnung kann eine generische Methode wie die folgende angewendet werden:

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 gab so ziemlich die beste Antwort, aber es kann nur kürzer gemacht werden. Ich bin überrascht, dass noch niemand darauf gekommen ist.

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.