В R: добавление строк с годовыми интервалами дат в фрейм данных

#r #dataframe #date

#r #фрейм данных #Дата

Вопрос:

Я хотел бы добавить строки для каждой точки выборки, содержащие временные интервалы с годовыми интервалами. Итак, в добавленных строках я хочу изменить только содержимое столбцов «от» и «до» и сохранить всю остальную информацию из строки выше.

Что у меня есть прямо сейчас:

  > sample_points
point       from         to     label
    1 2004-05-01 2007-05-01  cropland
    2 2009-05-01 2012-05-01 grassland
    3 2014-05-01 2016-05-01    forest
  

Что мне нужно:

  > sample_points
point       from         to     label
    1 2004-05-01 2005-05-01  cropland
    1 2005-05-01 2006-05-01  cropland
    1 2006-05-01 2007-05-01  cropland
    2 2009-05-01 2010-05-01 grassland
    2 2010-05-01 2011-05-01 grassland
    2 2011-05-01 2012-05-01 grassland
    3 2014-05-01 2015-05-01    forest
    3 2015-05-01 2016-05-01    forest  
  

Вот пример фрейма данных:

 point <- c("1", "2", "3")
from <- as.Date(c("2004-05-01", "2009-05-01", "2014-05-01"))
to <- as.Date(c("2007-05-01", "2012-05-01", "2016-05-01"))
label <- c("cropland", "grassland", "forest")

sample_points <- data.frame(point, from, to, label)
  

Я новичок в R, и это мой первый вопрос здесь, поэтому, пожалуйста, простите меня, если вопрос сформулирован не идеально, чего-то не хватает или я пропустил аналогичный вопрос с решением моей проблемы.
Я благодарен за любые подсказки!

Ответ №1:

Вот один tidyverse из вариантов :

Мы создаем годовую последовательность от from столбца к to столбцу и создаем to столбец, который является следующим значением from значения для каждого point .

 library(tidyverse)

sample_points %>%
  mutate(from = map2(from, to, seq, by = 'year')) %>%
  unnest(from) %>%
  group_by(point) %>%
  mutate(to = lead(from)) %>%
  filter(!is.na(to))

#  point from       to         label    
#  <chr> <date>     <date>     <chr>    
#1 1     2004-05-01 2005-05-01 cropland 
#2 1     2005-05-01 2006-05-01 cropland 
#3 1     2006-05-01 2007-05-01 cropland 
#4 2     2009-05-01 2010-05-01 grassland
#5 2     2010-05-01 2011-05-01 grassland
#6 2     2011-05-01 2012-05-01 grassland
#7 3     2014-05-01 2015-05-01 forest   
#8 3     2015-05-01 2016-05-01 forest   
  

Ответ №2:

Вы можете создавать годовые seq значения по строкам, rep дважды использовать каждое значение, чтобы создать a matrix , где впоследствии вы удаляете ненужные строки.

 res <- do.call(rbind, lapply(1:nrow(sample_points), function(m) {
  cc <- c("from", "to")
  dc <- as.character(do.call(seq, as.list(c(sample_points[m, cc], by="year"))))
  if (length(dc) == 2) {
    o <- sample_points[m, ]
  } else {
    dm <- suppressWarnings(matrix(rep(dc, each=2)[-1],,2,b=T))
    dm <- if (nrow(dm) == 1) dm else dm[-nrow(dm), ]
    o <- setNames(data.frame(sample_points[m, "point"], dm, 
                             sample_points[m, "label"]),names(sample_points))
    o[cc] <- lapply(o[cc], as.Date)
  }
  o
}))
  

Дает

 res
#   point       from         to     label
# 1     1 2004-05-01 2005-05-01  cropland
# 2     1 2005-05-01 2006-05-01  cropland
# 3     1 2006-05-01 2007-05-01  cropland
# 4     2 2009-05-01 2010-05-01 grassland
# 5     2 2010-05-01 2011-05-01 grassland
# 6     2 2011-05-01 2012-05-01 grassland
# 7     3 2014-05-01 2015-05-01    forest
# 8     3 2015-05-01 2016-05-01    forest
  

Где

 str(res)
# 'data.frame': 8 obs. of  4 variables:
# $ point: chr  "1" "1" "1" "2" ...
# $ from : Date, format: "2004-05-01" ...
# $ to   : Date, format: "2005-05-01" ...
# $ label: chr  "cropland" "cropland" "cropland" "grassland" ...
  

Данные:

 sample_points <- structure(list(point = c("1", "2", "3"), from = structure(c(12539, 
14365, 16191), class = "Date"), to = structure(c(13634, 15461, 
16922), class = "Date"), label = c("cropland", "grassland", "forest"
)), class = "data.frame", row.names = c(NA, -3L))