距日期的时间距离矩阵

时间:2016-06-22 12:25:07

标签: r date datetime

来自一个非常简单的数据框,如

    time1 <- as.Date("2010/10/10")
    time2 <- as.Date("2010/10/11")
    time3 <- as.Date("2010/10/12")
    test <- data.frame(Sample=c("A","B", "C"), Date=c(time1, time2, time3))

如何获得样本A,B,C之间具有成对时间距离(样本之间的天数经过时间)的矩阵?

   A  B  C
A  0  1  2
B  1  0  1
C  2  1  0

/ edit:更改了日期的格式。抱歉给您带来不便

4 个答案:

答案 0 :(得分:4)

使用outer()

您无需使用数据框。在您的示例中,我们可以在单个向量中收集您的日期并使用outer()

x <- c(time1, time2, time3)
abs(outer(x, x, "-"))

     [,1] [,2] [,3]
[1,]    0    1    2
[2,]    1    0    1
[3,]    2    1    0

注意我在外面添加了abs(),这样你才能得到正时差,即时间差“今天 - 昨天”和“昨天 - 今天”都是1.

如果您的数据预先存储在数据框中,您可以将该列提取为矢量,然后继续。

使用dist()

正如Konrad所提到的,dist()经常用于计算距离矩阵。最大的好处是它只会计算下/上三角矩阵(对角线为0),而复制其余矩阵。另一方面,outer()强制计算所有矩阵元素,而不知道对称性。

然而,dist()采用数值向量,并且只计算某些距离类。见?dist

Arguments:

       x: a numeric matrix, data frame or ‘"dist"’ object.

  method: the distance measure to be used. This must be one of
          ‘"euclidean"’, ‘"maximum"’, ‘"manhattan"’, ‘"canberra"’,
          ‘"binary"’ or ‘"minkowski"’.  Any unambiguous substring can
          be given.

但我们实际上可以解决,使用它。

日期对象,如果你给它一个原点,可以强制成整数。由

x <- as.numeric(x - min(x))

我们获得自记录第一天起的天数。现在,我们可以使用dist()与默认Euclidean距离:

y <- as.matrix(dist(x, diag = TRUE, upper = TRUE))
rownames(y) <- colnames(y) <- c("A", "B", "C")

  A B C
A 0 1 2
B 1 0 1
C 2 1 0

为什么将outer()作为我的第一个例子

原则上,时差不是无符号的。在这种情况下,

outer(x, x, "-")

更合适。我之后添加了abs(),因为您似乎有意想要积极的结果。

此外,outer()的使用范围远远超过dist()。看看my answer here。 OP要求计算汉明距离,这实际上是一种按位距离。

答案 1 :(得分:4)

要获得实际天数计算,您可以将天数转换为自某个预定义日期以来的日期,然后使用dist。下面的例子(转换你的日子,我怀疑它们代表了你对它们的期望):

time1 <- as.Date("02/10/10","%m/%d/%y")
time2 <- as.Date("02/10/11","%m/%d/%y")
time3 <- as.Date("02/10/12","%m/%d/%y")
test <- data.frame(Sample=c("A","B", "C"), Date=c(time1, time2, time3))
days_s2010 <- difftime(test$Date,as.Date("01/01/10","%m/%d/%y"))
dist_days <- as.matrix(dist(days_s2010,diag=TRUE,upper=TRUE))
rownames(dist_days) <- test$Sample; colnames(dist_days) <- test$Sample

dist_days然后打印出来:

> dist_days
    A   B   C
A   0 365 730
B 365   0 365
C 730 365   0

实际上,dist无需将日期转换为自某段时间以来的日期,只需执行dist(test$Date)即可使用数天。

答案 2 :(得分:4)

分两步使用data.table方法的快速解决方案

# load library
 library(reshape)
 library(data.table)

# 1. Get all possible combinations of pairs of dates in long format
df <- expand.grid.df(test, test)
colnames(df) <- c("Sample", "Date", "Sample2", "Date2")

# 2. Calculate distances in days, weeks or hours, minutes etc
setDT(df)[, datedist := difftime(Date2, Date, units ="days")]

df
#>    Sample       Date Sample2      Date2 datedist
#> 1:      A 2010-10-10       A 2010-10-10   0 days
#> 2:      B 2010-10-11       A 2010-10-10  -1 days
#> 3:      C 2010-10-12       A 2010-10-10  -2 days
#> 4:      A 2010-10-10       B 2010-10-11   1 days
#> 5:      B 2010-10-11       B 2010-10-11   0 days
#> 6:      C 2010-10-12       B 2010-10-11  -1 days
#> 7:      A 2010-10-10       C 2010-10-12   2 days
#> 8:      B 2010-10-11       C 2010-10-12   1 days
#> 9:      C 2010-10-12       C 2010-10-12   0 days

答案 3 :(得分:1)

这是一种使用combn和矩阵索引的方法。

# data
Sample=c("A","B", "C")
Date=as.Date(c("02/10/10", "02/10/11", "02/10/12"), format="%y/%m/%d")
# build a matrix to be filled
myMat <- matrix(0, length(Sample), length(Sample), dimnames=list(Sample, Sample))

# get all pairwise combinations (upper triangle)
samplePairs <- t(combn(Sample, 2))
# add the reverse combination (lower triangle)
samplePairs <- rbind(samplePairs, cbind(samplePairs[,2], samplePairs[,1]))
# calculate differences
diffs <- combn(Date, 2, FUN=diff)

# fill in differences using matrix indexing
myMat[samplePairs] <- diffs