2017-12-29 15 views
3

Entschuldigung für den schlechten Titel, aber ich wusste wirklich nicht, wie ich es kurz und bündig formulieren soll.Datenrahmen auf eine bestimmte Art anordnen

Ich habe ein Datenrahmen Ich spiele um mit denen ein Element in einem der 4 Kategorien sein kann, nicht beschränkt auf 1. Hier ist ein Beispiel für die Dummy-Matrix mit arbeite ich:

ID <- 1:7 
A <- c(1,0,0,1,1,0,0) 
B <- c(0,1,0,0,1,0,1) 
C <- c(0,0,0,0,0,1,1) 
D <- c(1,0,1,1,0,0,0) 
A_B <- (A+B > 0)*1 
C_D <- (C+D > 0)*1 
Cost <- c(25, 52, 11, 75, 45, 5, 34) 

df <- data.frame(ID, A, B, C, D, A_B, C_D, A_B_C_D = 1, Cost) 
df 

ID A B C D A_B C_D A_B_C_D Cost 
1 1 0 0 1 1 1  1  25 
2 0 1 0 0 1 0  1  52 
3 0 0 0 1 0 1  1  11 
4 1 0 0 1 1 1  1  75 
5 1 1 0 0 1 0  1  45 
6 0 0 1 0 0 1  1  5 
7 0 1 1 0 1 1  1  34 

Ich muss für diesen Datenrahmen so organisiert werden, dass Zeile 1 ein A, Zeile 2 a B, Zeile 3 a C, Zeile 4 a D, Zeile 5 ein A oder B, Zeile 6 a C oder D und Zeile 7 enthält ist übrig geblieben. Ich kann arrange nicht, da würde mit desc(A) beginnend verwenden, um automatisch 1, 4, 5. Eine akzeptable Lösung für dieses Problem wäre:

Order <- c(4, 2, 7, 1, 5, 3, 6) 
df[Order,] 
df 

ID A B C D A_B C_D A_B_C_D Cost 
4 1 0 0 1 1 1  1 75 
2 0 1 0 0 1 0  1 52 
7 0 1 1 0 1 1  1 34 
1 1 0 0 1 1 1  1 25 
5 1 1 0 0 1 0  1 45 
3 0 0 0 1 0 1  1 11 
6 0 0 1 0 0 1  1 5 

Wesentlichen die diagonalen Bedürfnisse 7 Gerade sein, aber ich kann‘ Ich denke darüber nach, wie man es richtig programmiert, unabhängig vom Datensatz. Ich denke, das sollte wirklich einfach sein, aber ich sehe es einfach nicht. Würde das Transponieren es einfacher machen?

Vielen Dank im Voraus.

+0

Was wird die Logik für mehr Anzahl der Zeilen sein? – akrun

+0

@akrun gibt es immer nur 7 Zeilen, nur mehrere Iterationen: Sie sind das Ergebnis einer 'lpsolve'-Optimierung. Die Optimierung funktioniert so, dass ich immer die "richtige" Bestellung machen kann, ich muss nur die Bestellung rationalisieren. Die korrekte Reihenfolge ist erforderlich, damit die endgültige Ausgabe funktioniert. Danke – CoolGuyHasChillDay

+0

Gibt es nur eine Lösung oder können es mehrere sein?Wenn Letzteres, interessierst du dich welches du bekommst? Möglicherweise müssen Sie einen Suchalgorithmus implementieren, der den Baum möglicher Anordnungen durchläuft, bis er einen gefunden hat, der funktioniert. –

Antwort

2

Ein Ansatz wäre rohe Gewalt zu verwenden, indem man alle Permutationen von Reihenanordnungen und Kontrolle bekommen, die die Diagonale Erwartung erfüllen:

z <- apply(permute::allPerms(1:7), 1, function(x){ 
    mat <- as.matrix(df[,2:8]) 
    if(all(diag(mat[x,]) == rep(1,7))){ 
    return(df[x,]) 
    } 
    }) 

dann können Sie nur die NULL-Werte entfernen:

z <- Filter(Negate(is.null), z) 

und nutzen Sie die alle 88 Lösungen

length(z) #88 

z[[5]] #random solution 
#output 

    ID A B C D A_B C_D A_B_C_D Cost 
1 1 1 0 0 1 1 1  1 25 
2 2 0 1 0 0 1 0  1 52 
6 6 0 0 1 0 0 1  1 5 
4 4 1 0 0 1 1 1  1 75 
5 5 1 1 0 0 1 0  1 45 
3 3 0 0 0 1 0 1  1 11 
7 7 0 1 1 0 1 1  1 34 

nur das WLAN erhalten rst Permutation passend kann man eine while-Schleife verwenden:

perms <- permute::allPerms(1:7) 
mat <- as.matrix(df[,2:8]) 
i <- 1 
while (!all(diag(mat[perms[i,],]) == rep(1,7))) { 
    i = i+1 
} 

df[perms[i,],] 

# ID A B C D A_B C_D A_B_C_D Cost 
1 1 1 0 0 1 1 1  1 25 
2 2 0 1 0 0 1 0  1 52 
6 6 0 0 1 0 0 1  1 5 
3 3 0 0 0 1 0 1  1 11 
4 4 1 0 0 1 1 1  1 75 
7 7 0 1 1 0 1 1  1 34 
5 5 1 1 0 0 1 0  1 45 

lässt die Geschwindigkeit überprüfen:

test <- function(df){ 
    z <- apply(permute::allPerms(1:7), 1, function(x){ 
    mat <- as.matrix(df[,2:8]) 
    if(all(diag(mat[x,]) == rep(1,7))){ 
     return(df[x,]) 
    } 
    }) 
    z <- Filter(Negate(is.null), z) 
    return(z) 
} 

test2 <- function(df){ 
    perms <- permute::allPerms(1:7) 
    mat <- as.matrix(df[,2:8]) 
    i <- 1 
    while (!all(diag(mat[perms[i,],]) == rep(1,7))) { 
    i = i+1 
    } 
    df[perms[i,],] 
} 
microbenchmark::microbenchmark(b <- test(df), 
          c <- test2(df), times = 10L) 

    Unit: milliseconds 
      expr  min  lq  mean median  uq  max neval cld 
    b <- test(df) 392.68257 396.81450 412.41600 401.0613 408.15582 509.77693 10 b 
c <- test2(df) 46.11754 46.92276 47.80778 47.3977 48.82543 50.05795 10 a 

nicht so schlimm

+0

Das ist großartig, danke für die Hilfe. Nur so verstehe ich 'test2' auf einer höheren Ebene: Grundsätzlich ist es das, was du R zu tun gibst, so viele Reihen-Kombinationen wie möglich zu machen (wobei die spezifischen Anordnungen in' Dauerwellen' gespeichert sind). Dann sagst du R, das 'df' basierend auf den Spezifikationen in' permanent' zu reorganisieren. Sobald alle Diagonalen gleich 1 sind, stoppen Sie die Schleife und geben Sie 'df' in dieser Reihenfolge zurück. – CoolGuyHasChillDay

+0

schießen, meine tatsächlichen 'df' s haben eine weitere Spalte, so ist es eine 8: 8-Dummy-Matrix. 'permute :: allPerms' kann nicht mit 1: 8 umgehen (" Anzahl der möglichen Permutationen ist zu groß "). 'allPerms (1: 5)' hat 119 Zeilen, 'allPerms (1: 6)' hat 719 Zeilen und 'allPerms (1: 7)' hat 5039 Zeilen, also würde ich 'allPerms (1: 8)' vermuten um 38k Zeilen zu sein. Eine 38000x8-Matrix ist im Allgemeinen für R in Ordnung, also bin ich nicht sicher, warum es stecken bleibt. Weißt du, ob es einen Workaround gibt? Ich suche gerade in CRAN ... @missuse – CoolGuyHasChillDay

+0

Entschuldigung dafür, dass ich dich spammte, aber ich wollte dich wissen lassen, dass ich es herausgefunden habe, bevor du auf die Suche gingst. Hinzufügen von 'ctrl <- permute :: how (maxperm = 50000' dann' permute :: allPerms (1: 8, control = ctrl) 'hat den Trick gemacht. Nochmals vielen Dank! – CoolGuyHasChillDay

0

Aus den von Ihnen geposteten Daten ist keine eindeutige Lösung möglich, da die Zeilen 1 und 4 identische A-D-Spaltenfolgen haben. Ansonsten scheint es eine einfache Übung in der Verwendung von Vier-Bit-Booleschen Mustern gewesen zu sein. Ich verstehe nicht, warum Sie das Bitmuster 1001 wiederholen, es sei denn, dies ist ein Fehler beim Einrichten der Beispieldaten.

Um zu erklären, warum ich verwirrt bin, wenn die Zeilen 1 und 4 in der umgekehrten Bestellung vorschlug es Ihre Anforderung nicht ungültig macht, dass die Diagonale all 1s sein, aber es ist eindeutig nicht die gleiche Reihenfolge wie zuvor:

Order2 <- c(1, 2, 7, 4, 5, 3, 6) 
df[Order2,] 


    ID A B C D A_B C_D A_B_C_D Cost 
    1 1 0 0 1 1 1  1 25 
    2 0 1 0 0 1 0  1 52 
    7 0 1 1 0 1 1  1 34 
    4 1 0 0 1 1 1  1 75 
    5 1 1 0 0 1 0  1 45 
    3 0 0 0 1 0 1  1 11 
    6 0 0 1 0 0 1  1 5 

Eine nicht eindeutige Lösung kann mit AND- und OR-Kombinationen ermittelt werden, wenn Sie die Reihenfolge als solche nicht beachten - es ist eine Übung in der Verwendung von Wahrheitstabellen (oder in der Anwendung kombinatorischer Logik wie der Verwendung) von De Morgan's Theorem).

+0

Danke, dass du mir geholfen hast! Ich sagte, "eine akzeptable Antwort ist:" Aber ich hätte klarer sein sollen, dass es keine einzigartige Lösung gibt, solange die Diagonale mit 1 gefüllt ist, dann funktioniert es. Davon abgesehen werde ich einen Blick auf De Morgans Theorem werfen, danke für die Ressource. – CoolGuyHasChillDay

Verwandte Themen