Quantcast

factor S4 class is NA when as.character method exists

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

factor S4 class is NA when as.character method exists

Dan Murphy
Hello,

'factor' returns <NA> for my S4 object when the class is given an
"as.character" method. Here is a minimal example:

> setClass("foo", contains="numeric")
> bar <- new("foo", 12)
> factor(bar)
[1] 12
Levels: 12
> setMethod("as.character", "foo", function(x) paste("x=", x@.Data))
[1] "as.character"
> as.character(bar)
[1] "x= 12"
> factor(bar)
[1] <NA>
Levels: 12

I would like to 'aggregate' by my S4 objects, but 'factor' seems to be
getting in the way. Is there an 'as.character' implementation that works
better for S4 classes? I searched help.search("factor S4 class") and
help.search("factor S4 as.character") without success.

Thank you.

Dan Murphy

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: factor S4 class is NA when as.character method exists

Peter Dalgaard-2

On Jan 23, 2012, at 16:07 , Dan Murphy wrote:

> Hello,
>
> 'factor' returns <NA> for my S4 object when the class is given an
> "as.character" method. Here is a minimal example:
>
>> setClass("foo", contains="numeric")
>> bar <- new("foo", 12)
>> factor(bar)
> [1] 12
> Levels: 12
>> setMethod("as.character", "foo", function(x) paste("x=", x@.Data))
> [1] "as.character"
>> as.character(bar)
> [1] "x= 12"
>> factor(bar)
> [1] <NA>
> Levels: 12
>
> I would like to 'aggregate' by my S4 objects, but 'factor' seems to be
> getting in the way. Is there an 'as.character' implementation that works
> better for S4 classes? I searched help.search("factor S4 class") and
> help.search("factor S4 as.character") without success.

Single-stepping the factor call would have shown you that the real problem is that you don't have a unique() method for your class:

> unique(bar)
[1] 12

i.e., you are getting the default numeric method, which returns a numeric vector, so the levels become as.character(unique(bar)) which is c("12") and doesn't match any of the values of as.character(bar).

So, either provide a unique() method, or use factor(as.character(bar)).

>
> Thank you.
>
> Dan Murphy
>
> [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

--
Peter Dalgaard, Professor
Center for Statistics, Copenhagen Business School
Solbjerg Plads 3, 2000 Frederiksberg, Denmark
Phone: (+45)38153501
Email: [hidden email]  Priv: [hidden email]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: factor S4 class is NA when as.character method exists

Dan Murphy
Thank you for your reply, Peter. But that didn't work either. Continuing
the example:

setGeneric("unique")
setMethod("unique", "foo",  function(x,  incomparables = FALSE, ...){
    y <- callNextMethod(x = getDataPart(x),  incomparables = incomparables,
...)
    new("foo", y)
    })

> unique(bar)
An object of class "foo"
[1] 12
> factor(bar)
[1] <NA>
Levels: 12

Indeed I had tried stepping through the 'factor' call, but perhaps in an
unsophisticated manner -- I had copied the body of 'factor' to a local
version of the function:

myfactor <- function (x = character(), levels, labels = levels, exclude =
NA,
    ordered = is.ordered(x))
{
    if (is.null(x)) ...
etc.

And 'myfactor' worked as desired:

> myfactor(bar)
[1] x= 12
Levels: x= 12

I hypothesized that there might be a deeper interaction of an S4
'as.character' method with base::factor, but, having exhausted my woeful
lack of expertise, I decided to write my original email.

Thanks for your consideration.

Dan

On Mon, Jan 23, 2012 at 8:25 AM, peter dalgaard <[hidden email]> wrote:

>
> On Jan 23, 2012, at 16:07 , Dan Murphy wrote:
>
> > Hello,
> >
> > 'factor' returns <NA> for my S4 object when the class is given an
> > "as.character" method. Here is a minimal example:
> >
> >> setClass("foo", contains="numeric")
> >> bar <- new("foo", 12)
> >> factor(bar)
> > [1] 12
> > Levels: 12
> >> setMethod("as.character", "foo", function(x) paste("x=", x@.Data))
> > [1] "as.character"
> >> as.character(bar)
> > [1] "x= 12"
> >> factor(bar)
> > [1] <NA>
> > Levels: 12
> >
> > I would like to 'aggregate' by my S4 objects, but 'factor' seems to be
> > getting in the way. Is there an 'as.character' implementation that works
> > better for S4 classes? I searched help.search("factor S4 class") and
> > help.search("factor S4 as.character") without success.
>
> Single-stepping the factor call would have shown you that the real problem
> is that you don't have a unique() method for your class:
>
> > unique(bar)
> [1] 12
>
> i.e., you are getting the default numeric method, which returns a numeric
> vector, so the levels become as.character(unique(bar)) which is c("12") and
> doesn't match any of the values of as.character(bar).
>
> So, either provide a unique() method, or use factor(as.character(bar)).
>
> >
> > Thank you.
> >
> > Dan Murphy
> >
> >       [[alternative HTML version deleted]]
> >
> > ______________________________________________
> > [hidden email] mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
>
> --
> Peter Dalgaard, Professor
> Center for Statistics, Copenhagen Business School
> Solbjerg Plads 3, 2000 Frederiksberg, Denmark
> Phone: (+45)38153501
> Email: [hidden email]  Priv: [hidden email]
>
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: factor S4 class is NA when as.character method exists

William Dunlap
Here is code that does make factor() work on a new
class like yours.  It uses Sv3 methods.
  > setClass("foo", contains="numeric")
  [1] "foo"
  > as.character.foo <- function(x) paste("x=",x@.Data,sep="")
  > unique.foo <- function(x, ...) structure(NextMethod("unique"), class=class(x))
  > someFoo <- new("foo", c(11, 13, 11, 13, 12))
  > str(factor(someFoo))
   Factor w/ 3 levels "x=11","x=12",..: 1 3 1 3 2

It would be nice to have a list of methods that one
needs to define for a new class in order to make it
do the "basic" things you expect.

Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com

> -----Original Message-----
> From: [hidden email] [mailto:[hidden email]] On Behalf Of Dan Murphy
> Sent: Monday, January 23, 2012 10:31 PM
> To: peter dalgaard
> Cc: [hidden email]
> Subject: Re: [Rd] factor S4 class is NA when as.character method exists
>
> Thank you for your reply, Peter. But that didn't work either. Continuing
> the example:
>
> setGeneric("unique")
> setMethod("unique", "foo",  function(x,  incomparables = FALSE, ...){
>     y <- callNextMethod(x = getDataPart(x),  incomparables = incomparables,
> ...)
>     new("foo", y)
>     })
>
> > unique(bar)
> An object of class "foo"
> [1] 12
> > factor(bar)
> [1] <NA>
> Levels: 12
>
> Indeed I had tried stepping through the 'factor' call, but perhaps in an
> unsophisticated manner -- I had copied the body of 'factor' to a local
> version of the function:
>
> myfactor <- function (x = character(), levels, labels = levels, exclude =
> NA,
>     ordered = is.ordered(x))
> {
>     if (is.null(x)) ...
> etc.
>
> And 'myfactor' worked as desired:
>
> > myfactor(bar)
> [1] x= 12
> Levels: x= 12
>
> I hypothesized that there might be a deeper interaction of an S4
> 'as.character' method with base::factor, but, having exhausted my woeful
> lack of expertise, I decided to write my original email.
>
> Thanks for your consideration.
>
> Dan
>
> On Mon, Jan 23, 2012 at 8:25 AM, peter dalgaard <[hidden email]> wrote:
>
> >
> > On Jan 23, 2012, at 16:07 , Dan Murphy wrote:
> >
> > > Hello,
> > >
> > > 'factor' returns <NA> for my S4 object when the class is given an
> > > "as.character" method. Here is a minimal example:
> > >
> > >> setClass("foo", contains="numeric")
> > >> bar <- new("foo", 12)
> > >> factor(bar)
> > > [1] 12
> > > Levels: 12
> > >> setMethod("as.character", "foo", function(x) paste("x=", x@.Data))
> > > [1] "as.character"
> > >> as.character(bar)
> > > [1] "x= 12"
> > >> factor(bar)
> > > [1] <NA>
> > > Levels: 12
> > >
> > > I would like to 'aggregate' by my S4 objects, but 'factor' seems to be
> > > getting in the way. Is there an 'as.character' implementation that works
> > > better for S4 classes? I searched help.search("factor S4 class") and
> > > help.search("factor S4 as.character") without success.
> >
> > Single-stepping the factor call would have shown you that the real problem
> > is that you don't have a unique() method for your class:
> >
> > > unique(bar)
> > [1] 12
> >
> > i.e., you are getting the default numeric method, which returns a numeric
> > vector, so the levels become as.character(unique(bar)) which is c("12") and
> > doesn't match any of the values of as.character(bar).
> >
> > So, either provide a unique() method, or use factor(as.character(bar)).
> >
> > >
> > > Thank you.
> > >
> > > Dan Murphy
> > >
> > >       [[alternative HTML version deleted]]
> > >
> > > ______________________________________________
> > > [hidden email] mailing list
> > > https://stat.ethz.ch/mailman/listinfo/r-devel
> >
> > --
> > Peter Dalgaard, Professor
> > Center for Statistics, Copenhagen Business School
> > Solbjerg Plads 3, 2000 Frederiksberg, Denmark
> > Phone: (+45)38153501
> > Email: [hidden email]  Priv: [hidden email]
> >
> >
>
> [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: factor S4 class is NA when as.character method exists

Prof Brian Ripley
On 24/01/2012 17:17, William Dunlap wrote:
> Here is code that does make factor() work on a new
> class like yours.  It uses Sv3 methods.

Which is necessary as unique() is an S3 generic in the base namespace,
and creating some other function named 'unique' elsewhere (which is what
setGeneric does) is ineffective.

>    >  setClass("foo", contains="numeric")
>    [1] "foo"
>    >  as.character.foo<- function(x) paste("x=",x@.Data,sep="")
>    >  unique.foo<- function(x, ...) structure(NextMethod("unique"), class=class(x))
>    >  someFoo<- new("foo", c(11, 13, 11, 13, 12))
>    >  str(factor(someFoo))
>     Factor w/ 3 levels "x=11","x=12",..: 1 3 1 3 2
>
> It would be nice to have a list of methods that one
> needs to define for a new class in order to make it
> do the "basic" things you expect.

It would be nice to have a list of such things ... I suspect they depend
more heavily on the value of 'you' than the class.

> Bill Dunlap
> Spotfire, TIBCO Software
> wdunlap tibco.com
>
>> -----Original Message-----
>> From: [hidden email] [mailto:[hidden email]] On Behalf Of Dan Murphy
>> Sent: Monday, January 23, 2012 10:31 PM
>> To: peter dalgaard
>> Cc: [hidden email]
>> Subject: Re: [Rd] factor S4 class is NA when as.character method exists
>>
>> Thank you for your reply, Peter. But that didn't work either. Continuing
>> the example:
>>
>> setGeneric("unique")
>> setMethod("unique", "foo",  function(x,  incomparables = FALSE, ...){
>>      y<- callNextMethod(x = getDataPart(x),  incomparables = incomparables,
>> ...)
>>      new("foo", y)
>>      })
>>
>>> unique(bar)
>> An object of class "foo"
>> [1] 12
>>> factor(bar)
>> [1]<NA>
>> Levels: 12
>>
>> Indeed I had tried stepping through the 'factor' call, but perhaps in an
>> unsophisticated manner -- I had copied the body of 'factor' to a local
>> version of the function:
>>
>> myfactor<- function (x = character(), levels, labels = levels, exclude =
>> NA,
>>      ordered = is.ordered(x))
>> {
>>      if (is.null(x)) ...
>> etc.
>>
>> And 'myfactor' worked as desired:
>>
>>> myfactor(bar)
>> [1] x= 12
>> Levels: x= 12
>>
>> I hypothesized that there might be a deeper interaction of an S4
>> 'as.character' method with base::factor, but, having exhausted my woeful
>> lack of expertise, I decided to write my original email.
>>
>> Thanks for your consideration.
>>
>> Dan
>>
>> On Mon, Jan 23, 2012 at 8:25 AM, peter dalgaard<[hidden email]>  wrote:
>>
>>>
>>> On Jan 23, 2012, at 16:07 , Dan Murphy wrote:
>>>
>>>> Hello,
>>>>
>>>> 'factor' returns<NA>  for my S4 object when the class is given an
>>>> "as.character" method. Here is a minimal example:
>>>>
>>>>> setClass("foo", contains="numeric")
>>>>> bar<- new("foo", 12)
>>>>> factor(bar)
>>>> [1] 12
>>>> Levels: 12
>>>>> setMethod("as.character", "foo", function(x) paste("x=", x@.Data))
>>>> [1] "as.character"
>>>>> as.character(bar)
>>>> [1] "x= 12"
>>>>> factor(bar)
>>>> [1]<NA>
>>>> Levels: 12
>>>>
>>>> I would like to 'aggregate' by my S4 objects, but 'factor' seems to be
>>>> getting in the way. Is there an 'as.character' implementation that works
>>>> better for S4 classes? I searched help.search("factor S4 class") and
>>>> help.search("factor S4 as.character") without success.
>>>
>>> Single-stepping the factor call would have shown you that the real problem
>>> is that you don't have a unique() method for your class:
>>>
>>>> unique(bar)
>>> [1] 12
>>>
>>> i.e., you are getting the default numeric method, which returns a numeric
>>> vector, so the levels become as.character(unique(bar)) which is c("12") and
>>> doesn't match any of the values of as.character(bar).
>>>
>>> So, either provide a unique() method, or use factor(as.character(bar)).
>>>
>>>>
>>>> Thank you.
>>>>
>>>> Dan Murphy
>>>>
>>>>        [[alternative HTML version deleted]]
>>>>
>>>> ______________________________________________
>>>> [hidden email] mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>
>>> --
>>> Peter Dalgaard, Professor
>>> Center for Statistics, Copenhagen Business School
>>> Solbjerg Plads 3, 2000 Frederiksberg, Denmark
>>> Phone: (+45)38153501
>>> Email: [hidden email]  Priv: [hidden email]
>>>
>>>
>>
>> [[alternative HTML version deleted]]
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel


--
Brian D. Ripley,                  [hidden email]
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: factor S4 class is NA when as.character method exists

John Chambers-2


On 1/24/12 9:35 AM, Prof Brian Ripley wrote:
> On 24/01/2012 17:17, William Dunlap wrote:
>> Here is code that does make factor() work on a new
>> class like yours.  It uses Sv3 methods.
>
> Which is necessary as unique() is an S3 generic in the base namespace,
> and creating some other function named 'unique' elsewhere (which is
> what setGeneric does) is ineffective.

Creating a simple generic version of unique() (not just "some other
function...") causes S4 method selection to work for code that has
access to that function, but calls from within the base namespace will
still see the S3 version.

The safest technique is to ensure that both S4 and S3 dispatch see the
same method.
------------------------
setClass("myFactor", contains = "factor")

setGeneric("unique")

unique.myFactor <- function (x, incomparables = FALSE, ...)
     unique(as.character(x))

setMethod("unique", "myFactor", unique.myFactor)
------------------------

With this in PkgA and suitable exports from the namespace:

> library(PkgA)
> methods("unique")
[1] unique.POSIXlt         unique.array           unique.data.frame
[4] unique.default         unique.matrix          unique.myFactor
[7] unique.numeric_version
> showMethods("unique")
Function: unique (package base)
x="ANY"
x="myFactor"

Someday there may be a more natural approach.

John

>
>> >  setClass("foo", contains="numeric")
>>    [1] "foo"
>> >  as.character.foo<- function(x) paste("x=",x@.Data,sep="")
>> >  unique.foo<- function(x, ...) structure(NextMethod("unique"),
>> class=class(x))
>> >  someFoo<- new("foo", c(11, 13, 11, 13, 12))
>> >  str(factor(someFoo))
>>     Factor w/ 3 levels "x=11","x=12",..: 1 3 1 3 2
>>
>> It would be nice to have a list of methods that one
>> needs to define for a new class in order to make it
>> do the "basic" things you expect.
>
> It would be nice to have a list of such things ... I suspect they
> depend more heavily on the value of 'you' than the class.
>
>> Bill Dunlap
>> Spotfire, TIBCO Software
>> wdunlap tibco.com
>>
>>> -----Original Message-----
>>> From: [hidden email]
>>> [mailto:[hidden email]] On Behalf Of Dan Murphy
>>> Sent: Monday, January 23, 2012 10:31 PM
>>> To: peter dalgaard
>>> Cc: [hidden email]
>>> Subject: Re: [Rd] factor S4 class is NA when as.character method exists
>>>
>>> Thank you for your reply, Peter. But that didn't work either.
>>> Continuing
>>> the example:
>>>
>>> setGeneric("unique")
>>> setMethod("unique", "foo",  function(x,  incomparables = FALSE, ...){
>>>      y<- callNextMethod(x = getDataPart(x),  incomparables =
>>> incomparables,
>>> ...)
>>>      new("foo", y)
>>>      })
>>>
>>>> unique(bar)
>>> An object of class "foo"
>>> [1] 12
>>>> factor(bar)
>>> [1]<NA>
>>> Levels: 12
>>>
>>> Indeed I had tried stepping through the 'factor' call, but perhaps
>>> in an
>>> unsophisticated manner -- I had copied the body of 'factor' to a local
>>> version of the function:
>>>
>>> myfactor<- function (x = character(), levels, labels = levels,
>>> exclude =
>>> NA,
>>>      ordered = is.ordered(x))
>>> {
>>>      if (is.null(x)) ...
>>> etc.
>>>
>>> And 'myfactor' worked as desired:
>>>
>>>> myfactor(bar)
>>> [1] x= 12
>>> Levels: x= 12
>>>
>>> I hypothesized that there might be a deeper interaction of an S4
>>> 'as.character' method with base::factor, but, having exhausted my
>>> woeful
>>> lack of expertise, I decided to write my original email.
>>>
>>> Thanks for your consideration.
>>>
>>> Dan
>>>
>>> On Mon, Jan 23, 2012 at 8:25 AM, peter dalgaard<[hidden email]>
>>> wrote:
>>>
>>>>
>>>> On Jan 23, 2012, at 16:07 , Dan Murphy wrote:
>>>>
>>>>> Hello,
>>>>>
>>>>> 'factor' returns<NA>  for my S4 object when the class is given an
>>>>> "as.character" method. Here is a minimal example:
>>>>>
>>>>>> setClass("foo", contains="numeric")
>>>>>> bar<- new("foo", 12)
>>>>>> factor(bar)
>>>>> [1] 12
>>>>> Levels: 12
>>>>>> setMethod("as.character", "foo", function(x) paste("x=", x@.Data))
>>>>> [1] "as.character"
>>>>>> as.character(bar)
>>>>> [1] "x= 12"
>>>>>> factor(bar)
>>>>> [1]<NA>
>>>>> Levels: 12
>>>>>
>>>>> I would like to 'aggregate' by my S4 objects, but 'factor' seems
>>>>> to be
>>>>> getting in the way. Is there an 'as.character' implementation that
>>>>> works
>>>>> better for S4 classes? I searched help.search("factor S4 class") and
>>>>> help.search("factor S4 as.character") without success.
>>>>
>>>> Single-stepping the factor call would have shown you that the real
>>>> problem
>>>> is that you don't have a unique() method for your class:
>>>>
>>>>> unique(bar)
>>>> [1] 12
>>>>
>>>> i.e., you are getting the default numeric method, which returns a
>>>> numeric
>>>> vector, so the levels become as.character(unique(bar)) which is
>>>> c("12") and
>>>> doesn't match any of the values of as.character(bar).
>>>>
>>>> So, either provide a unique() method, or use
>>>> factor(as.character(bar)).
>>>>
>>>>>
>>>>> Thank you.
>>>>>
>>>>> Dan Murphy
>>>>>
>>>>>        [[alternative HTML version deleted]]
>>>>>
>>>>> ______________________________________________
>>>>> [hidden email] mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>
>>>> --
>>>> Peter Dalgaard, Professor
>>>> Center for Statistics, Copenhagen Business School
>>>> Solbjerg Plads 3, 2000 Frederiksberg, Denmark
>>>> Phone: (+45)38153501
>>>> Email: [hidden email]  Priv: [hidden email]
>>>>
>>>>
>>>
>>>     [[alternative HTML version deleted]]
>>>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: factor S4 class is NA when as.character method exists

Dan Murphy
In reply to this post by Prof Brian Ripley
But my NA issue does not arise from the S3 generic 'unique' alone but from
the interaction of that S3 generic with the non-S3 generic 'as.character'
(R.methodsS3::isGenericS3.default("as.character") returns FALSE). Here is
Bill's code with his S3 as.character foo method replaced by my S4.

> setClass("foo", contains="numeric")
[1] "foo"
> setMethod("as.character", "foo", function(x) paste("x=", x@.Data))
[1] "as.character"
> unique.foo <- function(x, ...) structure(NextMethod("unique"),
class=class(x))
> someFoo <- new("foo", c(11, 13, 11, 13, 12))
> str(factor(someFoo))
 Factor w/ 3 levels "11","12","13": NA NA NA NA NA

I thought I remember reading at some point in the past that package
developers were encouraged to implement methods in S4 rather than S3
because ... S3 support would dissipate? I can't remember the details. ...

In any event, this example suggests that I should first implement methods
in S3 if possible because that approach is more robust, at least as
measured by potential S3 pitfalls. I have no problems with that.

Thanks for the hints.

- Dan

On Tue, Jan 24, 2012 at 9:35 AM, Prof Brian Ripley <[hidden email]>wrote:

> On 24/01/2012 17:17, William Dunlap wrote:
>
>> Here is code that does make factor() work on a new
>> class like yours.  It uses Sv3 methods.
>>
>
> Which is necessary as unique() is an S3 generic in the base namespace, and
> creating some other function named 'unique' elsewhere (which is what
> setGeneric does) is ineffective.
>
>
>    >  setClass("foo", contains="numeric")
>>   [1] "foo"
>>   >  as.character.foo<- function(x) paste("x=",x@.Data,sep="")
>>   >  unique.foo<- function(x, ...) structure(NextMethod("unique")**,
>> class=class(x))
>>   >  someFoo<- new("foo", c(11, 13, 11, 13, 12))
>>   >  str(factor(someFoo))
>>    Factor w/ 3 levels "x=11","x=12",..: 1 3 1 3 2
>>
>> It would be nice to have a list of methods that one
>> needs to define for a new class in order to make it
>> do the "basic" things you expect.
>>
>
> It would be nice to have a list of such things ... I suspect they depend
> more heavily on the value of 'you' than the class.
>
>
>  Bill Dunlap
>> Spotfire, TIBCO Software
>> wdunlap tibco.com
>>
>>  -----Original Message-----
>>> From: [hidden email] [mailto:r-devel-bounces@r-**
>>> project.org <[hidden email]>] On Behalf Of Dan Murphy
>>> Sent: Monday, January 23, 2012 10:31 PM
>>> To: peter dalgaard
>>> Cc: [hidden email]
>>> Subject: Re: [Rd] factor S4 class is NA when as.character method exists
>>>
>>> Thank you for your reply, Peter. But that didn't work either. Continuing
>>> the example:
>>>
>>> setGeneric("unique")
>>> setMethod("unique", "foo",  function(x,  incomparables = FALSE, ...){
>>>     y<- callNextMethod(x = getDataPart(x),  incomparables =
>>> incomparables,
>>> ...)
>>>     new("foo", y)
>>>     })
>>>
>>>  unique(bar)
>>>>
>>> An object of class "foo"
>>> [1] 12
>>>
>>>> factor(bar)
>>>>
>>> [1]<NA>
>>> Levels: 12
>>>
>>> Indeed I had tried stepping through the 'factor' call, but perhaps in an
>>> unsophisticated manner -- I had copied the body of 'factor' to a local
>>> version of the function:
>>>
>>> myfactor<- function (x = character(), levels, labels = levels, exclude =
>>> NA,
>>>     ordered = is.ordered(x))
>>> {
>>>     if (is.null(x)) ...
>>> etc.
>>>
>>> And 'myfactor' worked as desired:
>>>
>>>  myfactor(bar)
>>>>
>>> [1] x= 12
>>> Levels: x= 12
>>>
>>> I hypothesized that there might be a deeper interaction of an S4
>>> 'as.character' method with base::factor, but, having exhausted my woeful
>>> lack of expertise, I decided to write my original email.
>>>
>>> Thanks for your consideration.
>>>
>>> Dan
>>>
>>> On Mon, Jan 23, 2012 at 8:25 AM, peter dalgaard<[hidden email]>
>>>  wrote:
>>>
>>>
>>>> On Jan 23, 2012, at 16:07 , Dan Murphy wrote:
>>>>
>>>>  Hello,
>>>>>
>>>>> 'factor' returns<NA>  for my S4 object when the class is given an
>>>>> "as.character" method. Here is a minimal example:
>>>>>
>>>>>  setClass("foo", contains="numeric")
>>>>>> bar<- new("foo", 12)
>>>>>> factor(bar)
>>>>>>
>>>>> [1] 12
>>>>> Levels: 12
>>>>>
>>>>>> setMethod("as.character", "foo", function(x) paste("x=", x@.Data))
>>>>>>
>>>>> [1] "as.character"
>>>>>
>>>>>> as.character(bar)
>>>>>>
>>>>> [1] "x= 12"
>>>>>
>>>>>> factor(bar)
>>>>>>
>>>>> [1]<NA>
>>>>> Levels: 12
>>>>>
>>>>> I would like to 'aggregate' by my S4 objects, but 'factor' seems to be
>>>>> getting in the way. Is there an 'as.character' implementation that
>>>>> works
>>>>> better for S4 classes? I searched help.search("factor S4 class") and
>>>>> help.search("factor S4 as.character") without success.
>>>>>
>>>>
>>>> Single-stepping the factor call would have shown you that the real
>>>> problem
>>>> is that you don't have a unique() method for your class:
>>>>
>>>>  unique(bar)
>>>>>
>>>> [1] 12
>>>>
>>>> i.e., you are getting the default numeric method, which returns a
>>>> numeric
>>>> vector, so the levels become as.character(unique(bar)) which is c("12")
>>>> and
>>>> doesn't match any of the values of as.character(bar).
>>>>
>>>> So, either provide a unique() method, or use factor(as.character(bar)).
>>>>
>>>>
>>>>> Thank you.
>>>>>
>>>>> Dan Murphy
>>>>>
>>>>>       [[alternative HTML version deleted]]
>>>>>
>>>>> ______________________________**________________
>>>>> [hidden email] mailing list
>>>>> https://stat.ethz.ch/mailman/**listinfo/r-devel<https://stat.ethz.ch/mailman/listinfo/r-devel>
>>>>>
>>>>
>>>> --
>>>> Peter Dalgaard, Professor
>>>> Center for Statistics, Copenhagen Business School
>>>> Solbjerg Plads 3, 2000 Frederiksberg, Denmark
>>>> Phone: (+45)38153501
>>>> Email: [hidden email]  Priv: [hidden email]
>>>>
>>>>
>>>>
>>>        [[alternative HTML version deleted]]
>>>
>>> ______________________________**________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/**listinfo/r-devel<https://stat.ethz.ch/mailman/listinfo/r-devel>
>>>
>>
>> ______________________________**________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/**listinfo/r-devel<https://stat.ethz.ch/mailman/listinfo/r-devel>
>>
>
>
> --
> Brian D. Ripley,                  [hidden email]
> Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~**ripley/<http://www.stats.ox.ac.uk/~ripley/>
> University of Oxford,             Tel:  +44 1865 272861 (self)
> 1 South Parks Road,                     +44 1865 272866 (PA)
> Oxford OX1 3TG, UK                Fax:  +44 1865 272595
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Loading...