在 R 中为马尔可夫模型创建转换矩阵
creating a transitions matrix for markov Model in R
我需要有关马尔可夫链和数据预处理相关主题的帮助。
假设我有以下矩阵将个人与状态随时间联系起来:
ID Time1 Time2
1 14021 A A
2 15031 B A
3 16452 A C
我想获得这个矩阵的状态转移矩阵:
因此,需要的是
A B C
A 1 0 1
B 1 0 0
C 0 0 0
同样的事情,但现在由该状态的转换总数加权,即
A B C
A 0.5 0 0.5
B 1 0 0
C 0 0 0
(因为有两个转换从状态 A 离开)。我知道 markovchain 包有一个功能
如果一个人有一个序列,比如 AAABBAAABBCC,但如果数据像我一样设置,则不会这样做。
理想情况下,一个直接的过程会很好,但如果有某种方法可以将数据转换成一组也可以工作的序列。
有什么想法吗?
提前致谢
肯定有更好的方法。这是我在一个蹩脚的星期五下午用循环涂鸦。
lvls <- sort(unique(unlist(df[,-1])))
dat <- matrix(0, nrow= length(lvls), ncol= length(lvls))
colnames(dat) <- lvls
rownames(dat) <- lvls
concat <- paste0(df[,2], df[,3])
for (i in 1:length(lvls)) {
for (j in 1:length(lvls)) {
dat[i,j] <- paste0(rownames(dat)[i], colnames(dat)[j])
}
}
dat <- matrix(sapply(dat, function(x) length(grep(x, concat))),
nrow= length(lvls), ncol= length(lvls))
colnames(dat) <- lvls
rownames(dat) <- lvls
dat
## A B C
## A 1 0 1
## B 1 0 0
## C 0 0 0
dat <- dat / rowSums(dat)
dat[is.na(dat)] <- 0
dat
## A B C
##A 0.5 0 0.5
##B 1.0 0 0.0
##C 0.0 0 0.0
这是另一个base R
解决方案。
df <- data.frame(Time1 = c("A","B","A"), Time2 = c("A","A","C"), stringsAsFactors = FALSE)
myStates <- sort(unique(c(df$Time1, df$Time2)))
lenSt <- length(myStates)
currState <- match(df$Time1, myStates)
nextState <- match(df$Time2, myStates)
transMat <- matrix(0L, lenSt, lenSt)
transMat[cbind(currState, nextState)] <- 1L
transMat <- transMat/rowSums(transMat)
transMat[is.na(transMat)] <- 0
transMat
[,1] [,2] [,3]
[1,] 0.5 0 0.5
[2,] 1.0 0 0.0
[3,] 0.0 0 0.0
igraph
方法,因此使用 df
来自 Joseph 的回答:
library(igraph)
g <- graph_from_data_frame(df)
E(g)$weight = 1/degree(g, mode="out")[df$Time1] # get counts
as_adj(g, attr = "weight", sparse=FALSE) # output weighted adjacency matrix
A B C
A 0.5 0 0.5
B 1.0 0 0.0
C 0.0 0 0.0
我需要有关马尔可夫链和数据预处理相关主题的帮助。 假设我有以下矩阵将个人与状态随时间联系起来:
ID Time1 Time2
1 14021 A A
2 15031 B A
3 16452 A C
我想获得这个矩阵的状态转移矩阵: 因此,需要的是
A B C
A 1 0 1
B 1 0 0
C 0 0 0
同样的事情,但现在由该状态的转换总数加权,即
A B C
A 0.5 0 0.5
B 1 0 0
C 0 0 0
(因为有两个转换从状态 A 离开)。我知道 markovchain 包有一个功能 如果一个人有一个序列,比如 AAABBAAABBCC,但如果数据像我一样设置,则不会这样做。 理想情况下,一个直接的过程会很好,但如果有某种方法可以将数据转换成一组也可以工作的序列。
有什么想法吗?
提前致谢
肯定有更好的方法。这是我在一个蹩脚的星期五下午用循环涂鸦。
lvls <- sort(unique(unlist(df[,-1])))
dat <- matrix(0, nrow= length(lvls), ncol= length(lvls))
colnames(dat) <- lvls
rownames(dat) <- lvls
concat <- paste0(df[,2], df[,3])
for (i in 1:length(lvls)) {
for (j in 1:length(lvls)) {
dat[i,j] <- paste0(rownames(dat)[i], colnames(dat)[j])
}
}
dat <- matrix(sapply(dat, function(x) length(grep(x, concat))),
nrow= length(lvls), ncol= length(lvls))
colnames(dat) <- lvls
rownames(dat) <- lvls
dat
## A B C
## A 1 0 1
## B 1 0 0
## C 0 0 0
dat <- dat / rowSums(dat)
dat[is.na(dat)] <- 0
dat
## A B C
##A 0.5 0 0.5
##B 1.0 0 0.0
##C 0.0 0 0.0
这是另一个base R
解决方案。
df <- data.frame(Time1 = c("A","B","A"), Time2 = c("A","A","C"), stringsAsFactors = FALSE)
myStates <- sort(unique(c(df$Time1, df$Time2)))
lenSt <- length(myStates)
currState <- match(df$Time1, myStates)
nextState <- match(df$Time2, myStates)
transMat <- matrix(0L, lenSt, lenSt)
transMat[cbind(currState, nextState)] <- 1L
transMat <- transMat/rowSums(transMat)
transMat[is.na(transMat)] <- 0
transMat
[,1] [,2] [,3]
[1,] 0.5 0 0.5
[2,] 1.0 0 0.0
[3,] 0.0 0 0.0
igraph
方法,因此使用 df
来自 Joseph 的回答:
library(igraph)
g <- graph_from_data_frame(df)
E(g)$weight = 1/degree(g, mode="out")[df$Time1] # get counts
as_adj(g, attr = "weight", sparse=FALSE) # output weighted adjacency matrix
A B C
A 0.5 0 0.5
B 1.0 0 0.0
C 0.0 0 0.0