2015-04-29 20 views
10

powiedzieć, że mam tę ramkę danych:Jak podsumować ponad przekątnych ramki danych

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

W tym powyższej ramce danych, wartości wskazują liczniki ile obserwacje podjąć (100, 1), (99, 1) itd

w moim kontekście przekątne mają te same znaczenia:

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

Jak chciałbym podsumować całej przekątnych (tj zsumować liczbę podobnego liter) w pierwszym ramki danych?

byłoby to produkować:

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

Na przykład D jest 5+5+4+14

+0

Jest to matryca lub data.frame? (Matryca jest łatwiejsza do wykonania tego) –

+0

data.frame, ale konwersja do macierzy iz powrotem do data.frame, jak w @Ben Bolker ma odpowiedź. – bill999

+0

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

Odpowiedz

17

Można użyć row() i col() zidentyfikować relacje wiersz/kolumna.

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

lub (jak zasugerowano w komentarzach przez? @thelatemail)

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

lub (@Frank)

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

as.matrix() jest wymagane, aby split() pracę poprawnie ...

+0

Jaka jest logika, dlaczego trzeba ją przekonwertować na macierz (zamiast pozostawić ją w data.frame), aby to zrobić? – bill999

+2

@BenBolker - rząd i col działają na wszystkich obiektach "matrycowych" z 2 wymiarami włącznie macierze, data.frames, tabele itp. – thelatemail

+0

oh, OK, myliłem się. –

5

Oto rozwiązanie z użyciem stack() i aggregate(), chociaż wymaga drugiego data.frame zawierają wektory postaci, w przeciwieństwie do czynników (mogą być zmuszone do 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

Innym rozwiązaniem stosując definicję bgoldst dotyczącą df1 i df2

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

Daje

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

(Niekoniecznie format, który chciał, ale może to ok ...)

+1

Zapomniałem wspomnieć, że moje rozwiązanie zakłada, że ​​ustawiłeś 'opcje (stringAsFactors = FALSE)'. – cryo111

6

aggregate Inną odmianą, aby uniknąć interfejs wzoru, który faktycznie utrudnienie w tym przypadku:

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