Hey Marc,
Your code was very helpful. You should make a new R function out of it.
Actually it looks like adding margins may be a little bit tricky if I
only want sums of the counts, not the percentages. If I add margins
after I rbind, then R will sum together the counts with the
probabilities, which is undesired. If I add margins before I rbind which
is what I've been doing, it will produce sums of the counts and
percentages independently but this still gives me sums of probabilities
that are pretty useless and confusing in the table.
I'm actually running into bigger trouble trying to put the for loop I
want into odfweave.
If I use odfweave, the odfweave function produces an output file, but
the for loop produces no tables. If I use R2HTML with similar code, I
just get the last table the for loop produces. Here is a look at the
code of odfweave, which seems to be correct with syntax but doesn't
produce any tables.
<<CrossTable, echo = FALSE, results = xml>>=
# Generate counts and proportions
# row, column and table
for ( i in 5:ncol(Elementary)[1] ) {
TAB <- table(Elementary[["Curriculum"]], Elementary[,i])
TAB.prop.c <- prop.table(table(Elementary[["Curriculum"]],
Elementary[,i]),2)
TAB <- addmargins(TAB)
TAB.prop.c <- addmargins(TAB.prop.c)
MAT.3 <- t(apply(rbind(TAB.prop.c), 1,
function(x) sprintf("%.3f", x)))
MAT <- rbind(TAB, MAT.3)
# order by rownames
MAT <- MAT[order(rownames(MAT)), ]
# Set duplicated rownames to blank
rownames(MAT)[which(duplicated(rownames(MAT)))] <- ""
odfTable(MAT)
}
@
Sorry for bugging everyone with a question that is probably simple. Also
is there a way to add a table title in the odfTable function.
Thanks again,
PJ
Marc Schwartz wrote:
on 03/02/2009 03:11 PM Max Kuhn wrote:
PJ,
Hi, I've been trying to prepare some crosstables for some survey questions
for a client. I have been using the CrossTable function in the gmodels
package. However, this command only seems to be able to create CrossTables
in text documents.
I've been trying to use odfTable in odfweave to create tables that are
standalone objects in the document that I can then convert to other formats,
copy and paste and do whatever with.
You will have to do some work to get CrossTable results into odfWeave
for a few reasons. The main one is: CrossTable prints the output (as
opposed to outputting an object of a certain class that uses print to
make the results like table() and print.table()). In some cases, it is
easy to translate the output you see on the screen to odf markup. I'm
not sure that this function is one of those cases. That is not a
slight against the function, it just isn't meant to do that.
The problem is no matter how I try to get the CrossTable into the odfTable,
i either get an error message saying there is no appropriate method for
odfTable or the table is inproperly formatted.
It would be nice to have a reproducible example along with the results
of sessionInfo(). Looking at ?odfTable, it has that the main argument
should be "a vector, matrix or data frame". I can' tell if there is a
bug in odfTable or if you are just using it incorrectly.
Honestly, I'm not even married to using odfTable. All I'm looking for is a
nicely formatted table, that is a standalone object, that I can copy and
paste and convert at will, and that contains the column percentages in the
table.
CrossTable may not be what you want then. The results are a list of
components of the table.
In follow up to Max' post, if you can output or print the captured
CrossTable() content in odfWeave to a monospaced font, it would line up
appropriately. The use of a monospace font in the R console is the
presumption for CrossTable() output. However, it will look exactly as it
would in the R console (see below) as opposed to something more
formalized and "pretty".
You could largely recreate most of CrossTable's output using table() and
prop.table() by creating a matrix or dataframe, depending upon what you
want things to look like. This is what is essentially done within
CrossTable().
Using one of the examples in ?CrossTable:
CrossTable(infert$education, infert$induced, prop.chisq = FALSE)
...
| infert$induced
infert$education | 0 | 1 | 2 | Row Total |
-----------------|-----------|-----------|-----------|-----------|
0-5yrs | 4 | 2 | 6 | 12 |
| 0.333 | 0.167 | 0.500 | 0.048 |
| 0.028 | 0.029 | 0.162 | |
| 0.016 | 0.008 | 0.024 | |
-----------------|-----------|-----------|-----------|-----------|
6-11yrs | 78 | 27 | 15 | 120 |
| 0.650 | 0.225 | 0.125 | 0.484 |
| 0.545 | 0.397 | 0.405 | |
| 0.315 | 0.109 | 0.060 | |
-----------------|-----------|-----------|-----------|-----------|
12+ yrs | 61 | 39 | 16 | 116 |
| 0.526 | 0.336 | 0.138 | 0.468 |
| 0.427 | 0.574 | 0.432 | |
| 0.246 | 0.157 | 0.065 | |
-----------------|-----------|-----------|-----------|-----------|
Column Total | 143 | 68 | 37 | 248 |
| 0.577 | 0.274 | 0.149 | |
-----------------|-----------|-----------|-----------|-----------|
# Do the above incrementally
# Generate counts and proportions
# row, column and table
TAB <- table(infert$education, infert$induced)
TAB.prop.r <- prop.table(table(infert$education, infert$induced), 1)
TAB.prop.c <- prop.table(table(infert$education, infert$induced), 2)
TAB.prop.t <- prop.table(table(infert$education, infert$induced))
# rbind() it all together
MAT <- rbind(TAB, TAB.prop.r, TAB.prop.c, TAB.prop.t)
# order by rownames
MAT <- MAT[order(rownames(MAT)), ]
# Set duplicated rownames to blank
rownames(MAT)[which(duplicated(rownames(MAT)))] <- ""
MAT
0 1 2
0-5yrs 4.00000000 2.000000000 6.00000000
0.33333333 0.166666667 0.50000000
0.02797203 0.029411765 0.16216216
0.01612903 0.008064516 0.02419355
12+ yrs 61.00000000 39.000000000 16.00000000
0.52586207 0.336206897 0.13793103
0.42657343 0.573529412 0.43243243
0.24596774 0.157258065 0.06451613
6-11yrs 78.00000000 27.000000000 15.00000000
0.65000000 0.225000000 0.12500000
0.54545455 0.397058824 0.40540541
0.31451613 0.108870968 0.06048387
So that gives you the core table with counts, table, row and column
proportions in that order top to bottom for each row category as in
CrossTable(). Adjust the above based upon what you actually want in the
table output.
With some additional work, you could add row and column totals and so
forth.
If you wanted variable numbers of digits after the decimal for each row
as in CrossTable(), you could pre-format the numbers using sprintf(),
converting MAT to a character matrix in the process. For example:
MAT.3 <- t(apply(rbind(TAB.prop.r, TAB.prop.c, TAB.prop.t), 1,
function(x) sprintf("%.3f", x)))
MAT <- rbind(TAB, MAT.3)
# order by rownames
MAT <- MAT[order(rownames(MAT)), ]
# Set duplicated rownames to blank
rownames(MAT)[which(duplicated(rownames(MAT)))] <- ""
MAT
0 1 2
0-5yrs "4" "2" "6"
"0.333" "0.167" "0.500"
"0.028" "0.029" "0.162"
"0.016" "0.008" "0.024"
12+ yrs "61" "39" "16"
"0.526" "0.336" "0.138"
"0.427" "0.574" "0.432"
"0.246" "0.157" "0.065"
6-11yrs "78" "27" "15"
"0.650" "0.225" "0.125"
"0.545" "0.397" "0.405"
"0.315" "0.109" "0.060"
With 'MAT' finalized, you could then use Max' functions to generate
pretty output for an OO.org document or use xtable() in the xtable
package or latex() in the Hmisc package for LaTeX or perhaps HTML output.
HTH,
Marc Schwartz
______________________________________________
R-help@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.