\chapter{Factors and Tables}
\label{chap:factab}

Factors form the basis for many of R's powerful operations, including
many of those performed on tabular data. The motivation for factors comes from the notion of {\it nominal}, or {\it categorical}, variables in statistics. These values are nonnumerical in nature, corresponding to categories such as Democrat, Republican, and Unaffiliated, although they may be coded using numbers.

In this chapter, we'll begin by looking at the extra information contained in factors, and then focus on the functions used with factors. We'll also explore tables and common table operations.

%
% The intro needed some "in this chapter ..." text and a head before the following details. I've suggested both. /MS
%

\section{Factors and Levels}

% NM:  Changed, next few paragraphs.

An R \emph{factor} might be viewed simply a vector with a bit more
information added (though as seen below, it's a bit different from this
internally).  That extra information consists of a record of the
distinct values in that vector, called {\it levels}. Here's an example:

\begin{Code}
> x <- c(5,12,13,12)
> xf <- factor(x)
> xf
[1] 5  12 13 12
Levels: 5 12 13
\end{Code}

\noindent 
The distinct values in {\tt xf}---5, 12, and 13---are the levels here.

Let's take a look inside:

\begin{Code}
> str(xf)
 Factor w/ 3 levels "5","12","13": 1 2 3 2
> unclass(xf)
[1] 1 2 3 2
attr(,"levels")
[1] "5"  "12" "13"
\end{Code}

This is revealing.  The core of {\tt xf} here is not (5,12,13,12), but
rather (1,2,3,2).  The latter means that our data consists first of a
level-1 value, then level-2 and level-3 values, and finally another
level-2 value.  So the data has been recoded by level.  The levels
themselves are recorded too, of course, though as characters such as "5"
rather than 5.

The length of a factor is still defined in terms of the length of the
data, rather than, say, being a count of the number of levels:

\begin{Code}
> length(xf)
[1] 4
\end{Code}

We can anticipate future new levels, as seen here:

\begin{Code}
> x <- c(5,12,13,12)
> xff <- factor(x,levels=c(5,12,13,88))
> xff
[1] 5  12 13 12
Levels: 5 12 13 88
> xff[2] <- 88
> xff
[1] 5  88 13 12
Levels: 5 12 13 88
\end{Code}

Originally, {\tt xff} did not contain the value 88, but in defining it, we
allowed for that future possibility. Later, we did indeed add the value.

By the same token, you cannot sneak in an ``illegal'' level. Here's what happens when you try:

\begin{Code}
> xff[2] <- 28
Warning message:
In `[<-.factor`(`*tmp*`, 2, value = 28) :
  invalid factor level, NAs generated
\end{Code}

%
% For better chapter structure, I suggest adding a general head here and making the function discussions subsections. Again, this required some intro text. /MS
%

\section{Common Functions Used with Factors}

With factors, we have yet another member of the family of \lstinline{apply} functions, \lstinline{tapply}. We'll look at that function, as well as two other functions commonly used with factors: \lstinline{split()} and \lstinline{by()}.

\subsection{The tapply() Function}
\label{tapply}

% NM:  Next few paragraphs changed, including the first example.

As motivation, suppose we have a vector {\tt x} of ages of voters, and a
factor {\tt f} showing some nonumeric trait of those voters, such as
party affiliation (Democrat, Republican, Unaffiliated).  We might wish
to find the mean ages in {\tt x} within each of the party groups.

In typical usage, the call {\tt tapply(x,f,g)} has {\tt x} as a vector,
{\tt f} as a factor or list of factors, and {\tt g} as a function.  The
function {\tt g()} in our little example above would be R's built-in
{\tt mean()} function.  If we wanted to group by both party and another
factor, say gender, we would need {\tt f} to consist of the two factors,
party and gender.

Each factor in {\tt f} must have the same length as {\tt x}.  If a
component of {\tt f} is a vector, it will be coerced into a factor by
applying {\tt as.factor()} to it.

The operation performed by {\tt tapply()} is to (temporarily) split {\tt
x} into groups, each group corresponding to a level of the factor (or a
combination of levels of the factors in the case of multiple factors),
and then apply {\tt g()} to the resulting subvectors of {\tt x}. Here's an
example:

\begin{Code}
> u <- c(22,8,33,6,8,29,-2)
> tapply(u,c(5,12,13,12,13,5,13),sum)
 5 12 13 
51 14 39 
\end{Code}

% NM:  Changed.

At first glance, this is not intuitive at all, so let's look at what
happened. The function {\tt tapply()} treated {\tt
c(5,12,13,12,13,5,13)} as a factor, with levels 5, 12, and 13. It noted
that 5 occurred in indices 1 and 6; 12 occurred in indices 2 and 4; and
13 occurred in indices 3, 5, and 7. For convenience, let's refer to the
three index vectors (1,6), (2,4), and (3,5,7) as {\tt x}, {\tt y}, and {\tt
z}, respectively.  Then {\tt tapply()} computed {\tt sum(u[x])}, {\tt
sum(u[y])}, and {\tt sum(u[z])}, and returned those sums in a
three-element vector.  And that vector's element names are 5, 12, and
13, reflecting the factor levels that were used by {\tt tapply()}.

What if we have two or more factors? Then each factor yields a set of
groups, as in the preceding example, and the groups are ANDed together. That's pretty abstract, so let's look at a two-factor example.

\begin{Code}
> u <- c(22,8,33,6,8,29,-2)
> fl <- list(c(5,12,13,12,13,5,13),c("a","bc","a","a","bc","a","a"))
> tapply(u,fl,sum)
    a bc
5  51 NA
12  6  8
13 31  8
\end{Code}

Where did that 51 come from? As you saw, level 5 in the first
factor corresponds to indices 1 and 6 of that factor. In the second factor, \lstinline{"a"} comes from indices 1, 3, 4, 6, and 7. The indices in common---the result of a Boolean AND operation---are 1 and 6. The
sum of elements 1 and 6 in {\tt u} is 22+29; hence, the 51 in the output
from {\tt tapply()}.

That 51 entry came from the first level of the first factor and the
first level of the second. As you can see from the two-dimensional
nature of the output, all combinations of the two factors are processed.

What about that NA?  Well, that entry in the table
corresponds to those indices in which the first factor is at level 5
(1,6,7), {\it and} the second factor is at level \lstinline{"bc"} (2,5).  There are no indices in common, hence the NA.

Note again that each of the factors in {\tt f} must have the same length as
{\tt x}.  In our first example, both {\tt u} and {\tt
c(5,12,13,12,13,5,13)} had length 7.  In the second example,
\lstinline{c("a","bc","a","a","bc","a","a")} also had length 7. 

Why would anyone be interested in this kind of operation?  Typically, in
the following call, {\tt x} and {\tt f} correspond to different variables in the
same data set.

\begin{Code}
tapply(x,f,g)
\end{Code}

As an example, suppose that we have an economic data set that includes data on the gender, age, and income. Here, the preceding call might
have {\tt x} as income and {\tt f} as a pair of factors: one for
gender and the other for coding whether the person is older or younger than
25. We may be interested in finding mean income, broken down by gender
and age. If we set {\tt g()} to be {\tt mean()}, {\tt tapply()}
will return the mean incomes in each of four subgroups:

\begin{itemize}

\item Male and under 25 years old

\item Female and under 25 years old

\item Male and over 25 years old

\item Female and over 25 years old

\end{itemize}

Here's a toy example of that setting:

\begin{Code}
> d <- data.frame(list(gender=c("M","M","F","M","F","F"),
+    age=c(47,59,21,32,33,24),income=c(55000,88000,32450,76500,123000,45650)))
> d
  gender age income
1      M  47  55000
2      M  59  88000
3      F  21  32450
4      M  32  76500
5      F  33 123000
6      F  24  45650
> d$over25 <- ifelse(d$age > 25,1,0)
> d
  gender age income over25
1      M  47  55000      1
2      M  59  88000      1
3      F  21  32450      0
4      M  32  76500      1
5      F  33 123000      1
6      F  24  45650      0
> tapply(d$income,list(d$gender,d$over25),mean)
      0         1
F 39050 123000.00
M    NA  73166.67
\end{Code}

\subsection{The split() Function}
\label{split}

In contrast to {\tt tapply()}, which splits a vector into groups and
then applies a specified function on each group, {\tt split()} stops at
that first stage, just forming the groups.

The basic form, without bells and whistles, is {\tt split(x,f)}, where
{\tt x} is a vector or data frame and {\tt f} is a factor. (Note that
{\tt split()} will call {\tt as.factor()} on {\tt f} if needed.) The
action is to split {\tt x} into groups, which are returned in a list.  Another
way of looking at it is that {\tt tapply()} is more or less the same as
using {\tt split()} and {\tt sapply()}, with the latter having {\tt f()},
as an argument.

Let's try it out with our earlier example.

\begin{Code}
> u <- c(22,8,33,6,8,29,-2)
> fl <- list(c(5,12,13,12,13,5,13),c("a","bc","a","a","bc","a","a"))
> z <- split(u,fl)
> z
$`5.a`
[1] 22 29

$`12.a`
[1] 6

$`13.a`
[1] 33 -2

$`5.bc`
numeric(0)

$`12.bc`
[1] 8

$`13.bc`
[1] 8
\end{Code}

Recall that the components of a list---in this case, {\tt z}---are denoted
by dollar signs. So the last vector, for example, was named \lstinline{"13.bc" } to indicate that it was the result of combining 13 in the first 
factor and \lstinline{"bc"} in the second. Here is an example of referencing it
using a dollar sign:

\begin{Code}
> z$"13.bc"
[1] 8
\end{Code}

And why did that component of {\tt z} turn out to be the vector (8)?
The value 13 occurs at indices 3, 5, and 7 of the first factor, while
\lstinline{"bc"} occurs at indices 2 and 5 of the second factor.  The only common index is 5, so \lstinline{$`13.bc`} consisted of just {\tt u[5]}---that is, 8.

As another illustration, consider our abalone example from
Section \ref{abalone}. We wanted to determine the indices of the vector
elements corresponding to male, female, and infant. The data in that example was {\tt c("M","F","F","I","M","M","F")}, assigned to {\tt g}. We can do this in a
flash with {\tt split()}.

\begin{Code}
> split(1:7,g)
$F
[1] 2 3 7

$I
[1] 4

$M
[1] 1 5 6
\end{Code}

The results show the female cases are in records 2, 3, and 7; the infant case is in record 4; and the male cases are in records 1, 5, and 6.

%
% Edit of sentence above correct? /MS
%

Let's dissect this, step by step. The vector {\tt g}, taken as a
factor, has three levels: \lstinline{"M"}, \lstinline{"F"}, and \lstinline{"I"}. The indices corresponding to the first level are 1, 5, and 6, which means that{\tt g[1]}, {\tt g[5]}, and {\tt g[6]} all have the value \lstinline{"M"}.  So, R sets the {\tt M} component of the output to elements 1, 5, and 6 of {\tt 1:7}, which is the vector (1,5,6).

We can take a similar approach to simplify the code in our text concordance example from Section \ref{concord}. There, we wished to input a text file,
determine which words were in the text, and then output a list giving the
words and their locations within the text. We can use {\tt split()} to
make short work of writing the code, as follows:

\begin{lstlisting}[numbers=left]
findwords <- function(tf) {
   # read in the words from the file, into a vector of mode character
   txt <- scan(tf,"") 
   words <- split(1:length(txt),txt)
   return(words)
}
\end{lstlisting}

%
% Since you don't refer to the line numbers in this listing, are they necessary (i.e., remove the line numbers from this example?)? /MS
%
\subsection{The by() Function}

Suppose in the abalone example we wish to do regression analyses of
diameter against length separately for each gender code: males, females,
and infants. At first, this seems like something tailor-made for {\tt
tapply()}, but the first argument of that function must be a vector, not
a matrix or a data frame.  The function to be applied can be 
multivariate---for example, {\tt range()}---but the input must be a 
vector.  Yet the input for regression is a matrix (or data frame) 
with at least two columns: one for the predicted variable and one or more for predictor variables. In our abalone data application, 
the matrix would consist of a column for the diameter data and a column 
for length.  

The {\tt by()} function can be used here. It works like {\tt tapply()}
(which it calls internally, in fact), but is applied to objects rather
than vectors.  Here's how to use it for the desired regression analyses:

\begin{Code}
> aba <- read.csv("abalone.data",header=TRUE)
> by(aba,aba$Gender,function(m) lm(m[,2]~m[,3]))
aba$Gender: F

Call:
lm(formula = m[, 2] ~ m[, 3])

Coefficients:
(Intercept)       m[, 3]  
    0.04288      1.17918  

------------------------------------------------------------ 
aba$Gender: I

Call:
lm(formula = m[, 2] ~ m[, 3])

Coefficients:
(Intercept)       m[, 3]  
    0.02997      1.21833  

------------------------------------------------------------ 
aba$Gender: M

Call:
lm(formula = m[, 2] ~ m[, 3])

Coefficients:
(Intercept)       m[, 3]  
    0.03653      1.19480  
\end{Code}

Just as {\tt tapply()} forms groups of indices of a vector according to
levels of a factor, this {\tt by()} call finds groups of row numbers
of the data frame {\tt aba}.  That creates three subdata frames: one
for each gender level of M, F, and I.  

The anonymous function we defined regresses the second column of its
matrix argument {\tt m} against the third column.  This function will be
called three times---once for each of the three subdata frames created
earlier---thus producing the three regression analyses.

%
% Following head edit (to be more descriptive) OK? /MS
%
\section{Working with Tables}
\label{tables}

To begin exploring R tables, let's change our earlier example as follows:

\begin{Code}
> u <- c(22,8,33,6,8,29,-2)
> fl <- list(c(5,12,13,12,13,5,13),c("a","bc","a","a","bc","a","a"))
> tapply(u,fl,length)
   a bc
5  2 NA
12 1  1
13 2  1
\end{Code}

Here, {\tt tapply()} again temporarily breaks {\tt u} into subvectors as
you saw earlier, but in this case, it then applies the {\tt length()}
function to each subvector, instead of applying {\tt sum()} as before.
(Note that this is now independent of what's in {\tt u}.  Our focus now
is purely on the factors.) Those subvector lengths are the counts of the
occurrences of each of the $3 \times 2 = 6$ combinations of the two
factors.  For instance, 5 occurred twice with \lstinline{"a"} and not at all with \lstinline{"bc"}, hence the entries 2 and NA in the first row of the output.  In statistics, this is called a {\it contingency table}.

There is one problem in this example: the NA value. It really should
be 0, meaning that in no cases did the first factor have level 5 and
the second have level \lstinline{"bc"}. The {\tt table()} function creates contingency tables correctly.

\begin{Code}
> table(fl)
    fl.2
fl.1 a bc
  5  2  1
  12 1  1
  13 1  0
\end{Code}

The first argument in a call to {\tt table()} is either a factor or a
list of factors. In this case, an object that is interpretable as a
factor is counted as one.

For example, consider using a data frame as the \lstinline{table()} argument. Suppose the file \emph {ct.dat} consists of election-polling data, in which candidate X is running for reelection. The \emph {ct.dat} file looks like this:

\begin{Code}
"Vote for X" "Voted For X Last Time"
"Yes" "Yes"
"Yes" "No"
"No" "No"
"Not Sure" "Yes"
"No" "No"
\end{Code}

In the usual statistical fashion, each row in this file 
represents one subject under study. In this case, we have asked five 
people the following two questions:

\begin{itemize}

\item Do you plan to vote for candidate X?

\item Did you vote for X in the last election?

\end{itemize}

This gives us five rows in the data file.  

Let's read in the file:

\begin{Code}
> ct <- read.table("ct.dat",header=T)
> ct
  Vote.for.X Voted.for.X.Last.Time
1        Yes                   Yes
2        Yes                    No
3         No                    No
4   Not Sure                   Yes
5         No                    No
\end{Code}

We can use the {\tt table()} function to compute the contingency table
for this data:

\begin{Code}
> cttab <- table(ct)
> cttab
          Voted.for.X.Last.Time
Vote.for.X No Yes
  No        2   0
  Not Sure  0   1
  Yes       1   1
\end{Code}

The 2 in the upper-left corner of the table shows that we had, for
example, two people who said ``no'' to the first and second questions.  The 1 in the middle-right indicates that one person answered ``not sure'' to the first question and ``yes'' to the second question.

We can also get one-dimensional counts, which are counts on a single
factor, as follows:

\begin{Code}
> table(c(5,12,13,12,8,5))

 5  8 12 13 
 2  1  2  1 
\end{Code}

Here's an example of a three-dimensional table, involving voters and
their genders, race (white, black, Asian, and other), and political views
(liberal or conservative):

\begin{Code}
> v
  gender race pol
1      M    W   L
2      M    W   L
3      F    A   C
4      M    O   L
5      F    B   L
6      F    B   C
> vt <- table(v)
> vt
, , pol = C

      race
gender A B O W
     F 1 1 0 0
     M 0 0 0 0

, , pol = L

      race
gender A B O W
     F 0 1 0 0
     M 0 0 1 2
\end{Code}

R prints out a three-dimensional table as a series of two-dimensional
tables. In this case, it generates a table of gender and race for conservatives, and then a corresponding table for liberals.

\subsection{Matrix/Array-Like Operations on Tables}

Just as most (nonmathematical) matrix/array operations can also be used on
data frames, they can be applied to tables, too. (This is not
surprising, given that the cell counts portion of a {\tt table} object is
an array.)

For example, we can access the table cell counts using matrix notation.
Let's apply this to our voting example from the previous section.

\begin{Code}
> class(cttab)
[1] "table"
> cttab[1,1]
[1] 2
> cttab[1,]
 No Yes 
  2   0 
\end{Code}

In the second command, even though the first command had shown that {\tt
cttab} had class {\tt ``cttab''}, we treated it as a matrix and printed
out its ``[1,1] element.''  Continuing this idea, the third command
printed the first column of this ``matrix.''

We can multiply the matrix by a scalar. For instance, here's how to change cell counts to proportions:

\begin{Code}
> ctt/5
          Voted.for.X.Last.Time
Vote.for.X  No Yes
  No       0.4 0.0
  Not Sure 0.0 0.2
  Yes      0.2 0.2
\end{Code}

In statistics, the {\it marginal} values of a variable are those
obtained when this variable is held constant while others are summed.
In the voting example, the marginal values of the VoteX variable
are 2+0=2, 0+1=1 and 1+1=2.  We can of course obtain these via the
matrix {\tt apply()} function:

%
% Is "VoteX variable" above correct? Should it be "Vote.for.X" and in inline code style? Should it remain VoteX but be in inline code style? /MS
%

\begin{Code}
> apply(ctt,1,sum)
      No Not Sure      Yes 
       2        1        2 
\end{Code}

Note that the labels here, such as \lstinline{No}, came from the row names of
the matrix, which {\tt table()} produced.

But R supplies a function {\tt addmargins()} for this purpose---that is,
to find marginal totals. Here's an example:

\begin{Code}
> addmargins(cttab)
          Voted.for.X.Last.Time
Vote.for.X No Yes Sum
  No        2   0   2
  Not Sure  0   1   1
  Yes       1   1   2
  Sum       3   2   5
\end{Code}

Here, we got the marginal data for both dimensions at once, conveniently
superimposed onto the original table.

We can get the names of the dimensions and levels through {\tt
dimnames()}, as follows:

\begin{Code}
> dimnames(cttab)
$Vote.for.X
[1] "No"       "Not Sure" "Yes"     

$Voted.for.X.Last.Time
[1] "No"  "Yes"
\end{Code}

\subsection{Extended Example: Extracting a Subtable}
\label{subtable}

Let's continue working with our voting example:

\begin{Code}
> cttab
          Voted.for.X.Last.Time
Vote.for.X No Yes
  No        2   0
  Not Sure  0   1
  Yes       1   1
\end{Code}

Suppose we wish to present this data at a meeting, concentrating on those respondents who know they will vote for X in the current election. In other words, we wish to eliminate the Not Sure entries, to present a subtable that looks like this:

\begin{Code}
          Voted.for.X.Last.Time
Vote.for.X No Yes
  No        2   0
  Yes       1   1
\end{Code}

To accomplish this, we'll use the function {\tt subtable()}, which has two arguments:

\begin{itemize}

\item {\tt tbl}: The table of interest, of class {\tt ``table''}.

\item {\tt subnames}: A list giving the specification of the desired
subtable extraction. Each component of this list has the name
of one dimension of {\tt tbl}, and the value of that component 
is a vector of the names of the desired levels.

\end{itemize}

So, let's review what we have here before looking at the code. {\tt cttab} is a
two-dimensional table, and its dimension names are \lstinline{Voted.for.X} and
\lstinline{Voted.for.X.Last.Time}. Within those two dimensions, the level names
are \lstinline{No}, \lstinline{Not Sure}, and \lstinline{Yes} in the first dimension, and \lstinline{No} and \lstinline{Yes} in the
second. Of those, we wish to exclude the \lstinline{Not Sure} cases, so our actual argument corresponding to the formal argument {\tt subnames} is as follows: 

\begin{Code}
list(Vote.for.X=c("No","Yes"),Voted.for.X.Last.Time=c("No","Yes"))
\end{Code}

We can now call the function.

\begin{Code}
> subtable(cttab,list(Vote.for.X=c("No","Yes"),
+    Voted.for.X.Last.Time=c("No","Yes")))
          Voted.for.X.Last.Time
Vote.for.X No Yes
       No   2   0
       Yes  1   1
\end{Code}

Now that we have a feel for what the function does, let's take a look at
its innards.

\begin{lstlisting}[numbers=left,numberstyle=\footnotesize]
subtable <- function(tbl,subnames) {
   # get array of cell counts in tbl
   tblarray <- unclass(tbl)  (*@ \label{unclasstbl} @*)
   # we'll get the subarray of cell counts corresponding to subnames by
   # calling do.call() on the "[" function; we need to build up a list
   # of arguments first
   dcargs <- list(tblarray)  (*@ \label{yyy1} @*)
   ndims <- length(subnames)  # number of dimensions 
   for (i in 1:ndims) {
      dcargs[[i+1]] <- subnames[[i]]
   }  (*@ \label{yyy11} @*)
   subarray <- do.call("[",dcargs)  (*@ \label{yyy2} @*)
   # now we'll build the new table, consisting of the subarray, the
   # numbers of levels in each dimension, and the dimnames() value, plus
   # the "table" class attribute
   dims <- lapply(subnames,length) (*@ \label{yyya} @*)
   subtbl <- array(subarray,dims,dimnames=subnames)
   class(subtbl) <- "table"
   return(subtbl)
}
\end{lstlisting}

So, what's happening here? To prepare for writing this code, I first did a
little detective work, to determine the structure of objects of class
{\tt ``table''}.  I found that at its core, an object of this class
consists of an array, whose elements are the cell counts. So the
strategy is to extract the desired subarray, then add names to the
dimensions of the subarray, and then bestow {\tt "table"} class status to
the result.

For the code here, then, the first task is to form the subarray
corresponding to the user's desired subtable, and this constitutes most
of the code. To this end, in line \ref{unclasstbl}, we first extract the full cell counts array, storing it in {\tt tblarray}.  The question is how to use
that to find the desired subarray. In principle, this is easy. In practice, that's not always the case.

To get the desired subarray, I needed to form a subsetting expression on
the array {\tt tblarray}---something like this:

\begin{Code}
tblarray[some index ranges here]
\end{Code}

In our voting example, the expression is as follows:

\begin{Code}
tblarray[c("No","Yes"),c("No","Yes")]
\end{Code}

Simple in concept, but difficult to do directly, since {\tt tblarray} could 
be of different dimensions (two, three, or anything else).  Recall 
that R's array subscripting is actually done via a function named 
{\tt "["()}.  This function takes a variable number of arguments:
two for two-dimensional arrays, three for three-dimensional arrays, and so
on.

This problem is solved by using R's {\tt do.call()}. This function has the following basic form:

\begin{Code}
do.call(f,argslist)
\end{Code}

\noindent 
where {\tt f} is a function and {\tt argslist} is a list of arguments
on which to call {\tt f()}. In other words, the preceding code
basically does this:

\begin{Code}
f(argslist[[1],argslist[[2]],...)
\end{Code}

This makes it easy to call a function with a variable number of
arguments.

For our example, we need to form a list consisting first of {\tt tblarray} and then the user's desired levels for each dimension. Our list looks like this: 

\begin{Code}
list(tblarray,Vote.for.X=c("No","Yes"),Voted.for.X.Last.Time=c("No","Yes"))
\end{Code}

Lines \ref{yyy1} through \ref{yyy11} build up this list for the general
case. That's our subarray.  Then we need to attach the names, and set the
class to {\tt ``table''}. The former operation can be done via R's {\tt
array()} function, which has the following arguments:

\begin{itemize}

\item {\tt data}: The data to be placed into the new array. In our case,
this is {\tt subarray}.

\item {\tt dim}: The dimension lengths (number of rows, number of
columns, number of layers, and so on). In our case, this is the value
{\tt ndims}, computed in line \ref{yyya}.

\item {\tt dimnames}: The dimension names and the names of their
levels, already given to us by the user as the argument {\tt subnames}.

\end{itemize}

This was a somewhat conceptually complex function to write, but it gets easier once you've mastered the inner structures of the {\tt ``table''} class.

\subsection{Extended Example: Finding the Largest Cells in a Table}
\label{largestcells}

It can be difficult to view a table that is very big, with a large number of rows or dimensions. One approach might be to focus on the cells with the largest frequencies. That's the purpose of the \tt{tabdom()} function---it reports the dominant frequencies in a table. Here's a simple call:

\begin{Code}
tabdom(tbl,k)
\end{Code}

This reports the cells in the table {\tt tbl} that have the {\tt k} largest 
frequencies. 

Here's another example:

\begin{Code}
> d <- c(5,12,13,4,3,28,12,12,9,5,5,13,5,4,12)
> dtab <- table(d)
> tabdom(dtab,3)
   d Freq
3  5    4
5 12    4
2  4    2
\end{Code}

The function tells us that the values 5 and 12 were the most frequent in
{\tt d}, with four instances each, and the next most frequent value was
4, with two instances. (The 3, 5, and 2 on the left are actually extraneous
information, to be discussed later.)

%
% Regarding the last sentence above in parentheses, it's too vague and I don't see this information discussed later in this chapter. I suggest that you either expand it to actually explain what these numbers are and where it's discussed later or delete it. /MS
%

As another example, consider our table {\tt cttab} in the examples in the
preceding sections:

\begin{Code}
> tabdom(cttab,2)
  Vote.for.X Voted.For.X.Last.Time Freq
1         No                    No    2
3        Yes                    No    1
\end{Code}

So the combination No-No was most frequent, with two instances, with the
second most frequent being Yes-No, with one instance.

\begin{note}
But didn't the Not Sure-Yes and Yes-Yes combinations also have one
instance, and thus should be tied with Yes-No for second place? Yes,
definitely. My code is cavalier regarding ties, and the reader is
encouraged to refine it in that direction.
\end{note}

Well, how is this accomplished? It looks fairly complicated, but
actually the work is made pretty easy by a trick, exploiting the fact
that you can present tables in data frame format. Let's use our {\tt
cttab} table again.

\begin{Code}
> as.data.frame(cttab)
  Vote.for.X Voted.For.X.Last.Time Freq
1         No                    No    2
2   Not Sure                    No    0
3        Yes                    No    1
4         No                   Yes    0
5   Not Sure                   Yes    1
6        Yes                   Yes    1
\end{Code}

Note that this is {\it not} the original data frame {\tt ct}
from which the table {\tt cttab} was constructed. It is simply a
different presentation of the table itself. There is one row for each
combination of the factors, with a Freq column added to show the number
of instances of each combination. This latter feature makes our task quite easy.

\begin{lstlisting}[numbers=left]
# finds the cells in table tbl with the k highest frequencies; handling
# of ties is unrefined
tabdom <- function(tbl,k) {
   # create a data frame representation of tbl, adding a Freq column
   tbldf <- as.data.frame(tbl)
   # determine the proper positions of the frequencies in a sorted order
   freqord <- order(tbldf$Freq,decreasing=TRUE)  (*@ \label{yyy3} @*)
   # rearrange the data frame in that order, and take the first k rows
   dom <- tbldf[freqord,][1:k,]
   return(dom)
}
\end{lstlisting}

\label{sortdf}
The comments should make the code self-explanatory.

The sorting approach in line \ref{yyy3}, which makes use of {\tt
order()}, is the standard way to sort a data frame (worth remembering,
since the situation arises rather frequently).

The approach taken here---converting a table to a data frame---could also 
be used in Section \ref{subtable}. However, you would need to be careful to remove levels from the factors, to avoid zeros in cells.

%
% Is my edit to make the following head more descriptive OK? /MS
%
\section{Other Factor- and Table-Related Functions}

R includes a number of other functions that are handy for working with tables and factors. We'll discuss two of them here: {\tt aggregate()} and {\tt cut()}.

%
% Below: I'm still not clear on why you're bringing up these packages
% here, especially after saying that we'll be discussing aggregate() and
% cut() in this section. It seems out of place. Unless you can give it
% more context, I'd suggesting cutting this paragraph. /kf
%
%
% I made the following a note, which I think works. /MS
%
\begin{note}

Hadley Wickham's {\tt reshape} package ``lets you flexibly
restructure and aggregate data using just two functions: \lstinline{melt} and
\lstinline{cast}.'' This package may take a while to learn, but it is extremely powerful.  His {\tt plyr} package is also quite versatile. You can download both packages from R's CRAN repository. See Chapter \ref{chap:packages} for more details about downloading and installing packages.
\end{note}

\subsection{The aggregate() Function}

The {\tt aggregate()} function calls {\tt tapply()} once for each
variable in a group. For example, in the abalone data, we could find
the median of each variable, broken down by gender, as follows:

\begin{Code}
> aggregate(aba[,-1],list(aba$Gender),median)
  Group.1 Length Diameter Height WholeWt ShuckedWt ViscWt ShellWt Rings
  1       F  0.590    0.465  0.160 1.03850   0.44050 0.2240   0.295 10
  2       I  0.435    0.335  0.110 0.38400   0.16975 0.0805   0.113 8
  3       M  0.580    0.455  0.155 0.97575   0.42175 0.2100   0.276 10
\end{Code}

The first argument, {\tt aba[,-1]}, is the entire data frame except for
the first column, which is \lstinline{Gender} itself. The second argument, which
must be a list, is our \lstinline{Gender} factor as before.  Finally, the third
argument tells R to compute the median on each column in each of the 
data frames generated by the subgrouping corresponding to our factors.
There are three such subgroups in our example here, and thus three rows
in the output of {\tt aggregate()}.

\subsection{The cut() Function}

A common way to generate factors, especially for tables, is the {\tt
cut()} function.  You give it a data vector {\tt x} and a set of bins
defined by a vector {\tt b}. The function then determines which bin
each of the elements of {\tt x} fall into.

The following is the form of the call we'll use here:

\begin{Code}
y <- cut(x,b,labels=FALSE)
\end{Code}

\noindent
where the bins are defined to be the semi-open intervals 
{\tt (b[1],b[2]], (b[2],b[3]],...}.  Here's an example:

\begin{Code}
> z
[1] 0.88114802 0.28532689 0.58647376 0.42851862 0.46881514 0.24226859 0.05289197
[8] 0.88035617
> seq(from=0.0,to=1.0,by=0.1)
 [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
> binmarks <- seq(from=0.0,to=1.0,by=0.1)
> cut(z,binmarks,labels=F)
[1] 9 3 6 5 5 3 1 9
\end{Code}

This says that {\tt z[1]}, 0.88114802, fell into bin 9, which was
(0,0,0.1]; {\tt z[2]}, 0.28532689, fell into bin 3; and so on.

This returns a vector, as seen in the example's result. But we can convert it into a factor, possibly then using it to build a table.  For instance, you can imagine using this to write your own specialized histogram function. (The R
function {\tt findInterval()} would be useful for this, too.)

%
% Same query re a summary paragraph. /MS
%

