2015-04-29 13 views
10

dire che ho questo frame di dati:Come somma sulle diagonali del telaio dati

 1 2 3 4  
100 8 12 5 14 
99 1 6 4 3 
98 2 5 4 11 
97 5 3 7 2 

In questo quadro i dati di cui sopra, i valori indicano conti di quanti osservazioni assumere (100, 1), (99, 1), ecc

nel mio contesto, le diagonali hanno gli stessi significati:

 1 2 3 4 
100 A B C D 
99 B C D E 
98 C D E F 
97 D E F G 

Come potrei riassumere attraverso le diagonali (vale a dire, somma i conteggi delle lettere simili) nel primo frame di dati?

Questo produrrebbe:

group sum 
A  8 
B  13 
C  13 
D  28 
E  10 
F  18 
G  2 

Per esempio, D è 5+5+4+14

+0

E' una matrice o un data.frame? (Una matrice è più facile da eseguire su questo) –

+0

data.frame, ma convertirlo in una matrice e tornare a un data.frame come in @Ben La risposta di Bolker fa il trucco. – bill999

+0

Simile: http://stackoverflow.com/q/27935555/1191259 – Frank

risposta

17

È possibile utilizzare row() e col() per identificare le relazioni riga/colonna.

m <- read.table(text=" 
    1 2 3 4  
100 8 12 5 14 
99 1 6 4 3 
98 2 5 4 11 
97 5 3 7 2") 

vals <- sapply(2:8, 
     function(j) sum(m[row(m)+col(m)==j])) 

o (come suggerito nei commenti da parte? @thelatemail)

vals <- sapply(split(as.matrix(m), row(m) + col(m)), sum) 
data.frame(group=LETTERS[seq_along(vals)],sum=vals) 

o (@Frank)

data.frame(vals = tapply(as.matrix(m), 
     (LETTERS[row(m) + col(m)-1]), sum)) 

as.matrix() è necessario per far funzionare correttamente split() ...

+0

Qual è la logica del motivo per cui è necessario convertirlo in una matrice (invece di lasciarlo in data.frame) per fare questo? – bill999

+2

@BenBolker - la riga e il lavoro funzionano su tutti gli oggetti "a matrice" con 2 dimensioni incl. matrici, data.frames, tabelle, ecc. – thelatemail

+0

oh, OK, ho sbagliato. –

5

Ecco una soluzione che utilizza stack() e.210, anche se richiede il secondo data.frame contengono vettori di caratteri, al contrario di fattori (potrebbe essere costretto con lapply(df2,as.character)):

df1 <- data.frame(a=c(8,1,2,5), b=c(12,6,5,3), c=c(5,4,4,7), d=c(14,3,11,2)); 
df2 <- data.frame(a=c('A','B','C','D'), b=c('B','C','D','E'), c=c('C','D','E','F'), d=c('D','E','F','G'), stringsAsFactors=F); 
aggregate(sum~group,data.frame(sum=stack(df1)[,1],group=stack(df2)[,1]),sum); 
## group sum 
## 1  A 8 
## 2  B 13 
## 3  C 13 
## 4  D 28 
## 5  E 10 
## 6  F 18 
## 7  G 2 
6

Un'altra soluzione utilizzando la definizione di bgoldst di df1 e df2

sapply(unique(c(as.matrix(df2))),function(x) sum(df1[df2==x])) 

esprime

#A B C D E F G 
#8 13 13 28 10 18 2 

(Non è proprio il formato che si voleva, ma forse è ok ...)

+1

Ho dimenticato di dire che il mio soluzione presume che tu abbia impostato 'options (stringsAsFactors = FALSE)'. – cryo111

6

Un'altra aggregate variante, evitando l'interfaccia formula, il che complica in realtà questioni in questo caso:

aggregate(list(Sum=unlist(dat)), list(Group=LETTERS[c(row(dat) + col(dat))-1]), FUN=sum) 

# Group Sum 
#1  A 8 
#2  B 13 
#3  C 13 
#4  D 28 
#5  E 10 
#6  F 18 
#7  G 2 
Problemi correlati