Liczniki i procenty w tabelach xTable, Sweave, R, cross

Edit: bazując na odpowiedzi aL3xa poniżej, zmodyfikowałem jego składnię poniżej. Nie idealnie, ale coraz bliżej. Nadal nie znalazłem sposobu, aby xtable accept \multicolumn{} argumenty dla kolumn lub wierszy. Wydaje się również, że Hmisc zajmuje się niektórymi tego typu zadaniami za kulisami, ale wygląda na to, że zrozumienie tego, co się tam dzieje, wygląda trochę jak przedsięwzięcie. Czy ktoś ma doświadczenie z funkcją latex w 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)
}

Chciałbym utworzyć tabelę sformatowane dla wyjścia LaTeX, które zawiera zarówno liczby i procenty dla każdej kolumny lub zmiennej. Nie znalazłem gotowego rozwiązania tego problemu, ale czuję, że muszę odtwarzać koło w pewnym stopniu.

Opracowałem rozwiązanie dla tabulacji prostych, ale zmagam się z przyjęciem czegoś do tabulacji krzyżowej.

Najpierw kilka przykładowych danych:

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

A teraz działa funkcja straight tab:

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

Czy ktoś ma jakieś sugestie dotyczące przyjęcie tego do tabulacji krzyżowych (tj. dzień tygodnia według celu podróży)? Oto, co napisałem obecnie, który nie korzysta z biblioteki xtable i prawie działa, ale nie jest dynamiczny i jest dość brzydki do pracy:

#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")
Author: Chase, 2010-08-10

7 answers

W pakiecie Tables jest to jedna linijka:

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

Używając tabel książkowych, otrzymujesz to (można je dodatkowo dostosować):

Tutaj wpisz opis obrazka

 11
Author: Rasmus Larsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-07 08:19:51

Świetne pytanie, to mi przeszkadza przez jakiś czas (to nie jestto trudne, to tylko ja jestem leniwy jak cholera... jak zwykle). Jednak... choć pytanie jest świetne, obawiam się, że Twoje podejście nie jest. istnieje bezcenny pakiet o nazwie xtable, który możesz (mis)użyć. Poza tym ten problem jest zbyt powszechny - istnieje duża szansa, że gdzieś na internetach jest już gotowe rozwiązanie.

Pewnego dnia mam zamiar to wypracować raz na zawsze (Wyślę kod na GitHub). Główna idea idzie trochę tak: czy chcesz częstotliwości i / lub wartości procentowe w jednej komórce (oddzielone przez\) lub wiersze z absolutnymi i względnymi częstotliwościami (lub %) po kolei? Ja wybrałbym 2nd jeden, więc na razie wrzucę rozwiązanie "pierwszej pomocy":

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

A teraz Spróbuj czegoś takiego:

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%

Upewnij się, że wczytałeś pakiet xtable i użyłeś print (jest to funkcja ogólna, więc musisz przekazać obiekt klasy xtable). On ważne, abyś usunął nazwy rzędów. Jutro zoptymalizuję ten - powinien być kompatybilny. Jest 3 rano w mojej strefie czasowej, więc tymi liniami zakończę swoją odpowiedź:

print(xtable(ctab(tb)), include.rownames = FALSE)
Zdrówko!
 7
Author: aL3xa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-10 00:55:14

Nie byłem w stanie dowiedzieć się, jak wygenerować nagłówek wielu kolumn za pomocą xtable, ale zdałem sobie sprawę, że mogę połączyć moje liczby i procenty w tę samą kolumnę do celów drukowania. Nie jest idealny, ale wydaje się, że wykonuje swoją pracę. Oto funkcja, którą napisałem:

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

Prawdopodobnie nie jest to produkt końcowy, ale pozwala na pewną elastyczność parametrów. Na najbardziej podstawowym poziomie, jest tylko wrapper table(), ale może również generować dane wyjściowe sformatowane w Latexie. Oto co ja koniec użycia w Sweave dokumencie:

<<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
Author: Chase,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-12 05:22:44

Używanie multicolumn z latex z pakietu Hmisc nie jest takie złe. Ten minimalny dokument Sweave:

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

Produkuje to dla mnie:

Tutaj wpisz opis obrazka

Oczywiście, zakodowałem sporo rzeczy i mogą być sprytniejsze sposoby, aby stworzyć ramkę danych, którą ostatecznie przekazujesz latex, ale to powinno przynajmniej dać początek użyciu multicolum.

Również, drobna wpadka, użyłem ggplot2 ' S interleave Funkcja przy łączeniu zliczeń i procentów do Zmień kolumny. To dlatego, że jestem leniwy.

 4
Author: joran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-17 04:56:13

Jak to działa dla Ciebie?

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)

To nie daje ładne wielokolumny, i nie mam wystarczająco dużo doświadczenia z xtable, aby dowiedzieć się, czy to możliwe. Jeśli jednak masz zamiar pisać niestandardowe funkcje, możesz wypróbować taką, która działa nad nazwami kolumn df.print. Możesz nawet napisać jeden na tyle ogólny, aby przyjąć wszystkie rodzaje przekształconych ramek danych jako dane wejściowe.

Edit: Po prostu pomyślałem o dobrym rozwiązaniu, aby zbliżyć cię do siebie. Po utworzeniu 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)

Teraz każda komórka będzie zawierać N / percent wartości

 1
Author: JoFrhwld,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-10 00:27:56

Zdaję sobie sprawę, że ten wątek jest trochę stary, ale funkcja tableNominal () w pakiecie reporttools może zapewnić funkcjonalność, której szukasz.

 0
Author: Charlie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-03 16:42:18
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
Author: Ademu Onu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-21 12:33:03