How to concatenate factors, without them being converted to integer level?

后端 未结 8 773
粉色の甜心
粉色の甜心 2020-11-28 10:12

I was surprised to see that R will coerce factors into a number when concatenating vectors. This happens even when the levels are the same. For example:

>         


        
相关标签:
8条回答
  • 2020-11-28 10:45

    Here's another way to add to a factor variable when the setup is slightly different:

    facs <- factor(1:3, levels=1:9,
                   labels=c("i", "want", "to", "be", "a", "factor", "not", "an", "integer"))
    facs
    # [1] i       want    to      be      a       factor  not     an      integer
    # Levels: a an be factor i integer not to want
    facs[4:6] <- levels(facs)[4:6]
    facs
    # [1] i      want   to     be     a      factor
    # Levels: i want to be a factor not an integer
    
    0 讨论(0)
  • 2020-11-28 10:47

    Use fct_c from the forcats package (part of the tidyverse).

    > library(forcats)
    > facs <- as.factor(c("i", "want", "to", "be", "a", "factor", "not", "an", "integer"))
    > fct_c(facs[1:3], facs[4:5])
    [1] i    want to   be   a
    Levels: a an be factor i integer not to want
    

    fct_c isn't fooled by concatenations of factors with discrepant numerical codings:

    > x <- as.factor(c('c', 'z'))
    > x
    [1] c z
    Levels: c z
    > y <- as.factor(c('a', 'b', 'z'))
    > y
    [1] a b z
    Levels: a b z
    > c(x, y)
    [1] 1 2 1 2 3
    > fct_c(x, y)
    [1] c z a b z
    Levels: c z a b
    > as.numeric(fct_c(x, y))
    [1] 1 2 3 4 2
    
    0 讨论(0)
  • 2020-11-28 10:47

    Wow, I never realized it did that. Here is a work-around:

    x <- c(facs[1 : 3], facs[4 : 5]) 
    x <- factor(x, levels=1:nlevels(facs), labels=levels(facs))
    x
    

    With the output:

    [1] i    want to   be   a   
    Levels: a an be factor i integer not to want
    

    It will only work if the two vectors have the same levels as here.

    0 讨论(0)
  • 2020-11-28 10:54

    An alternate workaround is to convert the factor to be a character vector, then convert back when you are finshed concatenating.

    cfacs <- as.character(facs)
    x <- c(cfacs[1:3], cfacs[4:5]) 
    
    # Now choose between
    factor(x)
    # and
    factor(x, levels = levels(facs))
    
    0 讨论(0)
  • 2020-11-28 10:57

    From the R Mailing list:

    unlist(list(facs[1 : 3], facs[4 : 5]))
    

    To 'cbind' factors, do

    data.frame(facs[1 : 3], facs[4 : 5])
    
    0 讨论(0)
  • 2020-11-28 10:58

    This is a really bad R gotcha. Along those lines, here's one that just swallowed several hours of my time.

    x <- factor(c("Yes","Yes","No", "No", "Yes", "No"))
    y <- c("Yes", x)
    
    > y
    [1] "Yes" "2"   "2"   "1"   "1"   "2"   "1"  
    > is.factor(y)
    [1] FALSE
    

    It appears to me the better fix is Richie's, which coerces to character.

    > y <- c("Yes", as.character(x))
    > y
    [1] "Yes" "Yes" "Yes" "No"  "No"  "Yes" "No" 
    > y <- as.factor(y)
    > y
    [1] Yes Yes Yes No  No  Yes No 
    Levels: No Yes
    

    As long as you get the levels set properly, as Richie mentions.

    0 讨论(0)
提交回复
热议问题