Подсчеты и проценты в xTable, Sweave, R, кросс-табуляции

Редактировать: Основываясь на ответе aL3xa ниже, я изменил его синтаксис ниже. Не идеально, но все ближе. Я до сих пор не нашел способ заставить xtable принимать аргументы \ multicolumn {} для столбцов или строк. Также кажется, что Hmisc выполняет некоторые из этих типов задач за кулисами, но это кажется чем-то вроде понимания того, что там происходит. У кого-нибудь есть опыт работы с функцией latex в Hmisc?

ctab <- function(tab, dec = 2, margin = NULL) {
    tab <- as.table(tab)
    ptab <- paste(round(prop.table(tab, margin = margin) * 100, dec), "%", sep = "")
    res <- matrix(NA, nrow = nrow(tab) , ncol = ncol(tab) * 2, byrow = TRUE)
    oddc <- 1:ncol(tab) %% 2 == 1
    evenc <- 1:ncol(tab) %% 2 == 0
    res[,oddc ] <- tab
    res[,evenc ] <- ptab
    res <- as.table(res)
    colnames(res) <- rep(colnames(tab), each = 2)
    rownames(res) <- rownames(tab)
    return(res)
}

Я хотел бы создать таблицу, отформатированную для вывода LaTeX, которая будет содержать как количество, так и проценты для каждого столбца или переменной. Я не нашел готового решения этой проблемы, но чувствую, что должен в какой-то степени воссоздать колесо.

Я разработал решение для прямых таблиц, но я борюсь с принятием чего-то для кросс-табуляции.

Сначала некоторые примерные данные:

#Generate sample data
dow <- sample(1:7, 100, replace=TRUE)
purp <- sample(1:4, 100, replace=TRUE)
dow <- factor(dow, 1:7, c("Mon", "Tues", "Wed", "Thurs", "Fri", "Sat", "Sun"))
purp <- factor(purp, 1:4, c("Business", "Commute", "Vacation", "Other"))

А теперь работающая прямая табуляция:

customTable <- function(var, capt = NULL){
    counts <- table(var)
    percs <- 100 * prop.table(counts)       

    print(
        xtable(
            cbind(
                Count = counts
                , Percent = percs
            )
        , caption = capt
        , digits = c(0,0,2)
        )
    , caption.placement="top"
    )
}

#Usage
customTable(dow, capt="Day of Week")
customTable(purp, capt="Trip Pupose")

Есть ли у кого-нибудь какие-либо предложения по принятию этого для кросс-табуляции (т.е. день недели BY цель поездки)? Вот то, что я в настоящее время написал, который НЕ использует библиотеку xtable, и ALMOST работает, но не является динамическим и довольно уродливым для работы:

#Create table and percentages
a <- table(dow, purp)
b <- round(prop.table(a, 1),2)

#Column bind all of the counts & percentages together, this SHOULD become dynamic in future
d <- cbind( cbind(Count = a[,1],Percent =  b[,1])
        , cbind(Count = a[,2], Percent = b[,2])
        , cbind(Count = a[,3], Percent = b[,3])
        , cbind(Count = a[,4], Percent = b[,4])
)

#Ugly function that needs help, or scrapped for something else
crossTab <- function(title){
    cat("\\begin{table}[ht]\n")
    cat("\\begin{center}\n")
    cat("\\caption{", title, "}\n", sep="") 

    cat("\\begin{tabular}{rllllllll}\n")
    cat("\\hline\n")

    cat("", cat("", paste("&\\multicolumn{2}{c}{",colnames(a), "}"), sep = ""), "\\\\\n", sep="")
    c("&", cat("", colnames(d), "\\\\\n", sep=" & "))
    cat("\\hline\n")
    c("&", write.table(d, sep = " & ", eol="\\\\\n", quote=FALSE, col.names=FALSE))

    cat("\\hline\n")
    cat("\\end{tabular}\n")
    cat("\\end{center}\n")
    cat("\\end{table}\n")   
}   

crossTab(title = "Day of week BY Trip Purpose")
15
задан Chase 10 August 2010 в 02:12
поделиться

3 ответа

Мне не удалось понять, как сгенерировать заголовок из нескольких столбцов с помощью xtable, но я понял, что могу объединить свои подсчеты и проценты в один столбец для печати. Не идеально, но, похоже, выполняет свою работу. Вот функция, которую я написал:

ctab3 <- function(row, col, margin = 1, dec = 2, percs = FALSE, total = FALSE, tex = FALSE, caption = NULL){
    tab <- as.table(table(row,col))
    ptab <- signif(prop.table(tab, margin = margin), dec)

    if (percs){

        z <- matrix(NA, nrow = nrow(tab), ncol = ncol(tab), byrow = TRUE) 
        for (i in 1:ncol(tab)) z[,i] <- paste(tab[,i], ptab[,i], sep = " ")
        rownames(z) <- rownames(tab)
        colnames(z) <- colnames(tab)

        if (margin == 1 & total){
            rowTot <- paste(apply(tab, 1, sum), apply(ptab, 1, sum), sep = " ")
            z <- cbind(z, Total = rowTot)
        } else if (margin == 2 & total) {
            colTot <- paste(apply(tab, 2, sum), apply(ptab, 2, sum), sep = " ")
            z <- rbind(z,Total = colTot)
        }
    } else {
        z <- table(row, col)    
    }
ifelse(tex, return(xtable(z, caption)), return(z))
}

Возможно, не окончательный продукт, но допускает некоторую гибкость в параметрах. На самом базовом уровне это только оболочка для table () , но также может генерировать выходные данные в формате LaTeX. Вот что я в итоге использовал в документе Sweave :

<<echo = FALSE>>=
for (i in 1:ncol(df)){
    print(ctab3(
        col = df[,1]
        , row = df[,i]
        , margin = 2
        , total = TRUE
        , tex = TRUE
        , caption = paste("Dow by", colnames(df[i]), sep = " ")
    ))
}
@
4
ответ дан 1 December 2019 в 02:28
поделиться

Отличный вопрос, это меня какое-то время беспокоит (это не так сложно, просто я чертовски ленив ... как обычно). Однако ... хотя вопрос отличный, но, боюсь, ваш подход - нет. Есть бесценный пакет под названием xtable , который можно (не) использовать. Кроме того, эта проблема слишком распространена - велика вероятность, что где-то в Интернет уже есть готовое решение.

На днях я собираюсь разобраться с этим раз и навсегда (выложу код на GitHub). Основная идея выглядит примерно так: хотите ли вы, чтобы частота и / или процентные значения в одной ячейке (разделенной \) или строках с абсолютной и относительной частотами (или%) последовательно? Я бы выбрал 2 и , поэтому сейчас я опубликую решение для «первой помощи»:

ctab <- function(tab, dec = 2, ...) {
  tab <- as.table(tab)
  ptab <- paste(round(prop.table(tab) * 100, dec), "%", sep = "")
  res <- matrix(NA, nrow = nrow(tab) * 2, ncol = ncol(tab), byrow = TRUE)
  oddr <- 1:nrow(tab) %% 2 == 1
  evenr <- 1:nrow(tab) %% 2 == 0
  res[oddr, ] <- tab
  res[evenr, ] <- ptab
  res <- as.table(res)
  colnames(res) <- colnames(tab)
  rownames(res) <- rep(rownames(tab), each = 2)
  return(res)
}

Теперь попробуйте что-нибудь вроде:

data(HairEyeColor)           # load an appropriate dataset
tb <- HairEyeColor[, , 1]    # choose only male respondents
ctab(tb)
      Brown  Blue   Hazel Green
Black 32     11     10    3    
Black 11.47% 3.94%  3.58% 1.08%
Brown 53     50     25    15   
Brown 19%    17.92% 8.96% 5.38%
Red   10     10     7     7    
Red   3.58%  3.58%  2.51% 2.51%
Blond 3      30     5     8    
Blond 1.08%  10.75% 1.79% 2.87%

Убедитесь, что вы загрузили xtable и используйте print (это общая функция, поэтому вы должны передать классифицированный объект xtable ). Важно подавить имена строк. Завтра я оптимизирую его - он должен быть совместим с xtable . В моем часовом поясе 3 часа ночи, поэтому я закончу свой ответ:

print(xtable(ctab(tb)), include.rownames = FALSE)

Ура!

7
ответ дан 1 December 2019 в 02:28
поделиться

Как это может работать для вас?

library(reshape)
library(plyr)
df <- data.frame(dow = dow, purp = purp)

df.count <- count(df)
df.count <- ddply(df.count, .(dow), transform, p = round(freq / sum(freq),2))

df.m <- melt(df.count)

df.print <- cast(df.m, dow ~ purp + variable)

library(xtable)
xtable(df.print)

Это не даст вам красивых многоколоночных таблиц, и у меня нет достаточного опыта работы с xtable, чтобы понять, возможно ли это. Однако, если вы собираетесь писать пользовательские функции, вы можете попробовать функцию, которая работает над именами столбцов df.print. Возможно, вы даже сможете написать достаточно общую функцию, которая будет принимать на вход всевозможные переделанные фреймы данных.

Edit:. Только что пришло в голову хорошее решение, которое поможет вам приблизиться к цели. После создания df.m

df.preprint <- ddply(df.m, .(dow, purp), function(x){
        x <- cast(x, dow ~ variable)
        x$value <- paste(x$freq, x$p, sep = " / ")
        return(c(value = x$value))
     }
)

df.print <- cast(df.preprint, dow ~ purp)

print(xtable(df.print), include.rownames = F)

Теперь каждая ячейка будет содержать N / percent значений

1
ответ дан 1 December 2019 в 02:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: