来自一个非常简单的数据框,如
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:更改了日期的格式。抱歉给您带来不便
答案 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