Ik heb een dataset met de naam spam
die 58 kolommen en ongeveer 3500 rijen met gegevens met betrekking tot spamberichten bevat.
Ik ben van plan om in de toekomst wat lineaire regressie uit te voeren op deze dataset, maar ik zou graag vooraf wat voorverwerking willen doen en de kolommen standaardiseren om een gemiddelde nul- en eenheidsvariantie te hebben.
Er is mij verteld dat ik dit het beste kan doen met R, dus ik zou graag willen vragen hoe kan ik normalisatie bereiken met R? Ik heb de gegevens al correct geladen en ik ben gewoon op zoek naar enkele pakketten of methoden om deze taak uit te voeren.
Antwoord 1, autoriteit 100%
Ik neem aan dat je bedoelde te zeggen dat je een gemiddelde van 0 en een standaarddeviatie van 1 wilde. Als je gegevens in een dataframe staan en alle kolommen numeriek zijn, kun je eenvoudig de scale
functie op de gegevens om te doen wat je wilt.
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)
Het gebruik van ingebouwde functies is stijlvol. Vind deze kat leuk:
Antwoord 2, autoriteit 18%
Als ik me realiseer dat de vraag oud is en één antwoord is geaccepteerd, geef ik een ander antwoord ter referentie.
scale
wordt beperkt door het feit dat het alle variabelenschaalt. Met de onderstaande oplossing kunnen alleen specifieke variabelenamen worden geschaald terwijl andere variabelen ongewijzigd blijven (en de variabelenamen kunnen dynamisch worden gegenereerd):
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
wat me dit geeft:
> 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
en
> 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): Reactie van Julian beantwoord: de uitvoer van scale
is Nx1-matrix, dus idealiter zouden we een as.vector
moeten toevoegen om het matrixtype weer om te zetten in een vectortype. Bedankt Julian!
EDIT 2 (2019): De opmerking van Duccio A. citeren: Voor de nieuwste dplyr (versie 0.8) moet je dplyr::funcs wijzigen met een lijst, zoals dat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))
EDIT 3 (2020): Met dank aan @mj_whales: de oude oplossing is verouderd en nu moeten we mutate_at
gebruiken.
Antwoord 3, autoriteit 12%
Dit is 3 jaar oud. Toch heb ik het gevoel dat ik het volgende moet toevoegen:
De meest voorkomende normalisatie is de z-transformatie, waarbij u het gemiddelde aftrekt en deelt door de standaarddeviatie van uw variabele. Het resultaat is mean=0 en sd=1.
Daarvoor heb je geen pakket nodig.
zVar <- (myVar - mean(myVar)) / sd(myVar)
Dat is het.
Antwoord 4, autoriteit 4%
Het ‘Caret’-pakket biedt methoden voor het voorbewerken van gegevens (bijv. centreren en schalen). U kunt ook de volgende code gebruiken:
library(caret)
# Assuming goal class is column 10
preObj <- preProcess(data[, -10], method=c("center", "scale"))
newData <- predict(preObj, data[, -10])
Meer details: http://www.inside-r.org/node/86978
Antwoord 5, autoriteit 3%
Toen ik de oplossing van Dason gebruikte, kreeg ik in plaats van een dataframe als resultaat een vector van getallen (de geschaalde waarden van mijn df).
Als iemand hetzelfde probleem heeft, moet je as.data.frame() als volgt aan de code toevoegen:
df.scaled <- as.data.frame(scale(df))
Ik hoop dat dit nuttig is voor mensen die hetzelfde probleem hebben!
Antwoord 6, autoriteit 3%
U kunt de gegevens ook gemakkelijk normaliseren met de functie data.Normalization in clusterSim-pakket. Het biedt verschillende methoden voor gegevensnormalisatie.
data.Normalization (x,type="n0",normalization="column")
Argumenten
x
vector, matrix of dataset
typ
type normalisatie:
n0 – zonder normalisatie
n1 – standaardisatie ((x-mean)/sd)
n2 – positionele standaardisatie ((x-mediaan)/mad)
n3 – unitization ((x-mean)/range)
n3a – positionele eenheidsvorming ((x-mediaan)/bereik)
n4 – unitisatie met nul minimum ((x-min)/bereik)
n5 – normalisatie binnen bereik <-1,1> ((x-mean)/max(abs(x-mean)))
n5a – positionele normalisatie binnen bereik <-1,1> ((x-mediaan)/max(abs(x-mediaan)))
n6 – quotiënttransformatie (x/sd)
n6a – positionele quotiënttransformatie (x/mad)
n7 – quotiënttransformatie (x/bereik)
n8 – quotiënttransformatie (x/max)
n9 – quotiënttransformatie (x/gemiddelde)
n9a – positionele quotiënttransformatie (x/mediaan)
n10 – quotiënttransformatie (x/som)
n11 – quotiënttransformatie (x/sqrt(SSQ))
n12 – normalisatie ((x-mean)/sqrt(sum((x-mean)^2)))
n12a – positionele normalisatie ((x-mediaan)/sqrt(sum((x-mediaan)^2)))
n13 – normalisatie waarbij nul het centrale punt is ((x-midrange)/(range/2))
normalisatie
“column” – normalisatie per variabele, “row” – normalisatie per object
Antwoord 7, autoriteit 3%
Met dplyr
v0.7.4 kunnen alle variabelen worden geschaald met 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
Specifieke variabelen kunnen worden uitgesloten met 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
Gemaakt op 24-04-2018 door het reprex-pakket(v0.2.0).
Antwoord 8, autoriteit 2%
Schaal kan worden gebruikt voor zowel volledige dataframes als specifieke kolommen.
Voor specifieke kolommen kan de volgende code worden gebruikt:
trainingSet[, 3:7] = scale(trainingSet[, 3:7]) # For column 3 to 7
trainingSet[, 8] = scale(trainingSet[, 8]) # For column 8
Volledig gegevensframe
trainingSet <- scale(trainingSet)
Antwoord 9, autoriteit 2%
Nogmaals, ook al is dit een oude vraag, het is zeer relevant! En ik heb een eenvoudige manier gevonden om bepaalde kolommen te normaliseren zonder dat er pakketten nodig zijn:
normFunc <- function(x){(x-mean(x, na.rm = T))/sd(x, na.rm = T)}
Bijvoorbeeld
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)
Je zult zien dat de kolommen y en z zijn genormaliseerd. Geen pakketten nodig 🙂
Antwoord 10
Het pakket dplyr
heeft twee functies die dit doen.
> require(dplyr)
Om specifiekekolommen van een gegevenstabel te muteren, kunt u de functie mutate_at()
gebruiken. Om allekolommen te muteren, kun je mutate_all
gebruiken.
Het volgende is een kort voorbeeld voor het gebruik van deze functies om gegevens te standaardiseren.
Specifieke kolommen muteren:
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
Alle kolommen muteren:
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
Antwoord 11
Voordat ik deze thread toevallig vond, had ik hetzelfde probleem. Ik had gebruikersafhankelijke kolomtypen, dus schreef ik een for
-lus die er doorheen ging en de benodigde kolommen kreeg die scale
‘d. Er zijn waarschijnlijk betere manieren om het te doen, maar dit loste het probleem prima op:
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
is een noodzakelijk onderdeel, omdat bleek dat scale
rownames x 1
matrix doet, wat meestal niet is wat je wilt hebben in uw data.frame
.
Antwoord 12
@BBKim gaf vrijwel het beste antwoord, maar het kan ook korter. Het verbaast me dat nog niemand het heeft bedacht.
dat <- data.frame(x = rnorm(10, 30, .2), y = runif(10, 3, 5))
dat <- apply(dat, 2, function(x) (x - mean(x)) / sd(x))
Antwoord 13
Het collapsepakket biedt de snelste schaalfunctie – geïmplementeerd in C++ met behulp van Welfords Online Algorithm:
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
Bovendien: fscale
is S3 generiek voor vectoren, matrices en dataframes en ondersteunt ook gegroepeerde en/of gewogen schaalbewerkingen, evenals schalen naar willekeurige gemiddelden en standaarddeviaties.
Antwoord 14
Gebruik het pakket “recommenderlab”. Download en installeer het pakket.
Dit pakket heeft een commando “Normalize” ingebouwd. U kunt ook een van de vele methoden voor normalisatie kiezen, namelijk ‘center’ of ‘Z-score’
Volg het volgende voorbeeld:
## 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=”), items=paste('i', 1:10, sep=”)))
## 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")
Antwoord 15
De normaliserenfunctie van het BBMisc-pakket was de juiste tool voor mij omdat het kan omgaan met NA-waarden.
Zo gebruik je het:
Gezien de volgende dataset,
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
genormaliseerde waarden kunnen als volgt worden verkregen:
> 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
waarbij de met de hand berekende methode alleen colmuns negeert die NA’s bevatten:
> 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 heeft een lijst met NA’s gemaakt …)
met betrekking tot de selectie van specifieke kolommen voor berekening, kan een generieke methode worden gebruikt zoals deze:
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)