programing

요인 수준 정리 (여러 수준 / 라벨 축소)

itsource 2021. 1. 18. 07:58
반응형

요인 수준 정리 (여러 수준 / 라벨 축소)


축소해야하는 여러 수준을 포함하는 요인을 정리하는 가장 효과적인 (즉, 효율적 / 적절한) 방법은 무엇입니까? 즉, 두 개 이상의 요인 수준을 하나로 결합하는 방법입니다.

다음은 두 수준 "예"와 "Y"를 "예"로 축소하고 "아니요"와 "N"을 "아니요"로 축소 한 예입니다.

## Given: 
x <- c("Y", "Y", "Yes", "N", "No", "H")   # The 'H' should be treated as NA

## expectedOutput
[1] Yes  Yes  Yes  No   No   <NA>
Levels: Yes No  # <~~ NOTICE ONLY **TWO** LEVELS

한 가지 옵션은 물론 손으로 사용하기 전에 현을 청소하는 것 sub입니다.

또 다른 방법은 중복 라벨을 허용 한 다음 삭제하는 것입니다.

## Duplicate levels ==> "Warning: deprecated"
x.f <- factor(x, levels=c("Y", "Yes", "No", "N"), labels=c("Yes", "Yes", "No", "No"))

## the above line can be wrapped in either of the next two lines
factor(x.f)      
droplevels(x.f) 

그러나 더 효과적인 방법이 있습니까?


levelslabels인수가 벡터 여야 한다는 것을 알고 있지만 , 목록과 명명 된 목록 및 명명 된 벡터를 실험하여 무슨 일이 일어나는지 확인했습니다. 말할 필요도없이 다음 중 어느 것도 내 목표에 더 가까워지지 않았습니다.

  factor(x, levels=list(c("Yes", "Y"), c("No", "N")), labels=c("Yes", "No"))
  factor(x, levels=c("Yes", "No"), labels=list(c("Yes", "Y"), c("No", "N")))

  factor(x, levels=c("Y", "Yes", "No", "N"), labels=c(Y="Yes", Yes="Yes", No="No", N="No"))
  factor(x, levels=c("Y", "Yes", "No", "N"), labels=c(Yes="Y", Yes="Yes", No="No", No="N"))
  factor(x, levels=c("Yes", "No"), labels=c(Y="Yes", Yes="Yes", No="No", N="No"))

업데이트 2 : 빠르게 표준이되고있는 새로운 "tidyverse"방식을 보여주는 Uwe의 답변을 참조하십시오.

업데이트 1 : 중복 된 레이블 (레벨은 아님)이 이제 실제로 허용됩니다 (위의 의견에 따라). Tim의 대답을 참조하십시오.

원래 답변, 그러나 여전히 유용하고 흥미 롭습니다 levels. 정확히이 목적을 위해 명명 된 목록을 함수 에 전달하는 알려진 옵션이 거의 없습니다 . 목록의 이름은 원하는 레벨 이름이어야하며 요소는 이름을 바꿔야하는 현재 이름이어야합니다. 일부 (OP 포함, Tim의 답변에 대한 Ricardo의 의견 참조)는 읽기 쉽도록 이것을 선호합니다.

x <- c("Y", "Y", "Yes", "N", "No", "H", NA)
x <- factor(x)
levels(x) <- list("Yes"=c("Y", "Yes"), "No"=c("N", "No"))
x
## [1] Yes  Yes  Yes  No   No   <NA>  <NA>
## Levels: Yes No

levels문서 에서 언급했듯이 ; 또한 거기에있는 예를 참조하십시오.

value : 'factor'방법의 경우 길이가 'x'레벨 수 이상인 문자열 벡터 또는 레벨 이름을 바꾸는 방법을 지정하는 명명 된 목록입니다.

Marek이 여기에서 한 것처럼 한 줄로도이 작업을 수행 할 수 있습니다. https://stackoverflow.com/a/10432263/210673 ; levels<-마법은 여기에 설명 https://stackoverflow.com/a/10491881/210673 .

> `levels<-`(factor(x), list(Yes=c("Y", "Yes"), No=c("N", "No")))
[1] Yes  Yes  Yes  No   No   <NA>
Levels: Yes No

질문의 제목이 요인 수준 정리 (여러 수준 / 레이블 축소) 이므로 forcats완전성을 위해 여기에서도 패키지를 언급해야합니다. forcats2016 년 8 월 CRAN에 등장했습니다.

요인 수준을 정리하는 데 사용할 수있는 몇 가지 편의 기능이 있습니다.

x <- c("Y", "Y", "Yes", "N", "No", "H") 

library(forcats)

요인 수준을 수동으로 정의 된 그룹으로 축소

fct_collapse(x, Yes = c("Y", "Yes"), No = c("N", "No"), NULL = "H")
#[1] Yes  Yes  Yes  No   No   <NA>
#Levels: No Yes

수동으로 요인 수준 변경

fct_recode(x, Yes = "Y", Yes = "Yes", No = "N", No = "No", NULL = "H")
#[1] Yes  Yes  Yes  No   No   <NA>
#Levels: No Yes

요인 수준의 레이블을 자동으로 다시 지정하고 필요에 따라 축소

fun <- function(z) {
  z[z == "Y"] <- "Yes"
  z[z == "N"] <- "No"
  z[!(z %in% c("Yes", "No"))] <- NA
  z
}
fct_relabel(factor(x), fun)
#[1] Yes  Yes  Yes  No   No   <NA>
#Levels: No Yes

참고 fct_relabel()그것은 기대 때문에, 요소 수준에서 작동 요소 첫 번째 인수로합니다. 두 가지 다른 기능, fct_collapse()그리고 fct_recode(), 또한 동의를 문자 벡터 문서화되지 않은 기능입니다.

첫 출현으로 요인 수준 재정렬

OP가 제공하는 예상 출력은 다음과 같습니다.

[1] Yes  Yes  Yes  No   No   <NA>
Levels: Yes No

여기에서는 x기본값과 다른 수준으로 표시되는 순서가 지정됩니다 ( ?factor: 요인 수준은 기본적으로 정렬 됨 ).

예상되는 출력에 맞추려면 레벨을 축소 fct_inorder() 하기 전에 다음 을 사용하여 수행 할 수 있습니다 .

fct_collapse(fct_inorder(x), Yes = c("Y", "Yes"), No = c("N", "No"), NULL = "H")
fct_recode(fct_inorder(x), Yes = "Y", Yes = "Yes", No = "N", No = "No", NULL = "H")

둘 다 동일한 순서로 레벨이있는 ​​예상 출력을 지금 반환합니다.


아마도 명명 된 벡터를 키로 사용할 수 있습니다.

> factor(unname(c(Y = "Yes", Yes = "Yes", N = "No", No = "No", H = NA)[x]))
[1] Yes  Yes  Yes  No   No   <NA>
Levels: No Yes

이것은 당신의 마지막 시도와 매우 유사 해 보입니다 ...하지만 이것은 작동합니다 :-)


또 다른 방법은 매핑을 포함하는 테이블을 만드는 것입니다.

# stacking the list from Aaron's answer
fmap = stack(list(Yes = c("Y", "Yes"), No = c("N", "No")))

fmap$ind[ match(x, fmap$values) ]
# [1] Yes  Yes  Yes  No   No   <NA>
# Levels: No Yes

# or...

library(data.table)
setDT(fmap)[x, on=.(values), ind ]
# [1] Yes  Yes  Yes  No   No   <NA>
# Levels: No Yes

나는지도를 요약하는 쉽게 검사 할 수있는 객체를 남기기 때문에 이런 방식을 선호합니다. data.table 코드는 해당 구문의 다른 조인처럼 보입니다.


물론 fmap변경 사항을 요약하는 것과 같은 객체를 원하지 않는 경우 "한 줄"이 될 수 있습니다.

library(data.table)
setDT(stack(list(Yes = c("Y", "Yes"), No = c("N", "No"))))[x, on=.(values), ind ]
# [1] Yes  Yes  Yes  No   No   <NA>
# Levels: No Yes

이 답변을 추가하여 데이터 프레임의 특정 요소에서 작동하는 허용 된 답변을 보여줍니다. 처음에는 분명하지 않았기 때문입니다 (아마도 그랬어 야했지만).

levels(df$var1)
# "0" "1" "Z"
summary(df$var1)
#    0    1    Z 
# 7012 2507    8 
levels(df$var1) <- list("0"=c("Z", "0"), "1"=c("1"))
levels(df$var1)
# "0" "1"
summary(df$var1)
#    0    1 
# 7020 2507

R 3.5.0 (2018-04-23)부터 명확하고 간단한 한 줄로이를 수행 할 수 있습니다.

x = c("Y", "Y", "Yes", "N", "No", "H") # The 'H' should be treated as NA

tmp = factor(x, levels= c("Y", "Yes", "N", "No"), labels= c("Yes", "Yes", "No", "No"))
tmp
# [1] Yes  Yes  Yes  No   No   <NA>
# Levels: Yes No

한 줄, 여러 값을 동일한 수준에 매핑하고 누락 된 수준에 대해 NA를 설정합니다. "– h / t @Aaron


나는 당신의 실제 사용 사례를 모르지만 strtrim여기서는 아무 쓸모가 없을 것입니다 ...

factor( strtrim( x , 1 ) , levels = c("Y" , "N" ) , labels = c("Yes" , "No" ) )
#[1] Yes  Yes  Yes  No   No   <NA>
#Levels: Yes No

@Aaron의 접근 방식과 비슷하지만 약간 더 간단합니다.

x <- c("Y", "Y", "Yes", "N", "No", "H")
x <- factor(x)
# levels(x)  
# [1] "H"   "N"   "No"  "Y"   "Yes"
# NB: the offending levels are 1, 2, & 4
levels(x)[c(1,2,4)] <- c(NA, "No", "Yes")
x
# [1] Yes  Yes  Yes  No   No   <NA>
# Levels: No Yes

You may use the below function for combining/collapsing multiple factors:

combofactor <- function(pattern_vector,
         replacement_vector,
         data) {
 levels <- levels(data)
 for (i in 1:length(pattern_vector))
      levels[which(pattern_vector[i] == levels)] <-
        replacement_vector[i]
 levels(data) <- levels
  data
}

Example:

Initialize x

x <- factor(c(rep("Y",20),rep("N",20),rep("y",20),
rep("yes",20),rep("Yes",20),rep("No",20)))

Check the structure

str(x)
# Factor w/ 6 levels "N","No","y","Y",..: 4 4 4 4 4 4 4 4 4 4 ...

Use the function:

x_new <- combofactor(c("Y","N","y","yes"),c("Yes","No","Yes","Yes"),x)

Recheck the structure:

str(x_new)
# Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 2 2 2 ...

First let's note that in this specific case we can use partial matching:

x <- c("Y", "Y", "Yes", "N", "No", "H")
y <- c("Yes","No")
x <- factor(y[pmatch(x,y,duplicates.ok = TRUE)])
# [1] Yes  Yes  Yes  No   No   <NA>
# Levels: No Yes

In a more general case I'd go with dplyr::recode:

library(dplyr)
x <- c("Y", "Y", "Yes", "N", "No", "H")
y <- c(Y="Yes",N="No")
x <- recode(x,!!!y)
x <- factor(x,y)
# [1] Yes  Yes  Yes  No   No   <NA>
# Levels: Yes No

Slightly altered if the starting point is a factor:

x <- factor(c("Y", "Y", "Yes", "N", "No", "H"))
y <- c(Y="Yes",N="No")
x <- recode_factor(x,!!!y)
x <- factor(x,y)
# [1] Yes  Yes  Yes  No   No   <NA>
# Levels: Yes No

ReferenceURL : https://stackoverflow.com/questions/19410108/cleaning-up-factor-levels-collapsing-multiple-levels-labels

반응형