R의 요소 : 성가심 이상?


95

R의 기본 데이터 유형 중 하나는 요인입니다. 내 경험상 요인은 기본적으로 고통이며 절대 사용하지 않습니다. 나는 항상 문자로 변환합니다. 뭔가 빠진 것 같은 기분이 듭니다.

요인 데이터 유형이 필요한 경우 요인을 그룹화 변수로 사용하는 함수의 몇 가지 중요한 예가 있습니까? 요인을 사용해야하는 특정 상황이 있습니까?


7
이 질문을 찾을 가능성이있는 초보자 R 사용자를 위해이 설명을 추가합니다. 나는 최근에 R. gormanalysis.com/?p=115
Ben

각 항목이 레벨에 대한 포인터 인 것처럼 항상 요소가 문자보다 효율적으로 저장된다고 가정했습니다. 그러나 이것을 작성하기 위해 테스트 한 결과 사실이 아님을 알았습니다!
isomorphismes

2
@isomorphismes 잘, 예전 에는 사실 이었지만 R의 초기에는 바뀌 었습니다. 이 블로그 게시물 참조 : simplystatistics.org/2015/07/24/…
MichaelChirico

4
5 년 후이 "stringsAsFactors : 승인되지 않은 전기"가 작성되었습니다. simplystatistics.org/2015/07/24/…
JD Long

답변:


49

요인을 사용해야합니다. 예 그들은 통증이있을 수 있지만, 내 이론에 때문에 그들이 고통있는 이유의 90 %는 점이다 read.table하고 read.csv, 인수 stringsAsFactors = TRUE기본적으로 (대부분의 사용자가이 미묘를 그리워). lme4와 같은 모델 피팅 패키지는 모델을 차등 적으로 피팅하고 사용할 대비 유형을 결정하기 위해 요소와 순서가 지정된 요소를 사용하기 때문에 유용하다고 말합니다. 그리고 그래프 패키지는 또한 그들을 그룹화하는 데 사용합니다. ggplot대부분의 모델 피팅 함수는 문자 벡터를 요인으로 강제하므로 결과는 동일합니다. 그러나 코드에 경고가 표시됩니다.

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  

경고 메시지 : In model.matrix.default(mt, mf, contrasts):

변수 Species로 변환factor

한 가지 까다로운 것은 전체 drop=TRUE입니다. 벡터에서는 데이터에없는 요인 수준을 제거하는 데 효과적입니다. 예를 들면 :

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

그러나 ,와 data.frameS의 동작은 [.data.frame()다릅니다 볼 이 이메일을 하거나 ?"[.data.frame". drop=TRUEon data.frames를 사용하면 상상 한대로 작동하지 않습니다.

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

운 좋게도 쉽게 요인을 제거 할 수 있습니다. droplevels() 개별 요인 또는 data.frame(R 2.12 이후)의 모든 요인에 대해 사용되지 않은 요인 수준을 삭제하기 위해 .

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

이것은 당신이 선택한 레벨을 ggplot레전드에 들어 가지 못하게하는 방법 입니다.

내부적으로 factors는 속성 수준 문자형 벡터 ( attributes(iris$Species)및 참조 class(attributes(iris$Species)$levels)) 가있는 정수이며 , 이는 깨끗합니다. 레벨 이름을 변경해야한다면 (그리고 문자열을 사용하고 있었다면) 이것은 훨씬 덜 효율적인 작업 이 될 것 입니다. 특히 ggplot전설의 경우 레벨 이름을 많이 변경합니다 . 문자 벡터로 팩터를 가짜로 만들면 하나의 요소 만 변경하고 실수로 별도의 새 레벨을 생성 할 위험이 있습니다.


1
stringsAsFactors함수가 아닙니다.
IRTFM 2013

30

정렬 된 요소는 굉장합니다. 만약 내가 오렌지를 좋아하고 사과를 싫어하지만 포도는 신경 쓰지 않는다면, 그렇게 말하기 위해 이상한 색인을 관리 할 필요가 없습니다.

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", ]

그것은 깔끔한 응용 프로그램입니다. 그건 생각도 못 했어.
JD Long

무엇을 했 d$f <- ordered(d$f, c("apples", "grapes", "oranges"))습니까? 나는 그것이 데이터 프레임에서 이것을 주문했다고 추측했을 것입니다. 그러나 그 라인을 실행하고 데이터 프레임을 인쇄 한 후에는 아무것도 변하지 않습니다. 인쇄 된 주문이 변경되지 않더라도 내부 주문 만 부과합니까?
Addem

... 네, 제가 쓴 것이 올바른 문장 인 것 같아요. 내가 당신의 요점을 이해한다면, 당신은 우리에게 당신이 요인에 대한 순서를 지정할 수 있다는 것을 보여주고 있습니다. 이것은 당신이 문자열에 대해 할 수없는 일입니다.
Addem

4
ordered ()는 모든 값에서 임의의 순서를 생성합니다. 어휘 학적으로 정렬 된 값을 사용했다는 것은 유감입니다. 그것은 우연입니다. 예를 들어 "Z"가 나쁘고 "3"이 좋지만 레이블이 숫자 알파벳 이 아닌 데이터에 사용하므로 ordered (data, c ( "Z", "B", "A", " 0 ","1 ","2 ","3 ")) 그러면 데이터>"A "를 할 수 있습니다. 행복한 날입니다.
mdsumner

19

A factor는 다른 언어의 열거 형과 가장 유사합니다. 적절한 사용은 규정 된 값 세트 중 하나만 취할 수있는 변수에 대한 것입니다. 이러한 경우 허용되는 모든 값이 특정 데이터 집합에 존재하는 것은 아니며 "빈"수준이이를 정확하게 반영합니다.

몇 가지 예를 고려하십시오. 미국 전역에서 수집 된 일부 데이터의 경우 주를 요인으로 기록해야합니다. 이 경우 특정 주에서 수집 된 사례가 없다는 사실이 관련됩니다. 해당 상태의 데이터가있을 수 있지만 (관심의 이유가 될 수있는 이유가 무엇이든) 그렇지 않은 경우가있었습니다. 고향을 모았다면 요인이되지 않습니다. 가능한 고향의 사전 명시된 세트가 없습니다. 데이터가 전국이 아닌 3 개 도시에서 수집 된 경우 도시가 요인이 될 것입니다. 처음에 세 가지 선택이 주어졌고이 3 개 도시 중 하나에서 관련 사례 / 데이터가 발견되지 않았다면 이는 관련성이 있습니다.

factor문자열 세트에 임의의 정렬 순서를 제공하는 방법을 제공하는 것과 같은 s의 다른 측면은 s의 유용한 2 차 특성 factor이지만 존재 이유는 아닙니다.


3
+1. 브라이언, 데이터에없는 레벨을 캡처하여 머리에 못을 박았다고 생각합니다.
Ricardo Saporta 2013 년

13

통계 분석을하고 실제로 데이터를 탐색 할 때 요인은 환상적입니다. 그러나 그 전에는 데이터를 읽고, 정리하고, 문제를 해결하고, 병합하고, 일반적으로 조작 할 때 요소가 완전히 고통스러워집니다. 최근에는 지난 몇 년 동안과 같이 요소를 더 잘 처리하기 위해 많은 기능이 개선되었습니다. 예를 들어, rbind는 그들과 잘 어울립니다. 하위 집합 기능 후에 빈 수준을 남겨 두는 것이 여전히 성가신 일입니다.

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

요인의 수준을 다시 코딩하고 레이블을 다시 지정하는 것이 간단하며 수준을 재정렬하는 멋진 방법도 있다는 것을 알고 있습니다. 내 뇌는 그것들을 기억할 수 없으며 사용할 때마다 다시 배워야합니다. 레코딩은 현재보다 훨씬 쉬워야합니다.

R의 문자열 함수는 사용하기 매우 쉽고 논리적입니다. 그래서 조작 할 때 일반적으로 요소보다 문자를 선호합니다.


1
요인을 사용한 통계 분석의 예가 있습니까?
JD Long

3
이제 base-R 함수가 droplevels()있습니다. 기본적으로 요인을 재정렬하지 않습니다.
Ben Bolker 2013-10-16

6

얼마나 끔찍한 제목입니까!

많은 추정 함수를 사용하면 요인을 사용하여 더미 변수를 쉽게 정의 할 수 있다고 생각합니다. 그러나 나는 그것들을 사용하지 않습니다.

고유 한 관찰이 거의없는 매우 큰 문자 벡터가있을 때 사용합니다. 이는 특히 문자형 벡터의 문자열이 더 긴 경우 메모리 소비를 줄일 수 있습니다.

추신-제목에 대해 농담입니다. 나는 당신의 트윗을 보았다. ;-)


1
따라서 저장 공간을 절약하기 위해 실제로 사용합니다. 말이 되네요.
JD Long

13
적어도 ;-)에 사용되었습니다. 그러나 몇 R 버전 전에는 문자 저장소가 내부적으로 해시되도록 재 작성되었으므로이 역사적인 주장의 일부는 이제 무효입니다. 스틸 팩터는 그룹화 및 모델링에 매우 유용합니다.
Dirk Eddelbuettel 2010 년

1
?factorR-2.6.0 에 따르면 "정수 값은 4 바이트에 저장되는 반면 문자열에 대한 각 참조에는 4 바이트 또는 8 바이트의 포인터가 필요합니다."라고 말합니다. 문자열에 8 바이트가 필요한 경우 factor로 변환하는 공간을 절약 하시겠습니까?
Joshua Ulrich

2
N <-1000; a <-샘플 (c ( "a", "b", "c"), N, replace = TRUE); print (object.size (a), units = "Kb"); print (object.size (factor (a)), units = "Kb"); 8Kb 4.5Kb이므로 여전히 약간의 공간을 절약하는 것 같습니다.
Eduardo Leoni

2
@Eduardo 나는 4Kb 대 4.2Kb를 얻었습니다. 를 들어 N=100000I 391.8 이하 대 391.5 이하를 얻었다. 따라서 factor는 약간의 메모리를 필요로합니다.
Marek

1

요인은 우수한 "고유 한"배지 엔진입니다. 나는 이것을 여러 번 심하게 재현했으며 때때로 몇 가지 주름에도 불구하고 매우 강력합니다.

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

이 작업을 수행하는 더 좋은 방법이 있다면보고 싶습니다 factor. 이 기능에 대해 논의 할 수 없습니다 .


-2

tapply (및 집계 )는 요인에 의존합니다. 이러한 기능의 정보 ​​대 노력 비율은 매우 높습니다.

예를 들어, 한 줄의 코드 ( 아래의 tapply 호출 )에서 Cut 및 Color별로 다이아몬드의 평균 가격을 얻을 수 있습니다.

> 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
모든 예제가 문자열과 함께 작동하기 때문에 이것은 좋은 예제가 아닙니다.
hadley 2010 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.