É muito frustrante quando uma coluna de strings é lida como um fator, pois fatores não podem ser manipulados do mesmo jeito que manipulamos vetores de strings.
Muitos dos problemas associados ao uso de fatores no R existe por conta da falta de algumas ferramentas úteis no pacote base. Para resolver esse o problema, Hadley Wickham desenvolveu o pacote forcats (for categorial variables), que implementa algumas dessas ferramentas.
As principais funções do forcats servem para alterar a ordem e modificar os níveis de um fator.
Pacote forcats.
Um fator é definido como um vetor de integers com dois atributos específicos:
Fatores são úteis porque facilitam a ordenação de vetores de texto, principalmente quando estamos fazendo gráficos.
O forcats é um pacote bastante simples. Este pacote não faz parte do tidyverse. Ele é composto por funções de apenas dois tipos:
x1<-c("Fev","Mar","Abr","Jan", "Jul", "Jun")
is.factor(x1)
## [1] FALSE
sort(x1)
## [1] "Abr" "Fev" "Jan" "Jul" "Jun" "Mar"
x2<-c("Mar","ABr","Jam","Jun","Jul")
meses<-c("Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez")
y1<-factor(x1,levels = meses)
is.factor(y1)
## [1] TRUE
sort(y1)
## [1] Jan Fev Mar Abr Jun Jul
## Levels: Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez
y2<-factor(x2)
is.factor(y2)
## [1] TRUE
sort(y2)
## [1] ABr Jam Jul Jun Mar
## Levels: ABr Jam Jul Jun Mar
y3<-factor(x2, levels = meses)
y3
## [1] Mar <NA> <NA> Jun Jul
## Levels: Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez
sort(y3)
## [1] Mar Jun Jul
## Levels: Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez
y4<-readr::parse_factor(x2,levels = meses)
## Warning: 2 parsing failures.
## row col expected actual
## 2 -- value in level set ABr
## 3 -- value in level set Jam
Podemos preferir que a ordem dos níveis combine com a ordem da primeira aparição nos dados.
f1<-factor(x1,levels = unique(x1))
f1
## [1] Fev Mar Abr Jan Jul Jun
## Levels: Fev Mar Abr Jan Jul Jun
# ou da forma
library(tidyverse)
## -- Attaching packages -------------------------------------------------- tidyverse 1.2.1 --
## v ggplot2 3.2.0 v purrr 0.3.2
## v tibble 2.1.3 v dplyr 0.8.3
## v tidyr 0.8.3 v stringr 1.4.0
## v readr 1.3.1 v forcats 0.4.0
## -- Conflicts ----------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(forcats)
f2<- x1 %>% factor() %>% fct_inorder()
f2
## [1] Fev Mar Abr Jan Jul Jun
## Levels: Fev Mar Abr Jan Jul Jun
levels(f2)
## [1] "Fev" "Mar" "Abr" "Jan" "Jul" "Jun"
Vamos ver agora o exemplo de um conjunto de dados do General Social Survey (https://gss.norc.org/Get-The-Data) que é uma pesquisa norte amearicana de longa duração conduzida pela organização independente de pesquisas NORC da Universidade de Chicago.
glimpse(gss_cat)
## Observations: 21,483
## Variables: 9
## $ year <int> 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, ...
## $ marital <fct> Never married, Divorced, Widowed, Never married, Divor...
## $ age <int> 26, 48, 67, 39, 25, 25, 36, 44, 44, 47, 53, 52, 52, 51...
## $ race <fct> White, White, White, White, White, White, White, White...
## $ rincome <fct> $8000 to 9999, $8000 to 9999, Not applicable, Not appl...
## $ partyid <fct> "Ind,near rep", "Not str republican", "Independent", "...
## $ relig <fct> Protestant, Protestant, Protestant, Orthodox-christian...
## $ denom <fct> Southern baptist, Baptist-dk which, No denomination, N...
## $ tvhours <int> 12, NA, 2, 4, 1, NA, 3, NA, 0, 3, 2, NA, 1, NA, 1, 7, ...
# ?gss_cat
gss_cat %>% count(race)
ggplot(gss_cat, aes(race)) + geom_bar() + scale_x_discrete(drop=FALSE)
relig<- gss_cat %>% group_by(relig) %>%
summarise(mean(age,na.rm =TRUE),
tvhours = mean(tvhours, na.rm = TRUE),
n = n())
ggplot(relig, aes(tvhours, relig)) + geom_point()
# Podemos melhorar este gráfico reordenando os níveis relig usando fct_reorder()
ggplot(relig,aes(tvhours,fct_reorder(relig,tvhours))) + geom_point()
rincome <- gss_cat %>%
group_by(rincome) %>%
summarise(mean(age,na.rm =TRUE),
tvhours = mean(tvhours, na.rm = TRUE),
n = n())
head(rincome)
ggplot(rincome,aes(tvhours,fct_reorder(rincome,tvhours))) + geom_point()
ggplot(rincome,aes(tvhours,fct_relevel(rincome,"Not applicable"))) + geom_point()
* A função fct_reorder2() reordena o fator pelos valores de y associados com os maiores valores de x.
by_age <- gss_cat %>%
filter(!is.na(age)) %>%
count(age, marital) %>%
group_by(age) %>%
mutate(prop = n / sum(n))
ggplot(by_age, aes(age, prop, colour = marital)) +
geom_line(na.rm = TRUE)
ggplot(by_age, aes(age, prop, colour = fct_reorder2(marital, age, prop))) +
geom_line() +
labs(colour = "marital")
f <- factor(c("a", "b", "c"))
fct_rev(f)
## [1] a b c
## Levels: c b a
gss_cat %>%
mutate(marital = marital %>% fct_infreq() %>% fct_rev()) %>%
ggplot(aes(marital)) +
geom_bar()
gss_cat %>% count(partyid)
gss_cat %>%
mutate(partyid = fct_recode(partyid,
"Republican, strong" = "Strong republican",
"Republican, weak" = "Not str republican",
"Independent, near rep" = "Ind,near rep",
"Independent, near dem" = "Ind,near dem",
"Democrat, weak" = "Not str democrat",
"Democrat, strong" = "Strong democrat"
)) %>%
count(partyid)
gss_cat %>%
mutate(partyid = fct_recode(partyid,
"Republican, strong" = "Strong republican",
"Republican, weak" = "Not str republican",
"Independent, near rep" = "Ind,near rep",
"Independent, near dem" = "Ind,near dem",
"Democrat, weak" = "Not str democrat",
"Democrat, strong" = "Strong democrat",
"Other" = "No answer",
"Other" = "Don't know",
"Other" = "Other party"
)) %>%
count(partyid)
# Agora veja o exemplo:
gss_cat %>%
mutate(partyid = fct_collapse(partyid,
other = c("No answer", "Don't know", "Other party"),
rep = c("Strong republican", "Not str republican"),
ind = c("Ind,near rep", "Independent", "Ind,near dem"),
dem = c("Not str democrat", "Strong democrat")
)) %>%
count(partyid)
gss_cat %>%
mutate(relig = fct_lump(relig)) %>%
count(relig)
# O que muda agora?
gss_cat %>%
mutate(relig = fct_lump(relig, n = 10)) %>%
count(relig, sort = TRUE) %>%
print(n = Inf)
## # A tibble: 10 x 2
## relig n
## <fct> <int>
## 1 Protestant 10846
## 2 Catholic 5124
## 3 None 3523
## 4 Christian 689
## 5 Other 458
## 6 Jewish 388
## 7 Buddhism 147
## 8 Inter-nondenominational 109
## 9 Moslem/islam 104
## 10 Orthodox-christian 95
Lembrando que pipes são uma ferramenta importante para expressar claramente uma sequência de múlplicas operações.
O pipe ** %>% ** vem do pacote magrittr de Stefan Milton Bache.
Pacote magrittr.
library(magrittr)
##
## Attaching package: 'magrittr'
## The following object is masked from 'package:purrr':
##
## set_names
## The following object is masked from 'package:tidyr':
##
## extract
head(iris)
iris %>% filter(Sepal.Width == 3)
# Agora usando %<>% (operador de atribuição composta)
iris<- iris%>%
transform(Sepal.Length = Sepal.Width)
iris
iris %<>% transform(Sepal.Length = Sepal.Width)
iris %$% cor(Petal.Length, Petal.Width)
## [1] 0.9628654
set.seed(123)
rnorm(1000) %>%
matrix(ncol = 2) %>%
plot() %>%
str()
## NULL
rnorm(1000) %>%
matrix(ncol = 2) %T>%
plot() %>%
str()
## num [1:500, 1:2] -0.996 -1.04 -0.018 -0.132 -2.549 ...