Re: [Rd] aperm() should retain class of input object

2010-12-29 Thread Michael Friendly

On 12/28/2010 9:43 AM, Tim Hesterberg wrote:

Having aperm() return an object of the same class is dangerous, there
are undoubtedly classes for which that is not appropriate, producing an
illegal object for that class or quietly giving incorrect results.
OK.  I can see that my initial proposal would be dangerous for xtabs 
objects without further
modifications and that it is unwise to change default behavior in base 
functions without

very strong reasons.

Three alternatives are to:
* add the keep.class option but with default FALSE

This first option is the minimally invasive corrective surgery.
This would put the burden on the user (or package writer), but at least 
make it known

that keep.class=TRUE is an option.  This version is

## add keep.class, non-generic
aperm - function (a, perm, resize = TRUE, keep.class=FALSE)
{
if (missing(perm))
perm - integer(0L)
result - .Internal(aperm(a, perm, resize))
if(keep.class) class(result) - class(a)
result
}


* make aperm a generic function
   - without a keep.class argument
   - with a ... argument
   - methods for classes like table could have keep.class = TRUE
This would be much better, as long as an aperm.table method was added to 
base, to complement table() itself,

and gives the desired behavior for table objects by default.
This version seems to be:

## make generic, with ...
aperm - function(a, ...)
UseMethod(aperm, ...)

aperm.default - function (a, perm, resize = TRUE, ...)
{
if (missing(perm))
perm - integer(0L)
.Internal(aperm(a, perm, resize))
}

aperm.table - function(a, perm, resize=TRUE, keep.class=TRUE, ...)
{
result - aperm.default(a, perm, resize=resize)
if(keep.class) class(result) - class(a)
result
}

But it throws an error, maybe because I haven't redefined aperm as a 
generic:


 UCB - aperm(UCBAdmissions, c(2,1,3))
Error in aperm(UCBAdmissions, c(2, 1, 3)) :
  '...' used in an incorrect context

The .table method does work as desired:

 UCB - aperm.table(UCBAdmissions, c(2,1,3))
 str(UCB)
 table [1:2, 1:2, 1:6] 512 89 313 19 353 17 207 8 120 202 ...
 - attr(*, dimnames)=List of 3
  ..$ Gender: chr [1:2] Male Female
  ..$ Admit : chr [1:2] Admitted Rejected
  ..$ Dept  : chr [1:6] A B C D ...



* make aperm a generic function
   - without a keep.class argument
   - with a ... argument
   - default method have keep.class = TRUE

The third option would give the proposed behavior by default, but
allow a way out for classes where the behavior is wrong.  This puts
the burden on a class author to realize the potential problem with
aperm, so my preference is one of the first two options.


aperm() was designed for multidimensional arrays, but is also useful for
table objects, particularly
with the lattice, vcd and vcdExtra packages.  But aperm() was designed
and implemented before other
related object classes were conceived, and I propose a small tune-up to
make it more generally useful.

The problem is that  aperm() always returns an object of class 'array',
which causes problems for methods
designed for table objects. It also requires some package writers to
implement both .array and .table
methods for the same functionality, usually one in terms of the other.
Some examples of unexpected, and initially perplexing results (when only
methods for one class are implemented)
are shown below.



library(vcd)
pairs(UCBAdmissions, shade=TRUE)
UCB- aperm(UCBAdmissions, c(2, 1, 3))

# UCB is now an array, not a table
pairs(UCB, shade=TRUE)

There were 50 or more warnings (use warnings() to see the first 50)

# fix it, to get pairs.table
class(UCB)- table
pairs(UCB, shade=TRUE)




Of course, I can define a new function, tperm() that does what I think
should be the expected behavior:

# aperm, for table objects

tperm- function(a, perm, resize = TRUE) {
 result- aperm(a, per, resize)
 class(result)- class(a)
 result
}

But I think it is more natural to include this functionality in aperm()
itself.  Thus, I propose the following
revision of base::aperm(), at the R level:

aperm- function (a, perm, resize = TRUE, keep.class=TRUE)
{
 if (missing(perm))
 perm- integer(0L)
 result- .Internal(aperm(a, perm, resize))
 if(keep.class) class(result)- class(a)
 result
}


I don't think this would break any existing code, except where someone
depended on coercion to an array.
The drop-in replacement for aperm would set keep.class=FALSE by default,
but I think TRUE is  more
natural.

FWIW, here are the methods for table and array objects

from my current (non-representative) session.

methods(class=table)

  [1] as.data.frame.table barchart.table* cloud.table*
contourplot.table*  dotplot.table*
  [6] head.table* levelplot.table*pairs.table*
plot.table* print.table
[11] summary.table   tail.table*

Non-visible functions are asterisked

methods(class=array)

[1] anyDuplicated.array as.data.frame.array as.raster.array*
barchart.array* 

Re: [Rd] aperm() should retain class of input object

2010-12-29 Thread Martin Maechler
 Michael Friendly frien...@yorku.ca
 on Wed, 29 Dec 2010 08:33:07 -0500 writes:

 On 12/28/2010 9:43 AM, Tim Hesterberg wrote:
 Having aperm() return an object of the same class is dangerous, there
 are undoubtedly classes for which that is not appropriate, producing an
 illegal object for that class or quietly giving incorrect results.
 OK.  I can see that my initial proposal would be dangerous for xtabs 
 objects without further
 modifications and that it is unwise to change default behavior in base 
 functions without
 very strong reasons.

 Three alternatives are to:
 * add the keep.class option but with default FALSE
 This first option is the minimally invasive corrective surgery.
 This would put the burden on the user (or package writer), but at least 
 make it known
 that keep.class=TRUE is an option.  This version is

 ## add keep.class, non-generic
 aperm - function (a, perm, resize = TRUE, keep.class=FALSE)
 {
 if (missing(perm))
 perm - integer(0L)
 result - .Internal(aperm(a, perm, resize))
 if(keep.class) class(result) - class(a)
 result
 }

 * make aperm a generic function
 - without a keep.class argument
 - with a ... argument
 - methods for classes like table could have keep.class = TRUE
 This would be much better, as long as an aperm.table method was added to 
 base, to complement table() itself,
 and gives the desired behavior for table objects by default.
 This version seems to be:

 ## make generic, with ...
 aperm - function(a, ...)
 UseMethod(aperm, ...)

use  UseMethod(aperm)

instead and then all is fine


 aperm.default - function (a, perm, resize = TRUE, ...)
 {
 if (missing(perm))
 perm - integer(0L)
 .Internal(aperm(a, perm, resize))
 }

 aperm.table - function(a, perm, resize=TRUE, keep.class=TRUE, ...)
 {
 result - aperm.default(a, perm, resize=resize)
 if(keep.class) class(result) - class(a)
 result
 }

 But it throws an error, maybe because I haven't redefined aperm as a 
 generic:

 UCB - aperm(UCBAdmissions, c(2,1,3))
 Error in aperm(UCBAdmissions, c(2, 1, 3)) :
 '...' used in an incorrect context

.. well,  because you've used extraneous ... in the S3 generic
definition (see above).

I'm really sympathetic with your proposal and would indeed
implement it (for R-devel aka R 2.13.0 to be)
unless someone has good arguments for something else.
{{well, my version *would* keep the  'perm = NULL' default for
  both default and table methods.}}

Martin Maechler, ETH Zurich



 The .table method does work as desired:

 UCB - aperm.table(UCBAdmissions, c(2,1,3))
 str(UCB)
 table [1:2, 1:2, 1:6] 512 89 313 19 353 17 207 8 120 202 ...
 - attr(*, dimnames)=List of 3
 ..$ Gender: chr [1:2] Male Female
 ..$ Admit : chr [1:2] Admitted Rejected
 ..$ Dept  : chr [1:6] A B C D ...
 

 * make aperm a generic function
 - without a keep.class argument
 - with a ... argument
 - default method have keep.class = TRUE
 
 The third option would give the proposed behavior by default, but
 allow a way out for classes where the behavior is wrong.  This puts
 the burden on a class author to realize the potential problem with
 aperm, so my preference is one of the first two options.
 
 aperm() was designed for multidimensional arrays, but is also useful for
 table objects, particularly
 with the lattice, vcd and vcdExtra packages.  But aperm() was designed
 and implemented before other
 related object classes were conceived, and I propose a small tune-up to
 make it more generally useful.
 
 The problem is that  aperm() always returns an object of class 'array',
 which causes problems for methods
 designed for table objects. It also requires some package writers to
 implement both .array and .table
 methods for the same functionality, usually one in terms of the other.
 Some examples of unexpected, and initially perplexing results (when only
 methods for one class are implemented)
 are shown below.
 
 
 library(vcd)
 pairs(UCBAdmissions, shade=TRUE)
 UCB- aperm(UCBAdmissions, c(2, 1, 3))
 
 # UCB is now an array, not a table
 pairs(UCB, shade=TRUE)
 There were 50 or more warnings (use warnings() to see the first 50)
 # fix it, to get pairs.table
 class(UCB)- table
 pairs(UCB, shade=TRUE)
 
 
 
 Of course, I can define a new function, tperm() that does what I think
 should be the expected behavior:
 
 # aperm, for table objects
 
 tperm- function(a, perm, resize = TRUE) {
 result- aperm(a, per, resize)
 class(result)- class(a)
 result
 }
 
 But I think it is more natural to include this functionality in aperm()
 itself.  Thus, I propose the 

Re: [Rd] aperm() should retain class of input object

2010-12-28 Thread Tim Hesterberg
Having aperm() return an object of the same class is dangerous, there
are undoubtedly classes for which that is not appropriate, producing an
illegal object for that class or quietly giving incorrect results.

Three alternatives are to:
* add the keep.class option but with default FALSE
* make aperm a generic function 
  - without a keep.class argument
  - with a ... argument
  - methods for classes like table could have keep.class = TRUE
* make aperm a generic function 
  - without a keep.class argument
  - with a ... argument
  - default method have keep.class = TRUE

The third option would give the proposed behavior by default, but
allow a way out for classes where the behavior is wrong.  This puts
the burden on a class author to realize the potential problem with
aperm, so my preference is one of the first two options.

aperm() was designed for multidimensional arrays, but is also useful for
table objects, particularly
with the lattice, vcd and vcdExtra packages.  But aperm() was designed
and implemented before other
related object classes were conceived, and I propose a small tune-up to
make it more generally useful.

The problem is that  aperm() always returns an object of class 'array',
which causes problems for methods
designed for table objects. It also requires some package writers to
implement both .array and .table
methods for the same functionality, usually one in terms of the other.
Some examples of unexpected, and initially perplexing results (when only
methods for one class are implemented)
are shown below.


  library(vcd)
  pairs(UCBAdmissions, shade=TRUE)
  UCB - aperm(UCBAdmissions, c(2, 1, 3))
 
  # UCB is now an array, not a table
  pairs(UCB, shade=TRUE)
There were 50 or more warnings (use warnings() to see the first 50)
 
  # fix it, to get pairs.table
  class(UCB) - table
  pairs(UCB, shade=TRUE)
 



Of course, I can define a new function, tperm() that does what I think
should be the expected behavior:

# aperm, for table objects

tperm - function(a, perm, resize = TRUE) {
 result - aperm(a, per, resize)
 class(result) - class(a)
 result
}

But I think it is more natural to include this functionality in aperm()
itself.  Thus, I propose the following
revision of base::aperm(), at the R level:

aperm - function (a, perm, resize = TRUE, keep.class=TRUE)
{
 if (missing(perm))
 perm - integer(0L)
 result - .Internal(aperm(a, perm, resize))
 if(keep.class) class(result) - class(a)
 result
}


I don't think this would break any existing code, except where someone
depended on coercion to an array.
The drop-in replacement for aperm would set keep.class=FALSE by default,
but I think TRUE is  more
natural.

FWIW, here are the methods for table and array objects
from my current (non-representative) session.

  methods(class=table)
  [1] as.data.frame.table barchart.table* cloud.table*
contourplot.table*  dotplot.table*
  [6] head.table* levelplot.table*pairs.table*
plot.table* print.table
[11] summary.table   tail.table*

Non-visible functions are asterisked
 
  methods(class=array)
[1] anyDuplicated.array as.data.frame.array as.raster.array*
barchart.array* contourplot.array*  dotplot.array*
[7] duplicated.arraylevelplot.array*unique.array


--
Michael Friendly Email: friendly AT yorku DOT ca
Professor, Psychology Dept.
York University  Voice: 416 736-5115 x66249 Fax: 416 736-5814
4700 Keele StreetWeb:http://www.datavis.ca
Toronto, ONT  M3J 1P3 CANADA

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


[Rd] aperm() should retain class of input object

2010-12-27 Thread Michael Friendly
aperm() was designed for multidimensional arrays, but is also useful for 
table objects, particularly
with the lattice, vcd and vcdExtra packages.  But aperm() was designed 
and implemented before other
related object classes were conceived, and I propose a small tune-up to 
make it more generally useful.


The problem is that  aperm() always returns an object of class 'array', 
which causes problems for methods
designed for table objects. It also requires some package writers to 
implement both .array and .table

methods for the same functionality, usually one in terms of the other.
Some examples of unexpected, and initially perplexing results (when only 
methods for one class are implemented)

are shown below.


 library(vcd)
 pairs(UCBAdmissions, shade=TRUE)
 UCB - aperm(UCBAdmissions, c(2, 1, 3))

 # UCB is now an array, not a table
 pairs(UCB, shade=TRUE)
There were 50 or more warnings (use warnings() to see the first 50)

 # fix it, to get pairs.table
 class(UCB) - table
 pairs(UCB, shade=TRUE)




Of course, I can define a new function, tperm() that does what I think 
should be the expected behavior:


# aperm, for table objects

tperm - function(a, perm, resize = TRUE) {
result - aperm(a, per, resize)
class(result) - class(a)
result
}

But I think it is more natural to include this functionality in aperm() 
itself.  Thus, I propose the following

revision of base::aperm(), at the R level:

aperm - function (a, perm, resize = TRUE, keep.class=TRUE)
{
if (missing(perm))
perm - integer(0L)
result - .Internal(aperm(a, perm, resize))
if(keep.class) class(result) - class(a)
result
}


I don't think this would break any existing code, except where someone 
depended on coercion to an array.
The drop-in replacement for aperm would set keep.class=FALSE by default, 
but I think TRUE is  more

natural.

FWIW, here are the methods for table and array objects
from my current (non-representative) session.

 methods(class=table)
 [1] as.data.frame.table barchart.table* cloud.table*
contourplot.table*  dotplot.table*
 [6] head.table* levelplot.table*pairs.table*
plot.table* print.table

[11] summary.table   tail.table*

   Non-visible functions are asterisked

 methods(class=array)
[1] anyDuplicated.array as.data.frame.array as.raster.array*
barchart.array* contourplot.array*  dotplot.array*

[7] duplicated.arraylevelplot.array*unique.array


--
Michael Friendly Email: friendly AT yorku DOT ca
Professor, Psychology Dept.
York University  Voice: 416 736-5115 x66249 Fax: 416 736-5814
4700 Keele StreetWeb:http://www.datavis.ca
Toronto, ONT  M3J 1P3 CANADA

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel