Визуализация результатов от нескольких скрытых моделей классов


9

Я использую скрытый анализ классов для кластеризации выборки наблюдений на основе набора двоичных переменных. Я использую R и пакет poLCA. В LCA необходимо указать количество кластеров, которые вы хотите найти. На практике люди обычно запускают несколько моделей, каждая из которых задает разное количество классов, а затем используют различные критерии, чтобы определить, какое «лучшее» объяснение данных.

Я часто нахожу очень полезным просматривать различные модели, чтобы попытаться понять, как наблюдения, классифицированные в модели с классом = (i), распределяются моделью с классом = (i + 1). По крайней мере, иногда вы можете найти очень надежные кластеры, которые существуют независимо от количества классов в модели.

Я хотел бы, чтобы график этих отношений, чтобы легче сообщать эти сложные результаты в документах и ​​коллегам, которые не ориентированы на статистику. Я полагаю, что это очень легко сделать в R, используя какой-то простой сетевой графический пакет, но я просто не знаю как.

Может ли кто-нибудь, пожалуйста, указать мне в правильном направлении. Ниже приведен код для воспроизведения примера набора данных. Каждый вектор xi представляет классификацию 100 наблюдений в модели с i возможными классами. Я хочу изобразить, как наблюдения (строки) перемещаются из класса в класс по столбцам.

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)

Я предполагаю, что есть способ создать график, где узлы являются классификациями, а ребра отражают (по весам или, возможно, по цвету)% наблюдений, переходящих из классификаций от одной модели к другой. Например

введите описание изображения здесь

ОБНОВЛЕНИЕ: Имея некоторый прогресс с пакетом igraph. Начиная с кода выше ...

Результаты poLCA перезаписывают одни и те же числа, чтобы описать членство в классе, поэтому вам нужно немного перекодировать.

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

Затем вам нужно получить все перекрестные таблицы и их частоты и объединить их в одну матрицу, определяющую все ребра. Вероятно, есть гораздо более элегантный способ сделать это.

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)

введите описание изображения здесь

Думаю, пора больше играть с опциями igraph.


1
Если вы найдете решение, которое вас устраивает, вы также можете опубликовать свой код в качестве ответа
Gala

2
Это превращается в нечто вроде парсета . Смотрите ggparallel для реализации R.
Энди В.

1
Пока я не заметил комментарий @ Энди, я думал о чем-то вроде кластерной диаграммы (с идентификаторами субъектов против № кластеров) или, возможно, потоковой диаграммы (возможно, менее привлекательной, если у вас мало кластеров). Это, конечно, предполагает, что вы готовы работать на индивидуальном уровне.
ЧЛ

Ответы:


3

Пока что, благодаря вашим предложениям, я нашел лучшие варианты:

  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)

Сделано с игрой

С Играфом

Сделано с ggparallel

С ggparallel

Все еще слишком грубо, чтобы делиться этим в журнале, но я определенно обнаружил, что быстрый взгляд на них очень полезен.

В этом вопросе также есть вариант переполнения стека , но у меня еще не было возможности его реализовать; и еще одна возможность здесь .


1
Спасибо за размещение примеров. Этот пост в CV показывает некоторый более хороший код для графиков ParSets в R (извините, я должен был сначала указать на это). Мой набег в пакете ggparallel показывает, что пока он довольно грубый (хотя случайные данные, как вы показываете, не будут выглядеть хорошо IMO для ParSets).
Энди W
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.