2016-12-19 2 views
5

Ich habe eine Matrix wie dieseMerge Spalten einer Datenrahmen durch zwei Bedingungen mit Aggregat

P A B C 
    1 2 0 5 
    2 1 1 3 
    3 0 4 7 
    1 1 1 0 
    3 1 1 0 
    3 0 2 1 
    2 3 3 4 

I/sortieren die Zeilen von P zusammenführen möchten und durch jede der Säulen. So ist jeder P-Wert für jede Spalte einmal und der Wert für jedes P in jeder Spalte ist aufsummiert. Das Ergebnis sollte sein:

P A B C 
1 3 0 0 
1 0 1 0 
1 0 0 5 
2 4 0 0 
2 0 4 0 
2 0 0 7 
3 1 0 0 
3 0 7 0 
3 0 0 8 

Ich habe bereits versucht aggregate aber es hilft nur mir jeden P-Wert für alle Spalten zu summieren, so dass ich für jede P. nur eine Zeile haben

+0

weil jede p Zeile für jede Spalte angezeigt. – Miguel123

+0

es ist so etwas wie Mischung von Merge und Split – Miguel123

Antwort

3

Eine weitere Idee ist diag Funktion zu nutzen, um sich um eine Matrix zu erstellen. Dann können Sie diese Matrizen zusammenfügen.

xx=aggregate(. ~ P, df, sum) 
yy=xx[,-1] 
yy=as.data.frame(t(yy)) 
cbind(rep(1:ncol(yy),nrow(yy)),do.call("rbind", lapply(yy, function(xx) diag(xx, nrow = nrow(yy), ncol = nrow(yy))))) 

     [,1] [,2] [,3] [,4] 
[1,] 1 3 0 0 
[2,] 2 0 1 0 
[3,] 3 0 0 5 
[4,] 1 4 0 0 
[5,] 2 0 4 0 
[6,] 3 0 0 7 
[7,] 1 1 0 0 
[8,] 2 0 7 0 
[9,] 3 0 0 8 
+0

Sie möchten vielleicht ein wenig verallgemeinern, um mehr Spalten zu berücksichtigen (d. H. A, B, C, D, E ...) – Sotos

+0

ja, meine ursprüngliche Matrix ist 95x20 – Miguel123

+0

Dies sollte für jede Dimension funktionieren. –

3

Wir haben den Maximalwert erhalten der Häufigkeitszählung von 'P' Spalte ('i1'), aggregate die Spalten gruppiert von 'P', um die sum ('df2'), replizieren die Zeilen von 'df2' durch die 'i1', split der Datensatz von ' P 'und ändere die nichtdiagonalen Elemente in anderen Spalten auf 0 und gebe sie als data.frame, order zurück und ändere die Zeilennamen in NULL.

i1 <- max(table(df1$P)) 
df2 <- aggregate(.~P, df1, sum) 
df3 <- df2[rep(1:nrow(df2), i1)] 
res <- unsplit(lapply(split(df3, df3$P), function(x) { 
     x[-1] <- diag(3)*x[-1] 
     x}), df3$P) 
res1 <- res[order(res$P),] 
row.names(res1) <- NULL 
res1 
# P A B C 
#1 1 3 0 0 
#2 1 0 1 0 
#3 1 0 0 5 
#4 2 4 0 0 
#5 2 0 4 0 
#6 2 0 0 7 
#7 3 1 0 0 
#8 3 0 7 0 
#9 3 0 0 8 

Oder data.table verwenden, wandeln die 'data.frame' auf 'data.table' (setDT(df1)), Schleife durch die Subset von Data.table (.SD), erhalten die sum, gruppiert nach ' P 'replizieren die Zeilen des zusammengefassten Datensatzes und ändern die nichtdiagonalen Elemente in 0 (wie in der ersten Lösung besprochen).

library(data.table) 
setDT(df1)[, lapply(.SD, sum), by = P 
      ][rep(1:.N, i1) 
      ][, .SD*diag(ncol(df1)-1), by = P] 
# P A B C 
#1: 1 3 0 0 
#2: 1 0 1 0 
#3: 1 0 0 5 
#4: 2 4 0 0 
#5: 2 0 4 0 
#6: 2 0 0 7 
#7: 3 1 0 0 
#8: 3 0 7 0 
#9: 3 0 0 8 

Oder mit dplyr

library(dplyr) 
library(purrr) 
d1 <- as.data.frame(diag(i1)) 
df2 <- df1 %>% 
      group_by(P) %>% 
      summarise_each(funs(sum)) %>% 
      replicate(i1, ., simplify = FALSE) %>% 
      bind_rows() %>% 
      arrange(P) 
df2[-1] <- map2(df2[-1], d1, ~.x * .y) 
df2 
# A tibble: 9 × 4 
#  P  A  B  C 
# <int> <dbl> <dbl> <dbl> 
#1  1  3  0  0 
#2  1  0  1  0 
#3  1  0  0  5 
#4  2  4  0  0 
#5  2  0  4  0 
#6  2  0  0  7 
#7  3  1  0  0 
#8  3  0  7  0 
#9  3  0  0  8 
+1

irgendwie ist Ihre zweite Lösung die einzige, die funktioniert! Vielen Dank - ich war so auf die Verwendung von Aggregat – Miguel123

+0

gut ... sorry, ich habe gerade herausgefunden, dass es mit meinen riesigen Daten nicht funktioniert. hmm – Miguel123

4

Eine Idee ist, Datenrahmen auf P aufzuspalten und eine benutzerdefinierte Funktion (fun1) gelten, die eine Matrix mit 0 erzeugt und ersetzt die Diagonale mit der Summe der Spalten. das heißt

fun1 <- function(x){ 
m1 <- matrix(0, ncol = ncol(x) - 1, nrow = ncol(x) - 1) 
diag(m1) <- sapply(x[-1], sum) 
return(m1) 
     } 

l1 <- split(df, df$P) 
do.call(rbind, lapply(l1, fun1)) 

#  [,1] [,2] [,3] 
# [1,] 3 0 0 
# [2,] 0 1 0 
# [3,] 0 0 5 
# [4,] 4 0 0 
# [5,] 0 4 0 
# [6,] 0 0 7 
# [7,] 1 0 0 
# [8,] 0 7 0 
# [9,] 0 0 8 

Oder es auf die gewünschte Ausgabe zu erhalten, dann

final_df <- as.data.frame(cbind(rep(names(l1), each = ncol(df)-1), 
              do.call(rbind, lapply(l1, fun1)))) 
names(final_df) <- names(df) 

final_df 
# P A B C 
#1 1 3 0 0 
#2 1 0 1 0 
#3 1 0 0 5 
#4 2 4 0 0 
#5 2 0 4 0 
#6 2 0 0 7 
#7 3 1 0 0 
#8 3 0 7 0 
#9 3 0 0 8 
+0

das ist eine nette Idee aber irgendwie kann ich die Funktion nicht erzeugen ... – Miguel123

+0

Nochmal versuchen ... die Funktion – Sotos

+0

bearbeiten hmm da scheint irgendwas mit der Länge der Diagonalen nicht zu stimmen – Miguel123

1

Wenn ich etwas nicht vermisse, sieht das folgende auch gültig aus. Start durch die Summen der Berechnung pro "P":

s = as.matrix(rowsum(dat[-1], dat$P)) 

die endgültige Matrix erstellen:

k = s[rep(1:nrow(s), each = ncol(s)), ] 

Compute-Indizes mit "0" zu ersetzen:

k[col(k) != (row(k) - 1) %% ncol(k) + 1] = 0 
k 
# A B C 
#1 3 0 0 
#1 0 1 0 
#1 0 0 5 
#2 4 0 0 
#2 0 4 0 
#2 0 0 7 
#3 1 0 0 
#3 0 7 0 
#3 0 0 8 

Daten:

dat = structure(list(P = c(1L, 2L, 3L, 1L, 3L, 3L, 2L), A = c(2L, 1L, 
0L, 1L, 1L, 0L, 3L), B = c(0L, 1L, 4L, 1L, 1L, 2L, 3L), C = c(5L, 
3L, 7L, 0L, 0L, 1L, 4L)), .Names = c("P", "A", "B", "C"), class = "data.frame", row.names = c(NA, 
-7L)) 

Hav ing berechnet s, user20650 ‚s einfache Alternative:

matrix(diag(ncol(s)), nrow(s) * ncol(s), ncol(s), byrow = TRUE) * c(t(s)) 

oder auch mit anderen interessanten Alternativen auf der gleiche Idee Messing:

kronecker(rep_len(1, nrow(s)), diag(ncol(s))) * c(t(s)) 

diag(ncol(s))[rep(1:ncol(s), nrow(s)), ] * s[rep(1:nrow(s), each = ncol(s)), ] 
+0

sehr schön. (Ive nur hartcodierte Nr. ist hier), aber vielleicht ein kleines aber klarer ??? 't (Matrix (diag (3), nrow = 3, ncol = 9)) * c (t (s))' – user20650

+0

@ user20650: recycling 'diag()' ist in der Tat hier praktisch - habe nicht gedacht davon. Ich werde mein Recycling ernst nehmen müssen ...... die Parametrisierung scheint jetzt korrekt zu sein –

+0

netter Alexis, deine Kronecker-Methode ist ziemlich raffiniert. Ich denke, dass diese Matrixtransformationen der beste Weg sind, dieses Problem anzugehen ... immer noch ... – user20650

Verwandte Themen