R Language
Factoren
Zoeken…
Syntaxis
- factor (x = teken (), niveaus, labels = niveaus, uitsluiten = NA, geordend = is geordend (x), nmax = NA)
- Run
?factor
of bekijk de documentatie online.
Opmerkingen
Een object met factor
is een vector met een bepaalde set kenmerken.
- Het wordt intern opgeslagen als een
integer
vector. - Het behoudt een
levels
toont de karakterrepresentatie van de waarden. - De klasse wordt opgeslagen als
factor
Laten we ter illustratie een vector van 1.000 observaties genereren uit een set kleuren.
set.seed(1)
Color <- sample(x = c("Red", "Blue", "Green", "Yellow"),
size = 1000,
replace = TRUE)
Color <- factor(Color)
We kunnen elk van de hierboven genoemde kenmerken van Color
observeren:
#* 1. It is stored internally as an `integer` vector
typeof(Color)
[1] "integer"
#* 2. It maintains a `levels` attribute the shows the character representation of the values.
#* 3. Its class is stored as `factor`
attributes(Color)
$levels [1] "Blue" "Green" "Red" "Yellow" $class [1] "factor"
Het primaire voordeel van een factorobject is efficiëntie bij gegevensopslag. Een geheel getal heeft minder geheugen nodig om op te slaan dan een karakter. Een dergelijke efficiëntie was zeer wenselijk wanneer veel computers veel beperktere middelen hadden dan huidige machines (voor een meer gedetailleerde geschiedenis van de motivaties achter het gebruik van factoren, zie stringsAsFactors
: an Unauthorized Biography ). Het verschil in geheugengebruik is zelfs zichtbaar in ons object Color
. Zoals je ziet, vereist het opslaan van Color
als een personage ongeveer 1,7 keer zoveel geheugen als het factorobject.
#* Amount of memory required to store Color as a factor.
object.size(Color)
4624 bytes
#* Amount of memory required to store Color as a character
object.size(as.character(Color))
8232 bytes
Het gehele getal in kaart brengen
Terwijl de interne berekening van factoren het object als een geheel getal ziet, is de gewenste weergave voor menselijke consumptie het tekenniveau. Bijvoorbeeld,
head(Color)
[1] Blue Blue Green Yellow Red Yellow Levels: Blue Green Red Yellow
is gemakkelijker voor het menselijk begrip dan
head(as.numeric(Color))
[1] 1 1 2 4 3 4
Een illustratie bij benadering van hoe R de tekenrepresentatie aanpast aan de interne gehele waarde is:
head(levels(Color)[as.numeric(Color)])
[1] "Blue" "Blue" "Green" "Yellow" "Red" "Yellow"
Vergelijk deze resultaten met
head(Color)
[1] Blue Blue Green Yellow Red Yellow Levels: Blue Green Red Yellow
Modern gebruik van factoren
In 2007 introduceerde R een hash-methode voor tekens om de geheugenlast van stringsAsFactors
verminderen (ref: stringsAsFactors
: an Unauthorized Biography ). Merk op dat toen we bepaalden dat karakters 1,7 keer meer opslagruimte nodig hebben dan factoren, dat werd berekend in een recente versie van R, wat betekent dat het geheugengebruik van karaktervectoren nog zwaarder was vóór 2007.
Vanwege de hashing-methode in moderne R en veel grotere geheugenbronnen in moderne computers, is de kwestie van geheugenefficiëntie bij het opslaan van karakterwaarden teruggebracht tot een zeer kleine zorg. De heersende houding in de R-Gemeenschap is een voorkeur voor karaktervectoren boven factoren in de meeste situaties. De belangrijkste oorzaken voor de verschuiving van factoren zijn
- De toename van ongestructureerde en / of los gecontroleerde karaktergegevens
- De neiging van factoren om zich niet naar wens te gedragen wanneer de gebruiker vergeet dat ze te maken heeft met een factor en niet met een personage
In het eerste geval heeft het geen zin om vrije tekst of open responsvelden als factoren op te slaan, omdat er onwaarschijnlijk een patroon is dat meer dan één observatie per niveau mogelijk maakt. Als alternatief, als de gegevensstructuur niet zorgvuldig wordt beheerd, is het mogelijk om meerdere niveaus te krijgen die overeenkomen met dezelfde categorie (zoals "blauw", "Blauw" en "BLAUW"). In dergelijke gevallen geven velen er de voorkeur aan deze verschillen als tekens te beheren voordat ze worden omgezet in een factor (als de conversie überhaupt plaatsvindt).
In het tweede geval, als de gebruiker denkt dat ze met een tekenvector werkt, reageren bepaalde methoden mogelijk niet zoals verwacht. Dit basiskennis kan leiden tot verwarring en frustratie tijdens het debuggen van scripts en codes. Hoewel dit strikt genomen als de fout van de gebruiker kan worden beschouwd, vermijden de meeste gebruikers graag factoren te gebruiken en deze situaties helemaal te vermijden.
Basiscreatie van factoren
Factoren zijn een manier om categorische variabelen in R weer te geven. Een factor wordt intern opgeslagen als een vector van gehele getallen . De unieke elementen van de geleverde karaktervector staan bekend als de niveaus van de factor. Als de niveaus niet door de gebruiker worden geleverd, genereert R standaard de set unieke waarden in de vector, sorteert deze waarden alfanumeriek en gebruikt ze als niveaus.
charvar <- rep(c("n", "c"), each = 3)
f <- factor(charvar)
f
levels(f)
> f
[1] n n n c c c
Levels: c n
> levels(f)
[1] "c" "n"
Als u de volgorde van de niveaus wilt wijzigen, is er een optie om de niveaus handmatig op te geven:
levels(factor(charvar, levels = c("n","c")))
> levels(factor(charvar, levels = c("n","c")))
[1] "n" "c"
Factoren hebben een aantal eigenschappen. Aan niveaus kunnen bijvoorbeeld labels worden gegeven:
> f <- factor(charvar, levels=c("n", "c"), labels=c("Newt", "Capybara"))
> f
[1] Newt Newt Newt Capybara Capybara Capybara
Levels: Newt Capybara
Een andere eigenschap die kan worden toegewezen, is of de factor is besteld:
> Weekdays <- factor(c("Monday", "Wednesday", "Thursday", "Tuesday", "Friday", "Sunday", "Saturday"))
> Weekdays
[1] Monday Wednesday Thursday Tuesday Friday Sunday Saturday
Levels: Friday Monday Saturday Sunday Thursday Tuesday Wednesday
> Weekdays <- factor(Weekdays, levels=c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), ordered=TRUE)
> Weekdays
[1] Monday Wednesday Thursday Tuesday Friday Sunday Saturday
Levels: Monday < Tuesday < Wednesday < Thursday < Friday < Saturday < Sunday
Wanneer een droplevels()
niet meer wordt gebruikt, kunt u deze neerzetten met de functie droplevels()
:
> Weekend <- subset(Weekdays, Weekdays == "Saturday" | Weekdays == "Sunday")
> Weekend
[1] Sunday Saturday
Levels: Monday < Tuesday < Wednesday < Thursday < Friday < Saturday < Sunday
> Weekend <- droplevels(Weekend)
> Weekend
[1] Sunday Saturday
Levels: Saturday < Sunday
Factorniveaus consolideren met een lijst
Er zijn tijden waarin het wenselijk is om factorniveaus in minder groepen te consolideren, misschien vanwege schaarse gegevens in een van de categorieën. Het kan ook voorkomen als u spelling of hoofdletters van de categorienamen hebt. Beschouw als een voorbeeld de factor
set.seed(1)
colorful <- sample(c("red", "Red", "RED", "blue", "Blue", "BLUE", "green", "gren"),
size = 20,
replace = TRUE)
colorful <- factor(colorful)
Omdat R hoofdlettergevoelig is, zou een frequentietabel van deze vector er als volgt uitzien.
table(colorful)
colorful blue Blue BLUE green gren red Red RED 3 1 4 2 4 1 3 2
Deze tabel geeft echter niet de werkelijke verdeling van de gegevens weer en de categorieën kunnen effectief worden teruggebracht tot drie soorten: Blauw, Groen en Rood. Er worden drie voorbeelden gegeven. De eerste illustreert wat een voor de hand liggende oplossing lijkt, maar geen oplossing zal bieden. De tweede geeft een werkende oplossing, maar is uitgebreid en rekenkundig duur. De derde is geen voor de hand liggende oplossing, maar is relatief compact en rekenkundig efficiënt.
Niveaus consolideren met factor
( factor_approach
)
factor(as.character(colorful),
levels = c("blue", "Blue", "BLUE", "green", "gren", "red", "Red", "RED"),
labels = c("Blue", "Blue", "Blue", "Green", "Green", "Red", "Red", "Red"))
[1] Green Blue Red Red Blue Red Red Red Blue Red Green Green Green Blue Red Green [17] Red Green Green Red Levels: Blue Blue Blue Green Green Red Red Red Warning message: In `levels<-`(`*tmp*`, value = if (nl == nL) as.character(labels) else paste0(labels, : duplicated levels in factors are deprecated
Merk op dat er dubbele niveaus zijn. We hebben nog steeds drie categorieën voor "Blauw", wat onze taak van het consolideren van niveaus niet voltooit. Bovendien is er een waarschuwing dat dubbele niveaus zijn verouderd, wat betekent dat deze code in de toekomst een fout kan genereren.
Niveaus consolideren met ifelse
( ifelse_approach
)
factor(ifelse(colorful %in% c("blue", "Blue", "BLUE"),
"Blue",
ifelse(colorful %in% c("green", "gren"),
"Green",
"Red")))
[1] Green Blue Red Red Blue Red Red Red Blue Red Green Green Green Blue Red Green [17] Red Green Green Red Levels: Blue Green Red
Deze code genereert het gewenste resultaat, maar vereist het gebruik van geneste ifelse
instructies. Hoewel er niets mis is met deze aanpak, kan het beheren van geneste ifelse
verklaringen een vervelend karwei zijn en moet dit zorgvuldig worden gedaan.
Factorenniveaus consolideren met een lijst ( list_approach
)
Een minder voor de hand liggende manier om niveaus te consolideren is om een lijst te gebruiken waarbij de naam van elk element de gewenste categorienaam is en het element een tekenvector is van de niveaus in de factor die moet worden toegewezen aan de gewenste categorie. Dit heeft als bijkomend voordeel dat direct aan het levels
attribuut van de factor, zonder toe te wijzen nieuwe objecten.
levels(colorful) <-
list("Blue" = c("blue", "Blue", "BLUE"),
"Green" = c("green", "gren"),
"Red" = c("red", "Red", "RED"))
[1] Green Blue Red Red Blue Red Red Red Blue Red Green Green Green Blue Red Green [17] Red Green Green Red Levels: Blue Green Red
Benchmarking van elke benadering
De tijd die nodig is om elk van deze benaderingen uit te voeren, wordt hieronder samengevat. (Omwille van de ruimte wordt de code om deze samenvatting te genereren niet getoond)
Unit: microseconds expr min lq mean median uq max neval cld factor 78.725 83.256 93.26023 87.5030 97.131 218.899 100 b ifelse 104.494 107.609 123.53793 113.4145 128.281 254.580 100 c list_approach 49.557 52.955 60.50756 54.9370 65.132 138.193 100 a
De ifelse
loopt ongeveer twee keer zo snel als de ifelse
benadering. Echter, behalve in tijden van zeer, zeer grote hoeveelheden gegevens, zullen de verschillen in uitvoeringstijd waarschijnlijk worden gemeten in microseconden of milliseconden. Met zulke kleine tijdsverschillen hoeft efficiëntie geen leidraad te zijn bij de beslissing welke aanpak te gebruiken. Gebruik in plaats daarvan een vertrouwde en comfortabele aanpak die u en uw medewerkers bij toekomstige beoordelingen zullen begrijpen.
Factoren
Factoren zijn een methode om categorische variabelen in R weer te geven. Gegeven een vector x
waarvan de waarden kunnen worden geconverteerd naar tekens met behulp van as.character()
, as.character()
de standaardargumenten voor factor()
en as.factor()
een geheel getal toe aan elk afzonderlijk element van de vector evenals een niveaukenmerk en een labelkenmerk. Niveaus zijn de waarden x
mogelijk kunnen worden gebruikt en labels kunnen het gegeven element zijn of worden bepaald door de gebruiker.
Om bijvoorbeeld te werken hoe factoren werken, maken we een factor met standaardattributen, vervolgens aangepaste niveaus en vervolgens aangepaste niveaus en labels.
# standard
factor(c(1,1,2,2,3,3))
[1] 1 1 2 2 3 3
Levels: 1 2 3
Er kunnen situaties optreden waarbij de gebruiker weet dat het aantal mogelijke waarden dat een factor kan aannemen groter is dan de huidige waarden in de vector. Hiervoor wijzen we de niveaus zelf in factor()
.
factor(c(1,1,2,2,3,3),
levels = c(1,2,3,4,5))
[1] 1 1 2 2 3 3
Levels: 1 2 3 4 5
Voor stijldoeleinden kan de gebruiker labels aan elk niveau toewijzen. Standaard zijn labels de karakterweergave van de niveaus. Hier wijzen we labels toe voor elk van de mogelijke niveaus in de factor.
factor(c(1,1,2,2,3,3),
levels = c(1,2,3,4,5),
labels = c("Fox","Dog","Cow","Brick","Dolphin"))
[1] Fox Fox Dog Dog Cow Cow
Levels: Fox Dog Cow Brick Dolphin
Normaal kunnen factoren alleen worden vergeleken met ==
en !=
En als de factoren dezelfde niveaus hebben. De volgende vergelijking van factoren mislukt, hoewel ze gelijk lijken, omdat de factoren verschillende factorniveaus hebben.
factor(c(1,1,2,2,3,3),levels = c(1,2,3)) == factor(c(1,1,2,2,3,3),levels = c(1,2,3,4,5))
Error in Ops.factor(factor(c(1, 1, 2, 2, 3, 3), levels = c(1, 2, 3)), :
level sets of factors are different
Dit is logisch omdat de extra niveaus in de RHS betekenen dat R niet voldoende informatie over elke factor heeft om ze op een zinvolle manier te vergelijken.
De operatoren <
, <=
, >
en >=
zijn alleen bruikbaar voor geordende factoren. Deze kunnen categorische waarden vertegenwoordigen die nog steeds een lineaire volgorde hebben. Een geordende factor kan worden gemaakt door het argument ordered = TRUE
aan de factor
te geven of gewoon de ordered
functie te gebruiken.
x <- factor(1:3, labels = c('low', 'medium', 'high'), ordered = TRUE)
print(x)
[1] low medium high
Levels: low < medium < high
y <- ordered(3:1, labels = c('low', 'medium', 'high'))
print(y)
[1] high medium low
Levels: low < medium < high
x < y
[1] TRUE FALSE FALSE
Zie de Factor-documentatie voor meer informatie.
Veranderende en herordenende factoren
Wanneer factoren worden gemaakt met standaardwaarden, worden levels
gevormd door as.character
toegepast op de ingangen en alfabetisch gerangschikt.
charvar <- rep(c("W", "n", "c"), times=c(17,20,14))
f <- factor(charvar)
levels(f)
# [1] "c" "n" "W"
In sommige situaties is de behandeling van de standaardvolgorde van levels
(alfabetische / lexicale volgorde) acceptabel. Als je bijvoorbeeld gewoon de frequenties wilt plot
, is dit het resultaat:
plot(f,col=1:length(levels(f)))
Maar als we een andere volgorde van levels
, moeten we dit specificeren in de parameter levels
of labels
(zorg ervoor dat de betekenis van "bestelling" hier anders is dan geordende factoren, zie hieronder). Er zijn veel alternatieven om die taak te volbrengen, afhankelijk van de situatie.
1. Definieer de factor opnieuw
Wanneer het mogelijk is, kunnen we de factor opnieuw maken met behulp van de parameter levels
in de gewenste volgorde.
ff <- factor(charvar, levels = c("n", "W", "c"))
levels(ff)
# [1] "n" "W" "c"
gg <- factor(charvar, levels = c("W", "c", "n"))
levels(gg)
# [1] "W" "c" "n"
Wanneer de ingangsniveaus verschillen van het gewenste uitgangsniveaus, gebruiken we de labels
parameter die veroorzaakt levels
parameter om een "filter" aanvaardbare ingangswaarden worden, maar laat de eindwaarden van "niveaus" voor de factor vector als argument labels
:
fm <- factor(as.numeric(f),levels = c(2,3,1),
labels = c("nn", "WW", "cc"))
levels(fm)
# [1] "nn" "WW" "cc"
fm <- factor(LETTERS[1:6], levels = LETTERS[1:4], # only 'A'-'D' as input
labels = letters[1:4]) # but assigned to 'a'-'d'
fm
#[1] a b c d <NA> <NA>
#Levels: a b c d
2. Gebruik de relevel
functie
Wanneer er één specifiek level
dat het eerste moet zijn, kunnen we relevel
. Dit gebeurt bijvoorbeeld in de context van statistische analyse, wanneer een base
nodig is om de hypothese te testen.
g<-relevel(f, "n") # moves n to be the first level
levels(g)
# [1] "n" "c" "W"
Zoals kan worden geverifieerd zijn f
en g
hetzelfde
all.equal(f, g)
# [1] "Attributes: < Component “levels”: 2 string mismatches >"
all.equal(f, g, check.attributes = F)
# [1] TRUE
3. Herordenende factoren
Er zijn gevallen waarin we de levels
opnieuw moeten reorder
levels
basis van een getal, een gedeeltelijk resultaat, een berekende statistiek of eerdere berekeningen. Laten we opnieuw ordenen op basis van de frequenties van de levels
table(g)
# g
# n c W
# 20 14 17
De reorder
is generiek (zie help(reorder)
), maar heeft in dit verband nodig: x
, in dit geval de factor; X
, een numerieke waarde van dezelfde lengte als x
; en FUN
, een functie die moet worden toegepast op X
en wordt berekend door het niveau van de x
, die de volgorde van de levels
bepaalt, die standaard toeneemt. Het resultaat is dezelfde factor met de niveaus opnieuw geordend.
g.ord <- reorder(g,rep(1,length(g)), FUN=sum) #increasing
levels(g.ord)
# [1] "c" "W" "n"
Om de afnemende volgorde te krijgen, beschouwen we negatieve waarden ( -1
)
g.ord.d <- reorder(g,rep(-1,length(g)), FUN=sum)
levels(g.ord.d)
# [1] "n" "W" "c"
Opnieuw is de factor hetzelfde als de anderen.
data.frame(f,g,g.ord,g.ord.d)[seq(1,length(g),by=5),] #just same lines
# f g g.ord g.ord.d
# 1 W W W W
# 6 W W W W
# 11 W W W W
# 16 W W W W
# 21 n n n n
# 26 n n n n
# 31 n n n n
# 36 n n n n
# 41 c c c c
# 46 c c c c
# 51 c c c c
Wanneer er een kwantitatieve variabele is gerelateerd aan de factorvariabele, kunnen we andere functies gebruiken om de levels
opnieuw te ordenen. Laten we nemen de iris
data ( help("iris")
voor meer informatie), voor het herordenen van de Species
factor met behulp van de gemiddelde Sepal.Width
.
miris <- iris #help("iris") # copy the data
with(miris, tapply(Sepal.Width,Species,mean))
# setosa versicolor virginica
# 3.428 2.770 2.974
miris$Species.o<-with(miris,reorder(Species,-Sepal.Width))
levels(miris$Species.o)
# [1] "setosa" "virginica" "versicolor"
De gebruikelijke boxplot
(zeg: with(miris, boxplot(Petal.Width~Species)
) toont de species in deze volgorde: setosa , versicolor en virginica . Maar met behulp van de geordende factor krijgen we de soort geordend op de gemiddelde Sepal.Width
:
boxplot(Petal.Width~Species.o, data = miris,
xlab = "Species", ylab = "Petal Width",
main = "Iris Data, ordered by mean sepal width", varwidth = TRUE,
col = 2:4)
Bovendien is het ook mogelijk om de namen van levels
te wijzigen, ze in groepen te combineren of nieuwe levels
toe te voegen. Daarvoor gebruiken we de functie van dezelfde levels
.
f1<-f
levels(f1)
# [1] "c" "n" "W"
levels(f1) <- c("upper","upper","CAP") #rename and grouping
levels(f1)
# [1] "upper" "CAP"
f2<-f1
levels(f2) <- c("upper","CAP", "Number") #add Number level, which is empty
levels(f2)
# [1] "upper" "CAP" "Number"
f2[length(f2):(length(f2)+5)]<-"Number" # add cases for the new level
table(f2)
# f2
# upper CAP Number
# 33 17 6
f3<-f1
levels(f3) <- list(G1 = "upper", G2 = "CAP", G3 = "Number") # The same using list
levels(f3)
# [1] "G1" "G2" "G3"
f3[length(f3):(length(f3)+6)]<-"G3" ## add cases for the new level
table(f3)
# f3
# G1 G2 G3
# 33 17 7
- Geordende factoren
Ten slotte weten we dat ordered
factoren verschillen van factors
, de eerste wordt gebruikt om ordinale gegevens weer te geven en de tweede om te werken met nominale gegevens . In het begin heeft het geen zin om de volgorde van levels
voor geordende factoren te wijzigen, maar we kunnen de labels
wijzigen.
ordvar<-rep(c("Low", "Medium", "High"), times=c(7,2,4))
of<-ordered(ordvar,levels=c("Low", "Medium", "High"))
levels(of)
# [1] "Low" "Medium" "High"
of1<-of
levels(of1)<- c("LOW", "MEDIUM", "HIGH")
levels(of1)
# [1] "LOW" "MEDIUM" "HIGH"
is.ordered(of1)
# [1] TRUE
of1
# [1] LOW LOW LOW LOW LOW LOW LOW MEDIUM MEDIUM HIGH HIGH HIGH HIGH
# Levels: LOW < MEDIUM < HIGH
Opnieuw opbouwen van factoren vanaf nul
Probleem
Factoren worden gebruikt om variabelen voor te stellen die waarden uit een set categorieën aannemen, bekend als Niveaus in R. Een experiment kan bijvoorbeeld worden gekenmerkt door het energieniveau van een batterij, met vier niveaus: leeg, laag, normaal en vol. Vervolgens konden voor 5 verschillende bemonsteringslocaties die niveaus in die termen als volgt worden geïdentificeerd:
vol , vol , normaal , leeg , laag
Typisch, in databases of andere informatiebronnen, wordt de verwerking van deze gegevens door willekeurige gehele indices geassocieerd met de categorieën of niveaus. Als we aannemen dat we voor het gegeven voorbeeld de indices als volgt toewijzen: 1 = leeg, 2 = laag, 3 = normaal, 4 = vol, dan kunnen de 5 monsters worden gecodeerd als:
4 , 4 , 3 , 1 , 2
Het kan voorkomen dat u vanuit uw informatiebron, bijvoorbeeld een database, alleen de gecodeerde lijst met gehele getallen hebt en de catalogus die elk geheel getal aan elk niveau-trefwoord koppelt. Hoe kan een factor R uit die informatie worden gereconstrueerd?
Oplossing
We simuleren een vector van 20 gehele getallen die de monsters vertegenwoordigen, die elk een van vier verschillende waarden kunnen hebben:
set.seed(18)
ii <- sample(1:4, 20, replace=T)
ii
[1] 4 3 4 1 1 3 2 3 2 1 3 4 1 2 4 1 3 1 4 1
De eerste stap is om een factor uit de vorige reeks te maken, waarbij de niveaus of categorieën exact de getallen van 1 tot 4 zijn.
fii <- factor(ii, levels=1:4) # it is necessary to indicate the numeric levels
fii
[1] 4 3 4 1 1 3 2 3 2 1 3 4 1 2 4 1 3 1 4 1
Niveaus: 1 2 3 4
Nu moet je de factor die al is gemaakt aankleden met de index-tags:
levels(fii) <- c("empty", "low", "normal", "full")
fii
[1] volledig normaal volledig leeg leeg normaal laag normaal laag leeg
[11] normaal vol leeg laag vol leeg normaal leeg vol leeg
Niveaus: leeg laag normaal vol