R'deki faktörler: bir rahatsızlıktan daha fazlası mı?


95

R'deki temel veri türlerinden biri faktörlerdir. Deneyimlerime göre faktörler temelde bir acı ve onları asla kullanmıyorum. Ben her zaman karaktere dönüşürüm. Garip bir şekilde bir şey kaçırıyormuşum gibi hissediyorum.

Faktör veri türünün gerekli olduğu durumlarda değişkenleri gruplama olarak kullanan bazı önemli işlev örnekleri var mı? Faktörleri kullanmam gereken belirli durumlar var mı?


7
Bu yorumu, bu soruyu bulması muhtemel başlangıç ​​seviyesindeki R kullanıcıları için ekliyorum. Geçenlerde bir blog yazısı yazdı aşağıdan R. içinde faktörlerini kullanmak ne zaman, nasıl ve neden üzerinde bir öğretim öğretici içine çok cevaplardan bilgilerin derler gormanalysis.com/?p=115
Ben

Her zaman faktörlerin karakterlerden daha verimli bir şekilde saklandığını varsaymıştım - sanki her giriş, seviyeye işaret ediyormuş gibi. Ama bunu yazmak için test ettiğimde bunun doğru olmadığını anladım!
izomorfizmler

2
@isomorphismes şey, bu kullanılan R önceki günlerde, gerçek olamayacak kadar, ama bu değişti. Bu blog gönderisine bakın: simplystatistics.org/2015/07/24/…
MichaelChirico

4
5+ yıl sonra bu "stringsAsFactors: Yetkisiz bir biyografi" yazıldı: simplystatistics.org/2015/07/24/…
JD Long

Yanıtlar:


49

Faktörleri kullanmalısınız. Evet, acı verici olabilirler, ancak benim teorim, neden acı olduklarının% 90'ının read.tableve varsayılan olarak read.csvargümandan kaynaklandığı stringsAsFactors = TRUE(ve çoğu kullanıcı bu inceliği kaçırıyor). Kullanışlı olduklarını söylüyorum çünkü lme4 gibi model yerleştirme paketleri, modelleri farklı şekilde sığdırmak ve kullanılacak kontrast türlerini belirlemek için faktörleri ve sıralı faktörleri kullanır. Ve grafik paketleri de bunları gruplamak için kullanır. ggplotve model uydurma işlevlerinin çoğu karakter vektörlerini faktörlere zorlar, dolayısıyla sonuç aynıdır. Ancak, kodunuzda uyarılarla karşılaşırsınız:

lm(Petal.Length ~ -1 + Species, data=iris)

# Call:
# lm(formula = Petal.Length ~ -1 + Species, data = iris)

# Coefficients:
#     Speciessetosa  Speciesversicolor   Speciesvirginica  
#             1.462              4.260              5.552  

iris.alt <- iris
iris.alt$Species <- as.character(iris.alt$Species)
lm(Petal.Length ~ -1 + Species, data=iris.alt)

# Call:
# lm(formula = Petal.Length ~ -1 + Species, data = iris.alt)

# Coefficients:
#     Speciessetosa  Speciesversicolor   Speciesvirginica  
#             1.462              4.260              5.552  

Uyarı mesajı: Giriş model.matrix.default(mt, mf, contrasts):

değişken Speciesbirfactor

Bütünüyle aldatıcı bir şey var drop=TRUE. Vektörlerde bu, verilerde bulunmayan faktör düzeylerini kaldırmak için iyi çalışır. Örneğin:

s <- iris$Species
s[s == 'setosa', drop=TRUE]
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa
s[s == 'setosa', drop=FALSE]
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa versicolor virginica

Ancak , data.frames ile davranışı [.data.frame()farklıdır: bu e-postaya bakın veya ?"[.data.frame". Kullanılması drop=TRUEüzerine data.framehayal ediyorum gibi çalışmıyor s:

x <- subset(iris, Species == 'setosa', drop=TRUE)  # susbetting with [ behaves the same way
x$Species
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa versicolor virginica

Neyse ki droplevels(), tek bir faktör için veya a'daki her faktör için kullanılmayan faktör seviyelerini düşürmek için faktörleri kolayca düşürebilirsiniz data.frame(R 2.12'den beri):

x <- subset(iris, Species == 'setosa')
levels(x$Species)
# [1] "setosa"     "versicolor" "virginica" 
x <- droplevels(x)
levels(x$Species)
# [1] "setosa"

ggplotEfsanelere girmekten seçtiğiniz seviyeleri nasıl koruyacağınız budur .

Dahili olarak factors, öznitelik seviyesi karakter vektörüne (bakınız attributes(iris$Species)ve class(attributes(iris$Species)$levels)) sahip, temiz olan tam sayılardır . Bir seviye adını değiştirmeniz gerekirse (ve karakter dizilerini kullanıyor olsaydınız), bu çok daha az verimli bir işlem olurdu . Ve özellikle ggplotefsaneler için seviye isimlerini çok değiştiriyorum . Karakter vektörleriyle faktörleri taklit ederseniz, yalnızca bir öğeyi değiştirme ve yanlışlıkla ayrı bir yeni seviye oluşturma riski vardır.


1
stringsAsFactorsbir işlev değildir.
IRTFM

30

sıralı faktörler harika, eğer portakalları seviyorsam ve elmalardan nefret ediyorsam ama üzümlere aldırış etmiyorsam, bunu söylemek için garip bir indeks yönetmem gerekmiyor:

d <- data.frame(x = rnorm(20), f = sample(c("apples", "oranges", "grapes"), 20, replace = TRUE, prob = c(0.5, 0.25, 0.25)))
d$f <- ordered(d$f, c("apples", "grapes", "oranges"))
d[d$f >= "grapes", ]

bu harika bir uygulama. Bunu hiç düşünmedim.
JD Long

Ne yaptı d$f <- ordered(d$f, c("apples", "grapes", "oranges"))? Bunları veri çerçevesinde sipariş ettiğini tahmin etmiştim, ancak bu satırı çalıştırıp veri çerçevesini yazdırdıktan sonra hiçbir şey değişmiyor. Basılı sipariş değişmese bile sadece bir iç sipariş mi dayatıyor?
Addem

... Evet, yazdığım şey doğru bir cümle gibi bir şeydi. Söylemek istediğiniz şeyi anlarsam, bize faktörlere göre sıralama yapabileceğinizi göstermiş olursunuz, bu dizeler için yapamayacağınız bir şeydir.
Addem

4
order (), herhangi bir değerden - sıralı olduklarını söylediğiniz sırayla - keyfi bir sıralama oluşturur. Sözlükbilimsel olarak sıralanmış değerleri kullanmam talihsizlik, bu bir tesadüf. Örneğin bunu "Z" nin kötü, "3" ün iyi olduğu ancak etiketlerin sayısal veya alfabetik olmadığı veriler için kullanıyorum - bu yüzden sıralıyım (veri, c ("Z", "B", "A", " 0 "," 1 "," 2 "," 3 ")) ve böylece veri>" A "yapabilirim ve mutlu günler.
mdsumner

19

A factor, en çok diğer dillerdeki numaralandırılmış türe benzer. Uygun kullanımı, yalnızca önceden belirlenmiş değerlerden birini alabilen bir değişken içindir. Bu durumlarda, izin verilen her değer belirli bir veri kümesinde bulunmayabilir ve "boş" düzeyler bunu doğru bir şekilde yansıtır.

Bazı örnekleri ele alalım. Birleşik Devletler'in tamamında toplanan bazı veriler için eyalet bir faktör olarak kaydedilmelidir. Bu durumda, belirli bir eyaletten hiçbir vakanın toplanmaması önemlidir. Bu durumdan veri olabilirdi, ancak olmadı (her ne sebeple olursa olsun, bu bir ilgi nedeni olabilir). Memleket toplanmış olsaydı, bu bir faktör olmazdı. Önceden belirlenmiş olası memleketler dizisi yoktur. Veriler ulusal olarak değil üç kasabadan toplanmış olsaydı, kasaba bir faktör olurdu: Başlangıçta verilen üç seçenek vardır ve bu üç kasabadan birinde herhangi bir ilgili vaka / veri bulunmadıysa, bu önemlidir.

factorS'nin bir dizi dizgeye keyfi bir sıralama düzeni vermenin bir yolunu sağlama gibi diğer yönleri, s'nin yararlı ikincil özellikleridir factor, ancak varlıklarının nedeni değildir.


3
+1. Brian, sanırım verilerde bulunmayan seviyeleri yakalayarak kafasına çivi çaktın.
Ricardo Saporta

13

Bir kişi istatistiksel analiz yaparken ve verileri gerçekten keşfederken faktörler harikadır. Bununla birlikte, bundan önce kişi verileri okurken, temizlerken, sorun giderirken, birleştirirken ve genel olarak manipüle ederken, faktörler tam bir acıdır. Daha yakın zamanlarda, son birkaç yılda olduğu gibi, faktörleri daha iyi ele almak için birçok işlev geliştirildi. Örneğin, rbind onlarla güzelce oynuyor. Bir alt küme fonksiyonundan sonra boş seviyeleri bırakmayı hala tam bir sıkıntı buluyorum.

#drop a whole bunch of unused levels from a whole bunch of columns that are factors using gdata
require(gdata)
drop.levels(dataframe)

Bir faktörün seviyelerini yeniden kodlamanın ve etiketleri yeniden düzenlemenin kolay olduğunu ve seviyeleri yeniden düzenlemenin harika yolları da olduğunu biliyorum. Beynim onları hatırlayamıyor ve her kullandığımda yeniden öğrenmem gerekiyor. Yeniden kodlama, olduğundan çok daha kolay olmalıdır.

R'nin string fonksiyonlarının kullanımı oldukça kolay ve mantıklıdır. Bu yüzden manipüle ederken genellikle karakterleri faktörlere tercih ederim.


1
Faktörleri kullanan istatistik analizi örnekleriniz var mı?
JD Long

3
artık bir baz-R işlevi var droplevels(). Ve varsayılan olarak faktörleri yeniden sıralamaz.
Ben Bolker

6

Ne kadar keskin bir başlık!

Pek çok tahmin fonksiyonunun, kukla değişkenleri kolayca tanımlamak için faktörleri kullanmanıza izin verdiğine inanıyorum ... ama onları bunun için kullanmıyorum.

Birkaç benzersiz gözlem içeren çok büyük karakter vektörlerim olduğunda bunları kullanırım. Bu, özellikle karakter vektöründeki dizeler daha uzunsa bellek tüketimini azaltabilir.

Not - Başlık hakkında şaka yapıyorum. Tweetini gördüm. ;-)


1
Yani onları gerçekten sadece depolama alanını korumak için kullanırsınız. Mantıklı.
JD Long

13
En azından eskiden ;-). Ancak birkaç R sürümü önce karakter depolaması dahili olarak karma hale getirilmek üzere yeniden yazıldı, bu nedenle bu tarihi argümanın bir kısmı artık geçersiz. Hareketsiz faktörler gruplama ve modelleme için çok kullanışlıdır.
Dirk Eddelbuettel

1
Buna göre ?factorR-2.6.0 idi ve "Tamsayı değerleri 4 bayt olarak saklanırken, bir karakter dizisine yapılan her başvuru 4 veya 8 baytlık bir göstericiye ihtiyaç duyar." Karakter dizisi 8 bayta ihtiyaç duyarsa, çarpanlara dönüştürerek yerden tasarruf eder miydiniz?
Joshua Ulrich

2
N <- 1000; a <- örnek (c ("a", "b", "c"), N, değiştir = DOĞRU); print (nesne.size (a), birimler = "Kb"); print (nesne.size (faktör (a)), birimler = "Kb"); 8 Kb 4.5 Kb, bu yüzden hala biraz yer tasarrufu sağlıyor gibi görünüyor.
Eduardo Leoni

2
@Eduardo 4.2Kb'ye karşı 4Kb aldım. For N=100000I 391,8 Kb vs 391,5 Kb aldık. Yani faktör biraz daha fazla hafıza gerektirir.
Marek

1

Faktörler, mükemmel bir "benzersiz durum" rozeti motorudur. Bunu defalarca kötü bir şekilde yeniden yarattım ve ara sıra birkaç kırışıklığa rağmen son derece güçlüler.

library(dplyr)
d <- tibble(x = sample(letters[1:10], 20, replace = TRUE))

## normalize this table into an indexed value across two tables
id <- tibble(x_u = sort(unique(d$x))) %>% mutate(x_i = row_number())
di <- tibble(x_i = as.integer(factor(d$x)))


## reconstruct d$x when needed
d2 <- inner_join(di, id) %>% transmute(x = x_u)
identical(d, d2)
## [1] TRUE

Bu görevi yapmanın daha iyi bir yolu varsa, görmeyi çok isterim, bu yeteneğin factortartışıldığını görmüyorum .


-2

tapply (ve aggregate ) faktörlere bağlıdır. Bu fonksiyonların bilgi-çaba oranı çok yüksektir.

Örneğin, tek bir kod satırında ( aşağıdaki dokunma çağrısı ), Cut ve Color'a göre ortalama elmas fiyatını alabilirsiniz:

> data(diamonds, package="ggplot2")

> head(dm)

   Carat     Cut    Clarity Price Color
1  0.23     Ideal     SI2   326     E
2  0.21   Premium     SI1   326     E
3  0.23      Good     VS1   327     E


> tx = with(diamonds, tapply(X=Price, INDEX=list(Cut=Cut, Color=Color), FUN=mean))

> a = sort(1:diamonds(tx)[2], decreasing=T)  # reverse columns for readability

> tx[,a]

         Color
Cut         J    I    H    G    F    E    D
Fair      4976 4685 5136 4239 3827 3682 4291
Good      4574 5079 4276 4123 3496 3424 3405
Very Good 5104 5256 4535 3873 3779 3215 3470
Premium   6295 5946 5217 4501 4325 3539 3631
Ideal     4918 4452 3889 3721 3375 2598 2629

7
Bu iyi bir örnek değildir, çünkü tüm bu örnekler dizelerle de işe yarar.
hadley
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.