Skip to content
Prev 389279 / 398506 Next

how to remove factors from whole dataframe?

Bert, you got me. Factors seem to be implemented as a sort of one-way street. Mea maxima culpa!

I did some experiments and clearly I misunderstood the way factors in R are set up. I made a series of factors of various kinds such as integer and logical and character and they all are simply a class of "factor" as they have an attribute of 'class' and a typeof() "integer"  as the payload is now a series of small integers.  A dictionary of sorts is kept in the attribute of 'levels' but that seems to always be of type character as in:

levels(somelogsfac)
[1] "FALSE" "TRUE"
[1] "character"


So it sounds like if I read in or create something like a data.frame and I convert some columns to factors to get the results I want like more compressed storage or maybe get ggplot to use my data in some specified order, I also lose any idea of what it was once. That is fine for some purposes such as where the info is wanted in text form, perhaps less so if it has to constantly be converted back into some other form.

But it seems to be a destructive operation in the sense that once done, there is no info preserved as to what was there before. Mind you, that is not really a problem as doing many transformations like as.integer() also replaces what was with what now is.

But in a sense it can be made reversible if you choose to extend it a bit. Below is some code I threw together that if called instead of "factor()" will hide away the original type so it can be used later as an argument to as() to bring back the original type. This is not a change to the original factor() function but I wonder if it would cause any incompatibility if this was made standard. Yes, it costs a little extra in storage.
> # PURPOSE: Given a factor that has embedded knowlege of what
  > # the underlying type once was, carefully reconstruct a vector
  > # to put it back where it should have been. If this is a normal R
  > # vector or factor, just return it as of type character.
  > # If an attribute shows the information of what kind it is
  > # was saved, convert it to that.
  > 
  > unfactormem <- function(unorig) {
    +   what_kind <- attr(unorig, "OnceWas")
    +   unorigchar <- as.character(unorig)
    +   if (is.null(what_kind)) return(unorigchar)
    +   as(unorigchar, what_kind)
    + }
> # Make a logical vector
  > somelogs <- c(TRUE, FALSE, FALSE, TRUE, FALSE)
> # convert it to factor the new way that saves that it was logical.
  > somelogsfac <- factormem(orig)
Error in factormem(orig) : object 'orig' not found
> # display what it looks like
  > somelogsfac
[1] TRUE  FALSE FALSE TRUE  FALSE
attr(,"OnceWas")
[1] logical
Levels: FALSE TRUE
> attributes(somelogsfac)
$levels
[1] "FALSE" "TRUE" 

$class
[1] "factor"

$OnceWas
[1] "logical"
> attr(somelogsfac, "OnceWas")
[1] "logical"
> # Revivify it by hand, not the function I made.
  > revived <- as(as.character(somelogsfac), attr(somelogsfac, "OnceWas"))
> # show what it looks like:
  > revived
[1]  TRUE FALSE FALSE  TRUE FALSE
> typeof(revived)
[1] "logical"
> # Alternately, use the function I created to bring it back.
  > 
  > unfactormem(somelogsfac)
[1]  TRUE FALSE FALSE  TRUE FALSE
> typeof(unfactormem(somelogsfac))
[1] "logical"
> # A complex example:
  > 
  > somecomplex <- c( 3+5i, 4+6i, 13, 4+6i, 7i, 13)
[1] "complex"
$levels
[1] "0+7i"  "3+5i"  "4+6i"  "13+0i"

$class
[1] "factor"

$OnceWas
[1] "complex"
[1]  3+5i  4+6i 13+0i  4+6i  0+7i 13+0i
[1] "complex"


AGAIN, I am not asking this be done as a change in R, just that I think it is an idea of how to be able to say undo factorization properly when needed, such as before saving it to disk in some data structure, or when passing it for some other analysis where a non-factor form would work better.

NOTE: I threw this together quickly and may well have made errors or not made it bulletproof. Feel free to point out where I am wrong or how to improve it.

I also note my approach is partially based on  interactions I once had with Adrian Dusa when he shared his package "declared" and he needed to maintain additional info on some data brought into R that had multiple distinct categories of missing data. It had to carefully use attributes but also did much more to integrate the functionality more fully. So, yes, that might be something that could be done but this is just an academic exercise for me.

-----Original Message-----
From: Bert Gunter <bgunter.4567 at gmail.com> 
Sent: Sunday, September 19, 2021 7:19 PM
To: Avi Gross <avigross at verizon.net>
Cc: Luigi Marongiu <marongiu.luigi at gmail.com>; Rui Barradas <ruipbarradas at sapo.pt>; r-help <r-help at r-project.org>
Subject: Re: [R] how to remove factors from whole dataframe?

You do not understand factors. There is no "base type" that can be recovered.
[1] whoa baby
Levels: whoa baby
[1] 1 2
attr(,"levels")
[1] "whoa" "baby"
[1] "integer"


Bert Gunter

"The trouble with having an open mind is that people keep coming along and sticking things into it."
-- Opus (aka Berkeley Breathed in his "Bloom County" comic strip )
On Sun, Sep 19, 2021 at 2:15 PM Avi Gross via R-help <r-help at r-project.org> wrote: