R: Подстановка кадра данных с использованием списка дат в качестве фильтра
У меня есть кадр данных с столбцом даты и некоторыми другими столбцами значений. Я хотел бы извлечь из кадра данных те строки, в которых столбец даты соответствует любому из элементов в уже существующем списке дат. Например, используя список из одного элемента, дата "2012-01-01" выведет строку с датой "2012-01-01" из фрейма данных.
Для чисел, я думаю, я знаю, как соответствовать значениям. Этот код:
testdf <- data.frame(mydate = seq(as.Date('2012-01-01'),
as.Date('2012-01-10'), by = 'day'),
col1 = 1:10,
col2 = 11:20,
col3 = 21:30)
... создает этот фрейм данных:
mydate col1 col2 col3
1 2012-01-01 1 11 21
2 2012-01-02 2 12 22
3 2012-01-03 3 13 23
4 2012-01-04 4 14 24
5 2012-01-05 5 15 25
6 2012-01-06 6 16 26
7 2012-01-07 7 17 27
8 2012-01-08 8 18 28
9 2012-01-09 9 19 29
10 2012-01-10 10 20 30
Я могу это сделать:
testdf[which(testdf$col3 %in% c('25','29')),]
который производит это:
mydate col1 col2 col3
5 2012-01-05 5 15 25
9 2012-01-09 9 19 29
Я могу обобщить это на список следующим образом:
myvalues <- c('25','29')
testdf[which(testdf$col3 %in% myvalues),]
И я получаю тот же результат. Поэтому я подумал, что смогу использовать тот же подход для дат, но, похоже, я ошибался. Выполнение этого действия:
testdf[which(testdf$mydate %in% c('2012-01-05','2012-01-09')),]
Получает это:
[1] mydate col1 col2 col3
<0 rows> (or 0-length row.names)
И появление дат в их собственном списке - это конечная цель - тоже не помогает. Я могу думать о том, как обойти это с помощью циклов или применения функции, но мне кажется, что должен быть более простой способ для того, что, вероятно, является довольно распространенным требованием. Неужели я снова пропустил что-то простое?
В: Как я могу подмножить те строки фрейма данных, у которых есть столбец даты, значения которого соответствуют одному из списка дат?
Ответы
Ответ 1
Вам нужно преобразовать дату string
в переменную Date
, используя as.Date
(попробуйте ?as.Date
на консоли). Бонус: вы можете отказаться от того, что:
> testdf[testdf$mydate %in% as.Date(c('2012-01-05', '2012-01-09')),]
mydate col1 col2 col3
5 2012-01-05 5 15 25
9 2012-01-09 9 19 29
Ответ 2
Оба предложения до сих пор, безусловно, хороши, но если вы собираетесь много работать с датами, вы можете потратить некоторое время на пакет xts
:
# Some sample data for 90 consecutive days
set.seed(1)
testdf <- data.frame(mydate = seq(as.Date('2012-01-01'),
length.out=90, by = 'day'),
col1 = rnorm(90), col2 = rnorm(90),
col3 = rnorm(90))
# Convert the data to an xts object
require(xts)
testdfx = xts(testdf, order.by=testdf$mydate)
# Take a random sample of dates
testdfx[sample(index(testdfx), 5)]
# col1 col2 col3
# 2012-01-17 -0.01619026 0.71670748 1.44115771
# 2012-01-29 -0.47815006 0.49418833 -0.01339952
# 2012-02-05 -0.41499456 0.71266631 1.51974503
# 2012-02-27 -1.04413463 0.01739562 -1.18645864
# 2012-03-26 0.33295037 -0.03472603 0.27005490
# Get specific dates
testdfx[c('2012-01-05', '2012-01-09')]
# col1 col2 col3
# 2012-01-05 0.3295078 1.586833 0.5210227
# 2012-01-09 0.5757814 -1.224613 -0.4302118
Вы также можете получать даты от другого вектора.
# Get dates from another vector
lookup = c("2012-01-12", "2012-01-31", "2012-03-05", "2012-03-19")
testdfx[lookup]
testdfx[lookup]
# col1 col2 col3
# 2012-01-12 0.38984324 0.04211587 0.4020118
# 2012-01-31 1.35867955 -0.50595746 -0.1643758
# 2012-03-05 -0.74327321 -1.48746031 1.1629646
# 2012-03-19 0.07434132 -0.14439960 0.3747244
Пакет xts
предоставит вам интеллектуальные параметры подмножества. Например, testdfx["2012-03"]
вернет все данные с марта; testdfx["2012"]
вернется за год; testdfx["/2012-02-15"]
вернет данные с начала набора данных до 15 февраля; и testdfx["2012-02-15/"]
будет идти с 15 февраля до конца набора данных.
Ответ 3
Или вы можете пойти в обратном направлении к тому, что предложил @Rogi, и преобразовать Date
в строку:
testdf[as.character(testdf$mydate) %in% c('2012-01-05', '2012-01-09'),]
mydate col1 col2 col3
5 2012-01-05 5 15 25
9 2012-01-09 9 19 29
Изменить: время
Преобразование даты в строку немного быстрее, но на самом деле это не имеет никакого значения:
library(rbenchmark)
benchmark(asDate=testdf[testdf$mydate %in% as.Date(c('2012-01-05', '2012-01-09')),],
asString=testdf[as.character(testdf$mydate) %in% c('2012-01-05', '2012-01-09'),],
replications=1000)
# test replications elapsed relative user.self sys.self user.child
# 1 asDate 1000 0.211 1.076531 0.212 0 0
# 2 asString 1000 0.196 1.000000 0.192 0 0
# sys.child
# 1 0
# 2 0