15 Faktörler
15.1 Giriş
R’da, faktörler sabit ve bilinen bir olası değerler kümesi olan kategorik değişkenler ile çalışmak için kullanılır. Karakter vektörlerini alfabetik olmayan bir sırada görüntülemek istediğinizde de kullanışlılardır.
Tarihsel olarak, faktörlerle çalışmak karakterlerle çalışmaktan çok daha kolaydı. Buna bağlı olarak, temel R’daki fonksiyonların çoğu karakterleri otomatik olarak faktörlere dönüştürür. Bu, faktörlerin çoğu zaman gerçekten gerekli olmadıkları yerlerde bitmelerine neden olur. Neyse ki, tidyverse’de bu konuda endişelenmenize gerek yok ve faktörlerin gerçekten yararlı olduğu durumlara odaklanabilirsiniz.
15.1.1 Ön koşullar
Faktörlerle çalışmak için, kategorik (categorical) değişkenlerle baş etmemize yardımcı araçlar sağlayan forcats paketini kullanacağız (ve bu, faktörler anlamına gelen factors’ün bir anagramı!). Bu paket, faktörlerle çalışmak için çok çeşitli yardımcılar sağlar. forcats temel tidyverse paketlerinin bir parçası değildir, bu yüzden ayrıca yüklemeliyiz.
library(tidyverse)
library(forcats)
15.1.2 Daha fazlasını öğrenmek için
Eğer faktörler hakkında daha fazla bilgi edinmek istiyorsanız, Amelia McNamara ve Nicholas Horton’un makalesini, Wrangling categorical data in R okumanızı öneriyorum. Bu makale, stringsAsFactors: An unauthorized biography ve stringsAsFactors = <sigh>’te tartışılan tarihin bir kısmını ortaya koymaktadır, ve bu kitapta açıklanan kategorik verilere ilişkin tidyverse yaklaşımlarını temel R yöntemleriyle karşılaştırır. Makalenin erken bir sürümü forcats paketini motive etmeye ve kapsamını belirleme yardımcıdır; Amelia ve Nick’e teşekkürler!
15.2 Faktör oluşturma
Ayları içeren bir değişkeniniz olduğunu varsayalım:
<- c("Dec", "Apr", "Jan", "Mar") x1
Bu değişkeni kaydetmek için dizge kullanmanın iki sorunu vardır:
Sadece on iki olası ay var ve sizi yazım hatalarından koruyacak hiçbir şey yok:
<- c("Dec", "Apr", "Jam", "Mar") x2
İçeriği yararlı bir şekilde sıralamaz:
sort(x1) #> [1] "Apr" "Dec" "Jan" "Mar"
Bu sorunların her ikisini de faktörle düzeltebilirsiniz. Bir faktör oluşturmak için geçerli bir levels listesi oluşturarak başlamalısınız:
<- c(
month_levels "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
)
Şimdi bir faktör oluşturabilirsiniz:
<- factor(x1, levels = month_levels)
y1
y1#> [1] Dec Apr Jan Mar
#> Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
sort(y1)
#> [1] Jan Mar Apr Dec
#> Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Ve bu küme içerisinde yer almayan tüm değerler, sessizce NA’ya dönüştürülecektir:
<- factor(x2, levels = month_levels)
y2
y2#> [1] Dec Apr <NA> Mar
#> Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Eğer ki bir uyarı almak isterseniz, readr::parse_factor()
fonksiyonunu kullanabilirsiniz:
<- parse_factor(x2, levels = month_levels)
y2 #> Warning: 1 parsing failure.
#> row col expected actual
#> 3 -- value in level set Jam
Eğer seviyeleri (levels) çıkarırsanız, veriden alfabetik sıra ile çıkarılırlar:
factor(x1)
#> [1] Dec Apr Jan Mar
#> Levels: Apr Dec Jan Mar
Bazen faktörün seviyelerinin veride ilk göründükleri sırada olmasını tercih edebilirsiniz. Bunu faktörü oluştururken seviyeleri unique(x)
e eşitleyerek, ya da sonrasında, fct_inorder()
ile yapabilirsiniz:
<- factor(x1, levels = unique(x1))
f1
f1#> [1] Dec Apr Jan Mar
#> Levels: Dec Apr Jan Mar
<- x1 %>% factor() %>% fct_inorder()
f2
f2#> [1] Dec Apr Jan Mar
#> Levels: Dec Apr Jan Mar
Eğer geçerli seviyelere direkt olarak erişmeniz gerekirse, bunu levels()
ile yapabilirsiniz:
levels(f2)
#> [1] "Dec" "Apr" "Jan" "Mar"
15.3 Genel Sosyal Anket
Bu bölümün geri kalanında, forcats::gss_cat
verisine odaklanacağız. Bu, uzun süredir devam etmekte olan ve Chicago Üniversitesi’nde bağımsız araştırma organizasyonu NORC tarafından düzenlenen bir ABD anket olan Genel Sosyal Anket’ten örnek bir veri. Ankette binlerce soru var, bu yüzden gss_cat
te, faktörlerle çalışırken karşılaşacağınız bazı yaygın zorlukları örnekleyecek birkaç örnek seçtim.
gss_cat#> # A tibble: 21,483 × 9
#> year marital age race rincome partyid relig denom tvhours
#> <int> <fct> <int> <fct> <fct> <fct> <fct> <fct> <int>
#> 1 2000 Never married 26 White $8000 to 9999 Ind,near r… Prot… Sout… 12
#> 2 2000 Divorced 48 White $8000 to 9999 Not str re… Prot… Bapt… NA
#> 3 2000 Widowed 67 White Not applicable Independent Prot… No d… 2
#> 4 2000 Never married 39 White Not applicable Ind,near r… Orth… Not … 4
#> 5 2000 Divorced 25 White Not applicable Not str de… None Not … 1
#> 6 2000 Married 25 White $20000 - 24999 Strong dem… Prot… Sout… NA
#> # … with 21,477 more rows
(Hatırlayın, bu veriseti bir paket tarafından sağlandığından, değişkenlerle ilgili daha fazla bilgiyi ?gss_cat
ile alabilirsiniz.)
Faktörler bir tibble olarak kaydedildiğinde seviyelerini çok rahatlıkla göremezsiniz. Bunları görebilmenin bir yolu count()
iledir:
%>%
gss_cat count(race)
#> # A tibble: 3 × 2
#> race n
#> <fct> <int>
#> 1 Other 1959
#> 2 Black 3129
#> 3 White 16395
Ya da bir çubuk grafik ile:
ggplot(gss_cat, aes(race)) +
geom_bar()
Varsayılan olarak, ggplot2 bir değere sahip olmayan seviyeleri veriden çıkartacaktır. Onları görüntülemeye şu şekilde zorlayabilirsiniz:
ggplot(gss_cat, aes(race)) +
geom_bar() +
scale_x_discrete(drop = FALSE)
Bu seviyeler bu verisetinde mevcut olmayan geçerli değerleri temsil etmektedir. Ne yazık ki, dplyr’ın henüz bir drop
fonksiyonu yok, ancak gelecekte olacak.
Faktörlerle çalışırken, en yaygın iki işlem seviyelerin sıralamasını değiştirmek ve seviyelerin değerlerini değiştirmektir. Bu işlemler aşağıdaki bölümlerde açıklanmıştır.
15.3.1 Alıştırmalar
rincome
(rincome, rapor edilen gelir)’in dağılımını inceleyin. Varsayılan çubuk grafiğinin anlaşılmasını zorlaştıran nedir? Bu grafiği iyileştirebilir misiniz?Bu anketteki en yaygın
relig
nedir? En yaygınpartyid
nedir?Hangi
denom
değişkeni hangirelig
için geçerlidir? Bunu bir tablo ile nasıl bulursunuz? Bunu bir görselleştirme ile nasıl bulursunuz?
15.4 Faktör sırasını değiştirmek
Görselleştirme için faktör sıralamasını değiştirmek genellikle yararlıdır. Örneğin, dinler arasında günlük TV izlemek için harcanan ortalama saat sayısını karşılaştırmak istediğinizi düşünün:
<- gss_cat %>%
relig_summary group_by(relig) %>%
summarise(
age = mean(age, na.rm = TRUE),
tvhours = mean(tvhours, na.rm = TRUE),
n = n()
)
ggplot(relig_summary, aes(tvhours, relig)) + geom_point()
Bu figürü yorumlamak zor çünkü genel bir örüntü yok. Bunu relig
deki seviyeleri fct_reorder()
kullanarak yeniden sıralayarak geliştirebiliriz. fct_reorder()
üç argüman alır:
f
, seviyelerini değiştirmek istediğiniz faktör.x
, seviyeleri tekrar sıralamak için kullanacağınız nümerik bir vektör.- Opsiyonel olarak,
fun
, eğerf
teki her değer için birden fazlax
var ise kullanılacak fonksiyon. Varsayılan değermedian
dır.
ggplot(relig_summary, aes(tvhours, fct_reorder(relig, tvhours))) +
geom_point()
Dinleri tekrar sıralamak, “bilmiyorum” kategorisindeki insanların çok daha fazla, Hinduizm ve diğer doğu dinlerininse daha az TV izlediğini görmeyi çok daha kolaylaştırıyor.
Daha karmaşık dönüşümler yapmaya başladıkça, bunları aes()
dışına çıkartıp, farklı bir mutate()
basamağı haline getirmeyi öneririm. Örneğin, yukarıdaki figürü şu şekilde de yazabilirsiniz:
%>%
relig_summary mutate(relig = fct_reorder(relig, tvhours)) %>%
ggplot(aes(tvhours, relig)) +
geom_point()
Peki ya benzer bir figürü belirtilen gelir seviyesine göre ortalama yaşın nasıl değiştiğine bakmak için çizersek ne olur?
<- gss_cat %>%
rincome_summary group_by(rincome) %>%
summarise(
age = mean(age, na.rm = TRUE),
tvhours = mean(tvhours, na.rm = TRUE),
n = n()
)
ggplot(rincome_summary, aes(age, fct_reorder(rincome, age))) + geom_point()
Burada, seviyelerin keyfi bir şekilde yeniden sıralanması iyi bir fikir değil! Bunun nedeni, rincome
ın zaten uğraşmamamız gereken ilkeli bir düzene sahip olmasıdır. fct_reorder()
ı isteğe bağlı olarak sıralanmış faktörler için ayırın.
Bununla birlikte, “Not applicable”ı diğer özel seviyelerin önüne çekmek mantıklıdır. fct_relevel()
kullanabilirsiniz. Bu fonksiyon bir faktör f
, ve sonra sıranın önüne almak istediğiniz seviyeleri alır.
ggplot(rincome_summary, aes(age, fct_relevel(rincome, "Not applicable"))) +
geom_point()
Neden “Not applicable” için ortalama yaşın bu kadar yüksek olduğunu düşünüyorsunuz?
Bir figür üzerindeki çizgileri renklendirirken başka bir yeniden sıralama türü kullanışlıdır. fct_reorder2()
, faktörü en büyük x
değeri ile ilişkili y
değerine göre yeniden sıralar. Bu, çizgi renklerinin açıklama ile uyumlu (aynı sırada) olması nedeniyle figürün okunmasını kolaylaştırır.
<- gss_cat %>%
by_age 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")
Son olarak, çubuk grafikleri için, seviyeleri artan frekansa göre sıralamak için fct_infreq()
fonksiyonunu kullanabilirsiniz: bu en basit yeniden sıralama tipidir çünkü başka bir değişkene ihtiyaç duymaz. Bunu fct_rev()
ile birleştirmek isteyebilirsiniz.
%>%
gss_cat mutate(marital = marital %>% fct_infreq() %>% fct_rev()) %>%
ggplot(aes(marital)) +
geom_bar()
15.5 Faktör seviyelerini değiştirme
Seviyelerin sırasını değiştirmekten daha güçlü olan şey değerlerini değiştirmektir. Bu, yayın için etiketleri netleştirmenize ve üst düzey ekranlar için düzeyleri daraltmanıza olanak sağlar. En genel ve güçlü araç fct_recode()
dır. Bu, her seviyenin değerini yeniden kodlamanızı ya da değiştirmenizi sağlar. Örneğin, gss_cat$partyid
i alalım:
%>% count(partyid)
gss_cat #> # A tibble: 10 × 2
#> partyid n
#> <fct> <int>
#> 1 No answer 154
#> 2 Don't know 1
#> 3 Other party 393
#> 4 Strong republican 2314
#> 5 Not str republican 3032
#> 6 Ind,near rep 1791
#> # … with 4 more rows
Seviyeler kısa ve tutarsız. Daha uzun olacak ve paralel bir yapı kullanacak şekilde tekrar ayarlayalım.
%>%
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)
#> # A tibble: 10 × 2
#> partyid n
#> <fct> <int>
#> 1 No answer 154
#> 2 Don't know 1
#> 3 Other party 393
#> 4 Republican, strong 2314
#> 5 Republican, weak 3032
#> 6 Independent, near rep 1791
#> # … with 4 more rows
fct_recode()
, açıkça belirtilmeyen seviyeleri olduğu gibi bırakacak ve yanlışlıkla olmayan bir seviyeden bahsederseniz sizi uyaracaktır.
Grupları birleştirmek için aynı yeni seviyeye birden fazla eski seviye atayabilirsiniz:
%>%
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)
#> # A tibble: 8 × 2
#> partyid n
#> <fct> <int>
#> 1 Other 548
#> 2 Republican, strong 2314
#> 3 Republican, weak 3032
#> 4 Independent, near rep 1791
#> 5 Independent 4119
#> 6 Independent, near dem 2499
#> # … with 2 more rows
Bu tekniği dikkatli kullanmalısınız: eğer gerçekten farklı kategorileri bir arada gruplandırırsanız, yanıltıcı sonuçlarla karşılaşırsınız.
Çok fazla seviyeyi daraltmak istiyorsanız, fct_collapse()
, fct_recode()
un kullanışlı bir çeşididir. Her yeni değişken için eski seviyelerin bir vektörünü sağlayabilirsiniz:
%>%
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)
#> # A tibble: 4 × 2
#> partyid n
#> <fct> <int>
#> 1 other 548
#> 2 rep 5346
#> 3 ind 8409
#> 4 dem 7180
Bazen, bir figür veya tabloyu daha basitleştirmek için bütün küçük grupları bir araya toplamak istersiniz. Bu fct_lump()
ın işidir:
%>%
gss_cat mutate(relig = fct_lump(relig)) %>%
count(relig)
#> # A tibble: 2 × 2
#> relig n
#> <fct> <int>
#> 1 Protestant 10846
#> 2 Other 10637
Varsayılan davranış aşamalı olarak küçük grupları bir araya getirmektir eğer toplanmış grup hala en küçük grup olacaksa. Bu durumda çok yardımcı değil: Bu ankete katılan Amerikalıların çoğunluğunun Protestan olduğu doğrudur, ancak muhtemelen fazla daralttık.
Bunun yerine, n
parametresini kullanarak kaç tane grubu (diğer hariç) tutmak istediğimizi belirtebiliriz:
%>%
gss_cat mutate(relig = fct_lump(relig, n = 10)) %>%
count(relig, sort = TRUE) %>%
print(n = Inf)
#> # A tibble: 10 × 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