日期的时间距离矩阵

nou*_*use 4 datetime r date

从一个非常简单的数据框架

    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))
Run Code Online (Sandbox Code Playgroud)

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

   A  B  C
A  0  1  2
B  1  0  1
C  2  1  0
Run Code Online (Sandbox Code Playgroud)

/ edit:更改日期的格式。不便之处,敬请原谅

李哲源*_*李哲源 6

使用外部()

您不需要使用数据框。在您的示例中,我们可以在单个向量中收集您的日期并使用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
Run Code Online (Sandbox Code Playgroud)

注意我添加了一个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.
Run Code Online (Sandbox Code Playgroud)

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

日期对象,可以强制转换为整数,如果你给它一个原点。经过

x <- as.numeric(x - min(x))
Run Code Online (Sandbox Code Playgroud)

我们得到自记录的第一天以来的天数。现在我们可以使用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
Run Code Online (Sandbox Code Playgroud)

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

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

outer(x, x, "-")
Run Code Online (Sandbox Code Playgroud)

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

此外,outer()其用途远比dist(). 在这里看看我的回答。那个 OP 要求计算汉明距离,这实际上是一种按位距离。


And*_*y W 5

要获得实际的天数计算,您可以将天数转换为某个预定义日期之后的日期,然后使用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
Run Code Online (Sandbox Code Playgroud)

dist_days 然后打印出来:

> dist_days
    A   B   C
A   0 365 730
B 365   0 365
C 730 365   0
Run Code Online (Sandbox Code Playgroud)

实际上dist,自某些时间以来,无需将日期转换为几天,只需dist(test$Date)将其工作几天即可。


raf*_*ira 5

一个非常快速的解决方案,使用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
Run Code Online (Sandbox Code Playgroud)