От кадра данных к массиву вершин / ребер

У меня есть датафрейм

test <- structure(list(
     y2002 = c("freshman","freshman","freshman","sophomore","sophomore","senior"),
     y2003 = c("freshman","junior","junior","sophomore","sophomore","senior"),
     y2004 = c("junior","sophomore","sophomore","senior","senior",NA),
     y2005 = c("senior","senior","senior",NA, NA, NA)), 
              .Names = c("2002","2003","2004","2005"),
              row.names = c(c(1:6)),
              class = "data.frame")
> test
       2002      2003      2004   2005
1  freshman  freshman    junior senior
2  freshman    junior sophomore senior
3  freshman    junior sophomore senior
4 sophomore sophomore    senior   <NA>
5 sophomore sophomore    senior   <NA>
6    senior    senior      <NA>   <NA>

и мне нужно создать список вершин / ребер (для использования с igraph) с каждым разом, когда категория ученика меняется в последовательные годы, игнорируя, когда нет изменений, как в

testvertices <- structure(list(
 vertex = 
  c("freshman","junior", "freshman","junior","sophomore","freshman",
    "junior","sophomore","sophomore","sophomore"),
 edge = 
  c("junior","senior","junior","sophomore","senior","junior",
    "sophomore","senior","senior","senior"),
 id =
  c("1","1","2","2","2","3","3","3","4","5")),
                       .Names = c("vertex","edge", "id"),
                       row.names = c(1:10),
                       class = "data.frame")
> testvertices
      vertex      edge id
1   freshman    junior  1
2     junior    senior  1
3   freshman    junior  2
4     junior sophomore  2
5  sophomore    senior  2
6   freshman    junior  3
7     junior sophomore  3
8  sophomore    senior  3
9  sophomore    senior  4
10 sophomore    senior  5

На данный момент я игнорирую идентификаторы, мой график должен взвешивать края по счету (то есть, первокурсник -> младший =3). Идея состоит в том, чтобы сделать граф дерева. Я знаю, что это недалеко от главной точки, но если вы спросите...

2 ответа

Решение

Если я вас правильно понимаю, вам нужно что-то вроде этого:

elist <- lapply(seq_len(nrow(test)), function(i) {
  x <- as.character(test[i,])
  x <- unique(na.omit(x))
  x <- rep(x, each=2)
  x <- x[-1]
  x <- x[-length(x)]
  r <- matrix(x, ncol=2, byrow=TRUE)
  if (nrow(r) > 0) { r <- cbind(r, i) } else { r <- cbind(r, numeric()) }
  r
})

do.call(rbind, elist)

#                              i  
# [1,] "freshman"  "junior"    "1"
# [2,] "junior"    "senior"    "1"
# [3,] "freshman"  "junior"    "2"
# [4,] "junior"    "sophomore" "2"
# [5,] "sophomore" "senior"    "2"
# [6,] "freshman"  "junior"    "3"
# [7,] "junior"    "sophomore" "3"
# [8,] "sophomore" "senior"    "3"
# [9,] "sophomore" "senior"    "4"
#[10,] "sophomore" "senior"    "5"

Это не самое эффективное решение, но я думаю, что оно довольно дидактическое. Мы создаем ребра отдельно для каждой строки вашей входной матрицы, поэтому lapply, Чтобы создать ребра из строки, мы сначала удаляем NA и дубликаты, а затем включаем каждую вершину дважды. Наконец, мы удаляем первую и последнюю вершину. Таким образом, мы создали матрицу списка ребер, нам нужно всего лишь удалить первую и последнюю вершину и отформатировать ее в два столбца (на самом деле было бы эффективнее оставить ее как вектор, не говоря уже о).

При добавлении дополнительного столбца, мы должны быть осторожны, чтобы проверить, имеет ли матрица списка ребер нулевые строки.

do.call Функция просто склеит все вместе. В результате получается матрица, которую вы можете преобразовать во фрейм данных, если хотите, через as.data.frame(), а затем вы также можете преобразовать третий столбец в числовой. Вы также можете изменить имена столбцов, если хотите.

Это дау, что вы хотите, хорошо...

test1<-c(test[[2]],test[[3]],test[[4]])
test2<-c(test[[3]],test[[4]],test[[5]])
df<-data.frame(vertex=test1,edge=test2)
df1<-df[complete.cases(df),]
result<-df1[df1$vertex != df1$edge,]
Другие вопросы по тегам