От кадра данных к массиву вершин / ребер
У меня есть датафрейм
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,]