Visualisierung der Ergebnisse mehrerer latenter Klassenmodelle

9

Ich verwende die Analyse latenter Klassen, um eine Stichprobe von Beobachtungen basierend auf einer Reihe von binären Variablen zu gruppieren. Ich benutze R und das Paket poLCA. In der Ökobilanz müssen Sie die Anzahl der Cluster angeben, die Sie suchen möchten. In der Praxis führen Benutzer normalerweise mehrere Modelle aus, die jeweils eine unterschiedliche Anzahl von Klassen angeben, und verwenden dann verschiedene Kriterien, um zu bestimmen, welche die "beste" Erklärung für die Daten ist.

Ich finde es oft sehr nützlich, die verschiedenen Modelle zu betrachten, um zu verstehen, wie Beobachtungen, die in ein Modell mit Klasse = (i) klassifiziert sind, durch das Modell mit Klasse = (i + 1) verteilt werden. Zumindest finden Sie manchmal sehr robuste Cluster, die unabhängig von der Anzahl der Klassen im Modell existieren.

Ich möchte einen Weg finden, diese Beziehungen grafisch darzustellen, diese komplexen Ergebnisse leichter in Papieren und Kollegen zu kommunizieren, die nicht statistisch orientiert sind. Ich stelle mir vor, dass dies in R mit einem einfachen Netzwerkgrafikpaket sehr einfach ist, aber ich weiß einfach nicht wie.

Könnte jemand mich bitte in die richtige Richtung weisen. Unten finden Sie Code zum Reproduzieren eines Beispieldatensatzes. Jeder Vektor xi repräsentiert die Klassifizierung von 100 Beobachtungen in einem Modell mit i möglichen Klassen. Ich möchte grafisch darstellen, wie sich Beobachtungen (Zeilen) über die Spalten von Klasse zu Klasse bewegen.

x1 <- sample(1:1, 100, replace=T)
x2 <- sample(1:2, 100, replace=T)
x3 <- sample(1:3, 100, replace=T)
x4 <- sample(1:4, 100, replace=T)
x5 <- sample(1:5, 100, replace=T)

results <- cbind (x1, x2, x3, x4, x5)

Ich stelle mir vor, es gibt eine Möglichkeit, ein Diagramm zu erstellen, bei dem die Knoten Klassifikationen sind und die Kanten (nach Gewicht oder Farbe) den Prozentsatz der Beobachtungen widerspiegeln, die von Klassifikationen von einem Modell zum nächsten wechseln. Z.B

Geben Sie hier die Bildbeschreibung ein

UPDATE: Einige Fortschritte mit dem igraph-Paket. Ausgehend vom obigen Code ...

Die Ergebnisse von poLCA recyceln dieselben Zahlen, um die Klassenzugehörigkeit zu beschreiben. Sie müssen also ein wenig neu codieren.

N<-ncol(results) 
n<-0
for(i in 2:N) {
results[,i]<- (results[,i])+((i-1)+n)
n<-((i-1)+n)
}

Dann müssen Sie alle Kreuztabellen und ihre Häufigkeiten abrufen und sie in eine Matrix einbinden, die alle Kanten definiert. Es gibt wahrscheinlich einen viel eleganteren Weg, dies zu tun.

results <-as.data.frame(results)

g1           <- count(results,c("x1", "x2"))

g2           <- count(results,c("x2", "x3"))
colnames(g2) <- c("x1", "x2", "freq")

g3           <- count(results,c("x3", "x4"))
colnames(g3) <- c("x1", "x2", "freq")

g4           <- count(results,c("x4", "x5"))
colnames(g4) <- c("x1", "x2", "freq")

results <- rbind(g1, g2, g3, g4)

library(igraph)

g1 <- graph.data.frame(results, directed=TRUE)

plot.igraph(g1, layout=layout.reingold.tilford)

Geben Sie hier die Bildbeschreibung ein

Zeit, mehr mit den igraph-Optionen zu spielen, denke ich.

DL Dahly
quelle
1
Wenn Sie eine Lösung finden, die Sie zufriedenstellt, können Sie Ihren Code auch als Antwort veröffentlichen
Gala
2
Dies wird zu so etwas wie Parsets . Siehe ggparallel für eine R-Implementierung.
Andy W
1
Bis ich @ Andys Kommentar bemerkte, dachte ich an etwas wie ein Clustergramm (mit der ID der Probanden im Vergleich zu den Clustern) oder vielleicht an einen Streamgraph (wahrscheinlich weniger ansprechend, wenn Sie nur wenige Cluster haben). Dies setzt natürlich voraus, dass Sie bereit sind, auf individueller Ebene zu arbeiten.
Chl

Antworten:

3

Bisher sind die besten Optionen, die ich dank Ihrer Vorschläge gefunden habe, folgende:

  library (igraph)
  library (ggparallel)

# Generate random data

  x1 <- sample(1:1, 1000, replace=T)
  x2 <- sample(2:3, 1000, replace=T)
  x3 <- sample(4:6, 1000, replace=T)
  x4 <- sample(7:10, 1000, replace=T)
  x5 <- sample(11:15, 1000, replace=T)
  results <- cbind (x1, x2, x3, x4, x5)
  results <-as.data.frame(results)

# Make a data frame for the edges and counts

  g1           <- count (results, c("x1", "x2"))

  g2           <- count (results, c("x2", "x3"))
  colnames(g2) <- c     ("x1", "x2", "freq")

  g3           <- count (results, c("x3", "x4"))
  colnames(g3) <- c     ("x1", "x2", "freq")

  g4           <- count (results, c("x4", "x5"))
  colnames(g4) <- c     ("x1", "x2", "freq")

  edges        <- rbind (g1, g2, g3, g4)

# Make a data frame for the class sizes

  h1            <- count (results, c("x1"))

  h2            <- count (results, c("x2"))
  colnames (h2) <- c     ("x1", "freq")

  h3            <- count (results, c("x3"))
  colnames (h3) <- c     ("x1", "freq")

  h4            <- count (results, c("x4"))
  colnames (h4) <- c     ("x1", "freq")

  h5            <- count (results, c("x5"))
  colnames (h5) <- c     ("x1", "freq")

  cSizes        <- rbind (h1, h2, h3, h4, h5)

# Graph with igraph

  gph    <- graph.data.frame (edges, directed=TRUE)

  layout <- layout.reingold.tilford (gph, root = 1)
  plot (gph,
        layout           = layout,
        edge.label       = edges$freq, 
        edge.curved      = FALSE,
        edge.label.cex   = .8,
        edge.label.color = "black",
        edge.color       = "grey",
        edge.arrow.mode  = 0,
        vertex.label     = cSizes$x1 , 
        vertex.shape     = "square",
        vertex.size      = cSizes$freq/20)

# The same idea, using ggparallel

  a <- c("x1", "x2", "x3", "x4", "x5")

  ggparallel (list (a), 
              data        = results, 
              method      = "hammock", 
              asp         = .7, 
              alpha       = .5, 
              width       = .5, 
              text.angle = 0)

Fertig mit igraph

Mit Igraph

Fertig mit ggparallel

Mit ggparallel

Immer noch zu grob, um es in einem Tagebuch zu veröffentlichen, aber ich fand es auf jeden Fall sehr nützlich, einen kurzen Blick darauf zu werfen.

Es gibt auch eine mögliche Option aus dieser Frage zum Stapelüberlauf , aber ich hatte noch keine Chance, sie zu implementieren. und eine andere Möglichkeit hier .

DL Dahly
quelle
1
Vielen Dank für die Veröffentlichung der Beispiele. Dieser Beitrag im Lebenslauf zeigt einen schöneren Code für die ParSets-Diagramme in R ( leider hätte ich zuerst darauf hinweisen müssen). Mein Streifzug durch das ggparallel-Paket deutet darauf hin, dass es bisher ziemlich rau an den Rändern ist (obwohl zufällige Daten, wie Sie sie zeigen, IMO für ParSets nicht gut aussehen).
Andy W