我有一个类似于这个问题的问题 - Fast minimum distance (interval) between elements of 2 logical vectors (take 2)但它有一些重要的区别。
说我有一个矢量:
x <- c("A", "B", "C", "A", "D", "D", "A", "B", "A")
我想做的是:
对于每个元素,仅计算它与前向方向上每个不同类型的下一个元素之间的最小距离。如果对于任何元素,在正向方向上不发生特定类型的元素,则应返回0。返回的数据如下所示:
所需的输出表 -
N x A B C D
1 A 3 1 2 4
2 B 2 6 1 3
3 C 1 5 0 2
4 A 3 4 0 1
5 D 2 3 0 1
6 D 1 2 0 0
7 A 2 1 0 0
8 B 1 0 0 0
9 A 0 0 0 0
第一列/ var只是指元素顺序。第二个col / var是该位置的元素。然后有四个cols / vars - 每个cols / vars都是在向量中出现的唯一元素。
这四个cols / vars中的每一个中的数字是从该行的元素到FORWARD方向上每个类型的下一个出现元素的最小距离。如果输入“0”,则表示该元素不会出现在向量中该行的元素之后。
如何实现这一目标?
我的第一个想法是尝试模仿上述问题的某些方面。为此,我使用grepl函数将向量转换为四个单独的逻辑向量,指示每个元素的存在/不存在。
xA<-grepl("A", x) # TRUE FALSE FALSE TRUE FALSE FALSE TRUE FALSE TRUE
xB<-grepl("B", x) # FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
xC<-grepl("B", x) # FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
xD<-grepl("D", x) # FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE
然后我尝试了“Flodel”功能和GG使用库(data.table)提供的第二个功能。
例如,要计算从“As”到“D”的最小距离:
flodel <- function(x, y) {
xw <- which(x)
yw <- which(y)
i <- findInterval(xw, yw, all.inside = TRUE)
pmin(abs(xw - yw[i]), abs(xw - yw[i+1L]), na.rm = TRUE)
}
flodel(xA,xD)
> [1] 4 1 1 3
#GG's data.table option
wxA <- data.table(x = which(xA))
wxD <- data.table(y = which(xD), key = "y")
wxD[wxA, abs(x - y), roll = "nearest"]
# y V1
#1: 1 4
#2: 4 1
#3: 7 1
#4: 9 3
这两个选项都找到了所有A到D的最小距离。但是,它是在任何方向,而不是FORWARD方向。表面上GG的data.table选项对我来说更具吸引力,因为它返回显示每个元素位置的数据(输出的“y”列),这样可以很容易地打包成一个很好的汇总表(比如我想要的)上面的输出表。)
我试图找出在data.table中使用'roll'参数的替代方法,但我似乎没有解决这个问题。
感谢您的任何建议。
答案 0 :(得分:4)
另一种似乎有效的方式:
levs = sort(unique(x))
do.call(rbind,
lapply(seq_along(x),
function(n)
match(levs, x[-seq_len(n)], 0)))
# [,1] [,2] [,3] [,4]
# [1,] 3 1 2 4
# [2,] 2 6 1 3
# [3,] 1 5 0 2
# [4,] 3 4 0 1
# [5,] 2 3 0 1
# [6,] 1 2 0 0
# [7,] 2 1 0 0
# [8,] 1 0 0 0
# [9,] 0 0 0 0
答案 1 :(得分:0)
我不确定这是多么有效,但似乎有效。 <怎么样
x <- c("A", "B", "C", "A", "D", "D", "A", "B", "A")
#find indexes for each value
locations<-split(seq_along(x), x)
#for each index, find the distance from the next highest
# index in the locations list
t(sapply(seq_along(x), function(i) sapply(locations, function(l)
if(length(z<-l[l>i])>0) z[1]-i else 0)))
这将返回
A B C D
[1,] 3 1 2 4
[2,] 2 6 1 3
[3,] 1 5 0 2
[4,] 3 4 0 1
[5,] 2 3 0 1
[6,] 1 2 0 0
[7,] 2 1 0 0
[8,] 1 0 0 0
[9,] 0 0 0 0