Question Comptes et pourcentages dans xTable, Sweave, R, tableaux croisés


Edit: En partant de la réponse de aL3xa ci-dessous, j'ai modifié sa syntaxe ci-dessous. Pas parfait, mais se rapprocher. Je n'ai toujours pas trouvé de moyen de faire en sorte que xtable accepte les arguments \ multicolumn {} pour les colonnes ou les lignes. Il apparaît également que Hmisc gère certains de ces types de tâches dans les coulisses, mais il ressemble un peu d'une entreprise de comprendre ce qui se passe là-bas. Quelqu'un at-il de l'expérience avec la fonction latex dans 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)
}

Je voudrais créer un tableau formaté pour la sortie LaTeX qui contient à la fois les nombres et les pourcentages pour chaque colonne ou variable. Je n'ai pas trouvé de solution toute faite à ce problème, mais je pense que je dois recréer la roue dans une certaine mesure.

J'ai développé une solution pour les tabulations simples, mais j'ai du mal à adopter quelque chose pour un tableau croisé.

Quelques exemples de données:

#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"))

Et maintenant, la fonction onglet droit de travail:

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")

Quelqu'un a-t-il des suggestions pour l’adopter pour les tableaux croisés (c’est-à-dire le jour de la semaine PAR le but du voyage)? Voici ce que j'ai actuellement écrit, qui n'utilise pas la bibliothèque XTABLE et fonctionne presque, mais n'est pas dynamique et est assez moche pour travailler avec:

#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
2017-08-09 21:42


origine


Réponses:


Dans le paquetage Tables, il y a une ligne:

# 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"))

dataframe <-  data.frame( dow, purp)

# The packages

library(tables)
library(Hmisc)

# The table
tabular(  (Weekday=dow) ~  (Purpose=purp)*(Percent("row")+ 1)    ,data=dataframe        )

# The latex table
latex(  tabular(  (Weekday=dow) ~  (Purpose=purp)*(Percent("col")+ 1)    ,data=dataframe        ))

En utilisant les booktabs, vous obtenez ceci (peut être personnalisé davantage):

enter image description here


11
2018-05-07 08:19



Super question, celle-ci me dérange un peu (ce n'est pas cette dur, c'est juste que je suis paresseux comme un enfer ... comme d'habitude. Cependant ... même si la question est bonne, je crains que votre approche ne le soit pas. Il y a un paquet inestimable appelé xtable que vous pouvez (mal) utiliser. En outre, cette question est trop courante - il y a de grandes chances qu'il existe déjà une solution prête à l'emploi les internets.

Un de ces jours, je suis sur le point de travailler une fois pour toutes (je posterai le code sur GitHub). L'idée principale va un peu comme ceci: voulez-vous la fréquence et / ou des valeurs en pourcentage dans une cellule (séparés par \) ou des lignes avec des fréquences absolues et relatives (ou%) dans la succession? Je vais avec le 2nd un, alors je vais poster une solution "premiers secours" pour le moment:

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)
}

Maintenant, essayez quelque chose comme:

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%

Assurez-vous que vous avez chargé xtable paquet et utilisation print (c'est une fonction générique, vous devez donc passer une xtable objet classé). Il est important de supprimer les noms de lignes. Je vais optimiser celui-ci demain - il devrait être xtable compatible. C'est 3 heures dans mon fuseau horaire, alors avec ces lignes je terminerai ma réponse:

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

À votre santé!


7
2017-08-10 00:55



Je ne pouvais pas comprendre comment générer un en-tête de plusieurs colonnes en utilisant XTABLE, mais je ne me rends compte que je pouvais concaténer mes comptes et pourcentages dans la même colonne à des fins d'impression. Pas idéal, mais semble faire le travail. Voici la fonction que j'ai écrite:

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))
}

Probablement pas le produit final, mais permet une certaine flexibilité dans les paramètres. Au niveau le plus élémentaire, n’est qu’une enveloppe de table() mais peut également générer une sortie au format LaTeX. Voici ce que j'ai fini par utiliser dans un Sweavedocument:

<<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
2017-08-12 05:22



En utilisant multicolumn avec latex du Hmisc le paquet n'est pas trop mal. Ce document Sweave minimal:

\documentclass{article}
\begin{document}

<<echo = FALSE,results = tex>>=
library(Hmisc)
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"))
tbl <- table(dow,purp)
tbl_prop <- round(100 * prop.table(tbl,1),2)

tbl_df <- as.data.frame.matrix(tbl)
tbl_prop_df <- as.data.frame.matrix(tbl_prop)
colnames(tbl_prop_df) <- paste(colnames(tbl_prop_df),"1",sep = "")
df <- cbind(tbl_df,tbl_prop_df)[,ggplot2:::interleave(1:4,5:8)]
colnames(df) <- rep(c('n','\\%'),times = 4)

latex(object=df,file="",cgroup = colnames(tbl_df),
      colheads = NULL,rowlabel = "",
      center = "centering",collabel.just = rep("r",8))
@

\end{document}

Produit ceci pour moi:

enter image description here

De toute évidence, j'ai codé un bon nombre de choses, et il pourrait y avoir des façons plus lisses de produire le bloc de données que vous finissez par passer à latex, mais cela devrait au moins commencer à utiliser multicolum.

En outre, un léger gotcha, j'ai utilisé ggplot2's interleave fonction lors de la combinaison des comptes et des pourcentages pour alterner les colonnes. C'est juste parce que je suis paresseux.


4
2018-06-17 04:56



Comment cela fonctionnerait pour vous?

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)

Il ne vous donne pas de belles multicolonnes, et je n’ai pas assez d’expérience avec xtable savoir si cela est possible. Cependant, si vous allez écrire des fonctions personnalisées, vous pouvez en essayer une qui opère sur les noms de colonne de df.print. Vous pourriez même être en mesure d'en écrire un assez général pour prendre toutes sortes de données de refonte en entrée.

Modifier: Juste pensé à une bonne solution pour vous rapprocher. Après avoir créé 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)

Maintenant, chaque cellule contiendra N / percent valeurs


1
2017-08-09 23:55



Je me rends compte que ce thread est un peu ancien, mais la fonction tableNominal () dans le package reporttools peut fournir les fonctionnalités que vous recherchez.


0
2018-01-03 16:42



tab<-table(row, col)
ctab<-round(100*prop.table(tab,2), 2) # for column percents (see the args for prop.table)

for (i in 1:length(tab)) {
  ctab[i]<-paste(tab[i]," (", ctab[i], "%", ")", sep="")
}

require(xtable);
k<-xtable(ctab,digits=1) # make latex table

0
2018-06-16 12:25