2011-02-09 20 views
23

Ho un frame di dati in cui vorrei aggiungere una riga aggiuntiva che sommi i valori per le colonne. Per esempio, diciamo che ho questi dati:Come si aggiunge una riga a un frame di dati con totali?

x <- data.frame(Language=c("C++", "Java", "Python"), 
       Files=c(4009, 210, 35), 
       LOC=c(15328,876, 200), 
       stringsAsFactors=FALSE)  

dati assomiglia a questo:

Language Files LOC 
1  C++ 4009 15328 
2  Java 210 876 
3 Python 35 200 

Il mio istinto è quello di fare questo:

y <- rbind(x, c("Total", colSums(x[,2:3]))) 

E questo funziona, si calcola la totali:

> y 
    Language Files LOC 
1  C++ 4009 15328 
2  Java 210 876 
3 Python 35 200 
4 Total 4254 16404 

Il problema LEM è che i file e le colonne LOC sono stati tutti convertiti in stringhe:

> y$LOC 
[1] "15328" "876" "200" "16404" 

Capisco che questo sta accadendo perché ho creato un vettore c("Total", colSums(x[,2:3]) con gli input che sono entrambi i numeri e stringhe, ed è la conversione di tutti gli elementi per un tipo comune in modo che tutti gli elementi del vettore siano gli stessi. Quindi accade la stessa cosa alle colonne Files e LOC.

Qual è un modo migliore per farlo?

risposta

18

Avete bisogno della colonna Lingua nei vostri dati, o è più appropriato pensare a quella colonna come row.names? Ciò cambierebbe il tuo data.frame da 4 osservazioni di 3 variabili a 4 osservazioni di 2 variabili (file & LOC).

x <- data.frame(Files=c(4009, 210, 35), LOC=c(15328,876, 200), row.names=c("C++", "Java", "Python"), stringsAsFactors=F)  
x["Total" ,] <- colSums(x) 


> x 
     Files LOC 
C++  4009 15328 
Java  210 876 
Python 35 200 
Total 4254 16404 
+12

Personalmente, non è consigliabile memorizzare i dati in giochi di ruolo, ecco a cosa servono le variabili! – hadley

+1

In generale, sono d'accordo. Tendo anche a seguire il consiglio di @ csgillespie di non mescolare dati grezzi e statistiche riassuntive nello stesso oggetto. Come ha sottolineato il PO, tuttavia, non è un problema in questo caso poiché la domanda ruota intorno alla presentazione dei dati, non a un'ulteriore analisi. – Chase

+3

Qual è l'equivalente del tidyverse? – thadk

19

Ecco un modo che quello che vuoi fa, ma ci possono benissimo essere un soluzione più elegante.

rbind(x, data.frame(Language="Total",t(colSums(x[,-1])))) 

Per la cronaca, io preferisco la risposta di Chase se non assolutamente bisogno colonna Language.

4

Se (1) non abbiamo bisogno della voce "Language" sulla prima colonna allora possiamo rappresentarlo utilizzando i nomi di riga e se (2) è ok per etichettare l'ultima fila come "Sum" piuttosto che "Total" allora possiamo usare addmargins come questo:

rownames(x) <- x$Language 
addmargins(as.table(as.matrix(x[-1])), 1) 

dono:

 Files LOC 
C++  4009 15328 
Java  210 876 
Python 35 200 
Sum  4254 16404 

Se facciamo volere la prima colonna etichettata "Language" e la riga totale etichettato "Total" allora è un po 'lo dito:

rownames(x) <- x$Language 
Total <- sum 
xa <- addmargins(as.table(as.matrix(x[-1])), 1, FUN = Total) 
data.frame(Language = rownames(xa), as.matrix(xa[]), row.names = NULL) 

dando:

Language Files LOC 
1  C++ 4009 15328 
2  Java 210 876 
3 Python 35 200 
4 Total 4254 16404 
1

Sei sicuro di vuole veramente avere i totali delle colonne nella cornice di dati? Per me, l'interpretazione della cornice dati dipende ora dalla riga.Ad esempio,

  • Righe 1- (n-1): quanti file sono associati con un linguaggio particolare
  • Row n: quanti file sono associati tutte le lingue

Questo diventa più confuso se si inizia a suddividere i dati. Ad esempio, si supponga di voler sapere quali lingue hanno più di 100 file:

> x = data.frame(Files=c(4009, 210, 35), 
       LOC=c(15328,876, 200), 
       row.names=c("C++", "Java", "Python"), 
       stringsAsFactors=FALSE)  
> x["Total" ,] = colSums(x) 
> x[x$Files > 100,] 
     Files LOC 
C++ 4009 15328 
Java 210 876 
Total 4254 16404#But this refers to all languages! 

La fila Total ora è sbagliato!

Personalmente elaborerei le somme delle colonne e le memorizzerei in un vettore separato.

+1

In genere non lo farei per l'analisi, ma questo è per la presentazione. Questo è l'ultimo passo prima di generare una tabella in un documento LaTeX con Sweave. –

+1

@lorin Giusto abbastanza – csgillespie

0

tuo istinto originale funzionerebbe se costretti dalle colonne a numerico:

y$LOC <- as.numeric(y$LOC) 
y$Files <- as.numeric(y$Files) 

E poi applicare colSums() e rbind().

1

Dato che si tratta di un ultimo passaggio prima dell'esportazione per la presentazione, è possibile che i nomi di colonna includano spazi in essi per maggiore chiarezza (ad esempio "Totale generale"). In tal caso, il seguente sarà assicurare che il data.frame creata verrà rbind al dataset originale senza un errore causato da nomi di colonna non corrispondenti:

dfTotals <- data.frame(Language="Total",t(colSums(x[,-1])))) 

colnames(dfTotals) <- names(x) 

rbind(x, dfTotals) 
6

Prova questa

y[4,] = c("Total", colSums(y[,2:3])) 
1

penso che al giorno d'oggi c'è un più semplice modo per questo con il pacchetto dplyr:

library(dplyr) 
x <- mutate(x, Total = rowSums(x[, 2:3])) 
0

È possibile utilizzare applicare per ogni somma col

Applicare (df [-colonne che non si voleva insomma], 2, somma)

E poi si può

rbind

che i dati nel vostro df

Problemi correlati