2016-06-22 4 views
4

из очень простого dataframe какВременная матрица расстояний от даты

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 

/изменить: изменил формат дат. извините за неудобства

+0

@ZheyuanLi Написать ответ, то вы можете также правильно форматировать код. –

+1

В общем случае решением такого рода проблемы в R является функция 'dist'. В вашем случае 'dist (test $ Date)' "работает более или менее; однако 'dist' не знает о времени, поэтому результатом являются только числа, а не объекты timediff, что может быть проблемой. По этой причине вышеизложенное замечание Чжэюана показывает лучший ответ. –

ответ

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) будет работать в течение нескольких дней.

+0

OP отредактировал даты, когда я писал этот ответ. В обновленные даты просто выполняется запрос 'dist (test $ Date)'. То, как даты были отформатированы ранее, я думал, что они должны быть разными годами. –

+0

Я не знал, что dist() был хорош для этого формального! Благодарю вас. – nouse

4

Используя внешний()

Вам не нужно работать с фреймом данных. В вашем примере, мы можем собрать ваши даты в одном векторе и использовать 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()

Как упоминалось Конрада, 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. 

Но мы можем работать, чтобы использовать его.

Объект Date, может быть принудительно введен в целые числа, если вы дадите ему источник. К

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. Этот ОП просит вычислить расстояние Хэмминга, что на самом деле является своего рода побитовым расстоянием.

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 
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 
Смежные вопросы