清理因子水平(折叠多个层次/标签)

什么是最有效(即有效/适当)的方式来清理一个包含多个层次的因素需要被折叠? 也就是说,如何将两个或更多的因素水平合并为一个。

下面是一个例子,其中“是”和“是”两个级别应该折叠为“是”,“否”和“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 

一种select当然是用手和sub打交道。

另一种方法是允许重复标签,然后放下它们

 ## Duplicate levels ==> "Warning: deprecated" xf <- 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(xf) droplevels(xf) 

但是, 有没有更有效的方法


虽然我知道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")) 

    使用levels函数,并将其传递给一个名为list的名称,这些名字是所需级别的名称,元素是应该重命名的当前名称。

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

    正如在levels文件中提到的那样; 也看到那里的例子。

    值:对于“因子”方法,长度至less为“x”级别的string向量,或者指定如何重命名级别的命名列表。

    这也可以在一行中完成,正如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包。 forcats于2016年8月出现在CRAN上。

    有几个便利function可用于清理因子水平:

     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()也接受一个字符向量 ,它是一个未logging的特征。

    首先出现重新排列因子水平

    OP给出的预期产出是

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

    这里的水平是按照它们出现在x中的顺序排列的,它与默认值不同( ?factor一个因子的水平是默认sorting的 )。

    为了符合预期的输出,可以通过折叠级别之前使用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 

    我不知道你的真实用例,但是在这里可以使用任何东西…

     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 

    您可以使用下面的函数来合并/折叠多个因素:

     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 } 

    例:

    初始化x

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

    检查结构

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

    使用function:

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

    重新检查结构:

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