Re: [Rd] ftable <-> data.frame etc {was "justify hard coded in format.ftable"}

2020-05-23 Thread Gabor Grothendieck


That's not the problem.  The problem is that if you have

   ft <- ftable(UCBAdmissions, row.vars = 3:2)
   ft
   ## Admit Admitted Rejected
   ## Dept Gender
   ## AMale  512  313
   ##  Female 89   19
   ## BMale  353  207
   ##  Female 178
   ## CMale  120  205
  ## ... etc ...

then as.data.frame(ft) gives a deconstructed 24x4 data.frame
like this:

  as.data.frame(ft)
  ##Dept GenderAdmit Freq
  ## 1 A   Male Admitted  512
  ## 2 B   Male Admitted  353
  ## 3 C   Male Admitted  120
  ## 4 D   Male Admitted  138
  ## ... etc ...

which is fine but it does not address the problem here.  The
problem here is that we want a a usable data.frame
having columns that correspond to ft.  We want this 12x4
data.frame:

  ##Dept Gender Admitted Rejected
  ## 1 A   Male  512  313
  ## 2 A Female   89   19
  ## 3 B   Male  353  207
  ## 4 B Female   178
  ## ... etc ...

The links I provided already pointed to the code below which
someone posted on SO and solves the problem but I would
have thought this would be easy to do in base R and natural
to provide.

  ftable2df <- function(mydata) {
ifelse(class(mydata) == "ftable",
mydata <- mydata, mydata <- ftable(mydata))
dfrows <- rev(expand.grid(rev(attr(mydata, "row.vars"
dfcols <- as.data.frame.matrix(mydata)
names(dfcols) <- do.call(
  paste, c(rev(expand.grid(rev(attr(mydata, "col.vars", sep = "_"))
cbind(dfrows, dfcols)
  }
  ftable2df(ft)
  ##Dept Gender Admitted Rejected
  ## 1 A   Male  512  313
  ## 2 A Female   89   19
  ## 3 B   Male  353  207
  ## 4 B Female   178
  ## ... etc ...

 Fri, May 15, 2020 at 12:25 PM Martin Maechler
 wrote:
>
> > Gabor Grothendieck
> > on Thu, 14 May 2020 06:56:06 -0400 writes:
>
> > If you are looking at ftable could you also consider adding
> > a way to convert an ftable into a usable data.frame such as
> > the ftable2df function defined here:
>
> > https://stackoverflow.com/questions/11141406/reshaping-an-array-to-data-frame/11143126#11143126
>
> > and there is an example of using it here:
>
> > https://stackoverflow.com/questions/61333663/manipulating-an-array-into-a-data-frame-in-base-r/61334756#61334756
>
> > Being able to move back and forth between various base class representations
> > seems like something that would be natural to provide.
>
> Sure!
>
> But there is already an  as.data.frame() method for "ftable",
> {and I would not want theif(! .. ftable)  ftable(x)  part anyway.
>
> What I think many useRs / programmeRs  very often forget about
> is more-than-2-dimensional arrays {which *are* at the beginning
> of that SO question} and that these are often by far the most
> efficient data structure (rather than the corresponding data frames).
>
> and even less people forget that a "table" in base R is just a
> special case of a 1-D, 2-D, 3-D,  array.
> (Semantically a special case: "array" with non-negative integer content
>
> I'd claim that everything you here ("move back and forth between
> ...") is already there in the "ftable" implementation in stats,
> notably in the source file  src/library/stats/R/ftable.R
>  -> https://svn.r-project.org/R/trunk/src/library/stats/R/ftable.R
>
> The problem may be in
>
> 1) too sparse documentation about the close relations
>"ftable" <-> "array" <-> "table" <-> "data.frame"
>
> 2) people not thinking often enough about more-than-2D-arrays and the
>   special corresponding class "table" in R.
>
> To start with one:
>
> > str(UCBAdmissions)
>  'table' num [1:2, 1:2, 1:6] 512 313 89 19 353 207 17 8 120 205 ...
>  - attr(*, "dimnames")=List of 3
>   ..$ Admit : chr [1:2] "Admitted" "Rejected"
>   ..$ Gender: chr [1:2] "Male" "Female"
>   ..$ Dept  : chr [1:6] "A" "B" "C" "D" ...
> >
>
> and look at the *examples* in the help files and the S3 methods
>
> methods(class = "ftable")
> [1] as.data.frame as.matrix as.table  formathead  
> print
> [7] tail
> see '?methods' for accessing help and source code
> > methods(class = "table")
>  [1] [ aperm as.data.frame Axis  coerce
> initialize
>  [7] lines plot  pointsprint show  
> slotsFromS3
> [13] summary   tail
> see '?methods' for accessing help and source code
> >
>
> ... need to close now, there's more to be said ...
>
>
>
> > On Thu, May 14, 2020 at 5:32 AM Martin Maechler
> >  wrote:
> >>
> >> > SOEIRO Thomas
> >> > on Wed, 13 May 2020 20:27:15 + writes:
> >>
> >> > Dear all,
> >> > I haven't received any feedback so far on my proposal to make 
> "justify" argument available in stats:::format.ftable
> >>
> >> > Is this list the appropriate place for this kind of 

[Rd] ftable <-> data.frame etc {was "justify hard coded in format.ftable"}

2020-05-15 Thread Martin Maechler
> Gabor Grothendieck 
> on Thu, 14 May 2020 06:56:06 -0400 writes:

> If you are looking at ftable could you also consider adding
> a way to convert an ftable into a usable data.frame such as
> the ftable2df function defined here:

> https://stackoverflow.com/questions/11141406/reshaping-an-array-to-data-frame/11143126#11143126

> and there is an example of using it here:

> https://stackoverflow.com/questions/61333663/manipulating-an-array-into-a-data-frame-in-base-r/61334756#61334756

> Being able to move back and forth between various base class representations
> seems like something that would be natural to provide.

Sure!

But there is already an  as.data.frame() method for "ftable",
{and I would not want theif(! .. ftable)  ftable(x)  part anyway.

What I think many useRs / programmeRs  very often forget about
is more-than-2-dimensional arrays {which *are* at the beginning
of that SO question} and that these are often by far the most
efficient data structure (rather than the corresponding data frames).  

and even less people forget that a "table" in base R is just a
special case of a 1-D, 2-D, 3-D,  array.
(Semantically a special case: "array" with non-negative integer content 

I'd claim that everything you here ("move back and forth between
...") is already there in the "ftable" implementation in stats,
notably in the source file  src/library/stats/R/ftable.R
 -> https://svn.r-project.org/R/trunk/src/library/stats/R/ftable.R

The problem may be in

1) too sparse documentation about the close relations
   "ftable" <-> "array" <-> "table" <-> "data.frame" 

2) people not thinking often enough about more-than-2D-arrays and the
  special corresponding class "table" in R.

To start with one:

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

and look at the *examples* in the help files and the S3 methods

methods(class = "ftable")
[1] as.data.frame as.matrix as.table  formathead  print 
   
[7] tail 
see '?methods' for accessing help and source code
> methods(class = "table")
 [1] [ aperm as.data.frame Axis  coerce
initialize   
 [7] lines plot  pointsprint show  
slotsFromS3  
[13] summary   tail 
see '?methods' for accessing help and source code
> 

... need to close now, there's more to be said ...



> On Thu, May 14, 2020 at 5:32 AM Martin Maechler
>  wrote:
>> 
>> > SOEIRO Thomas
>> > on Wed, 13 May 2020 20:27:15 + writes:
>> 
>> > Dear all,
>> > I haven't received any feedback so far on my proposal to make 
"justify" argument available in stats:::format.ftable
>> 
>> > Is this list the appropriate place for this kind of proposal?
>> 
>> Yes, it is.. Actually such a post is even a "role model" post
>> for R-devel.
>> 
>> > I hope this follow-up to my message won't be taken as rude. Of course 
it's not meant to be, but I'm not used to the R mailing lists...
>> 
>> well, there could be said much, and many stories told here ... ;-)
>> 
>> > Thank you in advance for your comments,
>> 
>> > Best,
>> > Thomas
>> 
>> The main reasons for "no reaction" (for such nice post) probably
>> are combination of the following
>> 
>> - we are busy
>> - if we have time, we think other things are more exciting
>> - we have not used ftable much/at all and are not interested.
>> 
>> Even though the first 2 apply to me, I'll have a 2nd look into
>> your post now, and may end up well agreeing with your proposal.
>> 
>> Martin Maechler
>> ETH Zurich  and  R Core team
>> 
>> 
>> 
>> 
>> >> Dear all,
>> >>
>> >> justify argument is hard coded in format.ftable:
>> >>
>> >> cbind(apply(LABS, 2L, format, justify = "left"),
>> >> apply(DATA, 2L, format, justify = "right"))
>> >>
>> >> It would be useful to have the possibility to modify the argument 
between c("left", "right", "centre", "none") as in format.default.
>> >>
>> >> The lines could be changed to:
>> >>
>> >> if(length(justify) != 2)
>> >> stop("justify must be length 2")
>> >> cbind(apply(LABS, 2L, format, justify = justify[1]),
>> >> apply(DATA, 2L, format, justify = justify[2]))
>> >>
>> >> The argument justify could defaults to c("left", "right") for 
backward compatibility.
>> >>
>> >> It could then allow:
>> >> ftab <- ftable(wool + tension ~ breaks, warpbreaks)
>> >> format.ftable(ftab, justify = c("none", "none"))
>> >>
>> >> Best regards,
>> >>
>> >> Thomas


> -- 
> Statistics & Software Consulting
> GKX Group, GKX Associates Inc.