R как отфильтровать временной ряд измерений на основе предыдущих значений - PullRequest
1 голос
/ 12 апреля 2020

Я пытаюсь отфильтровать демографические данные по кораллам c во временном ряду. У меня есть набор кораллов, которые измеряются каждые 3 месяца. То, что я хочу сделать, - это.) Фильтр для всех кораллов, которые в какой-то момент имели максимальный диаметр в пределах указанного диапазона размеров (диаметр 8–12 мм), б.) Удаление кораллов, которые ранее были больше, чем диапазон размеров, и c.) Удалить измерения кораллов, попавшие в диапазон размеров ПОСЛЕ того, как они выросли или миновали диапазон размеров, включив только для каждого коралла ПЕРВОЕ измерение, в котором оно выросло в диапазон размеров (8-12 мм), и последующее измерение в следующий TimeStep.

Я создал образец базы данных и нужную базу данных, чтобы конкретно проиллюстрировать то, что я ищу. В пример базы данных я также включил все критерии, перечисленные для каждого коралла ниже, в разделе примечаний рядом с первой записью для каждого коралла для справки. Вот 8 кораллов, которые я включил в базу данных, и то, что я хочу сделать с ними в словах:

Коралл # 1 должен быть полностью удален из базы данных, потому что он пропустил желаемый диапазон размеров 8- 12 мм

Коралл № 2 следует удалить из базы данных, поскольку он начинался выше желаемого диапазона размеров, затем уменьшался ниже его, а затем увеличивался в нем. Мне нужны только кораллы, которые выросли до размера без предварительной усадки

Коралл # 3 - это пример коралла, который вырос до диапазона размеров (8-12 мм) и выше без усадки, и это коралл что я хочу сохранить, потому что он вырос до размера диапазона. Однако я хочу включить только ПЕРВУЮ меру в диапазон размеров (9 мм в этом случае в TimeStep 3) и продолжающееся измерение (12 мм в этом случае для TimeStep 4)

Коралл # 4 является примером коралла, который начался и остался выше диапазона размеров и поэтому должен быть удален.

Коралл # 5 является примером коралла, который начался ниже диапазона, вырос в него, а затем сжался обратно в диапазон (TimeStep 4). Для этого сценария я хочу включить только первый раз, когда диаметр попал в диапазон (TimeStep 2), и продолжающееся измерение (TimeStep 3), а не второй раз, когда он попал в диапазон. Это потому, что первый раз - это естественный рост, тогда как второй раз - это усадка и ее восстановление (которое я хочу исключить или отфильтровать).

Коралл № 6 - пример коралла, который начался с размера Диапазон для TimeStep 1, а затем вырос из него в следующем TimeStep и продолжал расти после. Я хочу сохранить только измерения в TimeStep 1 и 2 (первое измерение внутри диапазона и продолжающееся измерение)

Coral # 7 - пример коралла, который начался в диапазоне размеров в TimeStep 1, а затем оставался в диапазоне для TimeStep 2. В этом случае я хочу только первое измерение в диапазоне размеров (TimeStep 1) и последующее измерение (TimeStep 2)

Коралл # 8 является примером коралла, который вырос до диапазона размеров в TimeStep 3, оставался в диапазоне (10 => 9) в TimeStep 4, затем сжимался ниже желаемого диапазона, затем для TimeStep 6 снова увеличивался до диапазона. Для этой колонии, опять же, я хочу ПЕРВОЕ измерение в пределах диапазона (10 мм на TimeStep 3), и продолжающееся измерение в TimeStep 4, включенное для этого коралла

Коралл # 9, является примером коралла, который вырос в диапазон размеров в TimeStep 3 (9 мм), но не был найден в следующем TimeStep (NF для столбца кода состояния с измерением как NA). Я хочу сохранить такие кораллы в наборе данных, чтобы рассчитать выживаемость.

В общем, я хочу код, который фильтрует эту базу данных так, что если в какой-то момент коралл имеет диаметр в размере 8-12 см. диапазон, но ранее он был больше этого диапазона, никогда не превышал или не превышал диапазон, или начинался ниже диапазона и никогда не попадал в него, они полностью удаляются из базы данных. Кроме того, я хочу сохранить в базе данных любые кораллы, которые выросли до диапазона, а затем сократились до него, удаляя второй раз, когда он попадал в диапазон. Это можно сделать, удалив все измерения, кроме первого временного шага, в котором коралл вырос в размерный диапазон, и последующего измерения временного шага.

ОБРАЗЕЦ БАЗЫ ДАННЫХ

data <- structure(list(Site = c("WAI", "WAI", "WAI", "WAI", "WAI", "WAI", 
"WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", 
"WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", 
"WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", 
"WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", 
"WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", "WAI", 
"WAI"), `Module #` = c(116, 116, 116, 116, 116, 116, 116, 115, 
115, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 
116, 116, 116, 116, 116), Side = c("N", "N", "N", "N", "N", "N", 
"N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", 
"N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", 
"N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", 
"N", "N", "N", "N", "N", "N", "N"), TimeStep = c(1, 2, 3, 4, 
5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 
2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 
5, 6, 1, 2, 3, 4), Settlement_Area = c(0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336), `Colony #` = c(1, 1, 1, 1, 1, 1, 2, 
2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 
5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 
9, 9, 9), Location = c("C1", "C1", "C1", "C1", "C1", "C1", "B4", 
"B4", "B4", "B4", "B4", "B4", "A1", "A1", "A1", "A1", "A1", "A1", 
"B3", "B3", "B3", "B3", "B3", "B3", "D1", "D1", "D1", "D1", "D1", 
"D1", "A2", "A2", "A2", "A2", "A2", "A2", "A4", "A4", "A4", "A4", 
"A4", "A4", "B3", "B3", "B3", "B3", "B3", "B3", "A3", "A3", "A3", 
"A3"), `Taxonomic Code` = c("PC", "PC", "PC", "PC", "PC", "PC", 
"PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", 
"PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", 
"PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", 
"PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", "PC", 
"PC", "PC"), `Cover Code` = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, NA), 
    `Max Diameter (cm)` = c(5, 7, 13, 15, 16, 19, 15, 7, 9, 11, 
    14, 18, 3, 6, 9, 12, 15, 20, 13, 16, 18, 21, 23, 26, 6, 9, 
    14, 12, 15, 18, 11, 14, 17, 17, 21, 24, 9, 11, 14, 16, 20, 
    22, 3, 6, 10, 9, 7, 10, 4, 6, 9, NA), `Status Code` = c(NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, "NF"), Notes = c("coral # 1 should be deleted from the database because it skipped over the desired size range of 8-12 mm", 
    NA, NA, NA, NA, NA, "coral # 2 should be deleted from the database because it started above the desired size range then shrank back into it.  I only want corals that have grown into the size range", 
    NA, NA, NA, NA, NA, "Colony # 3 is an example of a coral that grew to the size range (8-12 mm) and beyond without shrinking and this is a coral that I want to keep because it grew to the size range.  However, I want to only include the FIRST measure inside the size range (9 mm in this case) and the proceeding measurement (12 mm)", 
    NA, NA, NA, NA, NA, "Colony # 4 is an example of a coral that started off above the size range and therefore needs to be removed.", 
    NA, NA, NA, NA, NA, "Colony # 5 is an example of a coral that started below the range, grew into it, then later shrank back into the range (TimeStep 4). For this scenario, I want to only include the first time the diameter fell into the range (TimeStep 2) and the proceeding measurement, not the second time it fell into the range. This is because the first time is natural growth whereas the second time is shrinkage and its resulting recovery (which I want to exclude or filter out).", 
    NA, NA, NA, NA, NA, "Colony # 6 is an example of a coral that started in the size range for TimeStep 1 and then grew out of it in the next TimeStep and continued to grow after. I want to maintain only the measurements in TimeStep 1 and 2 (the first measure inside the range and the proceeding measurement)", 
    NA, NA, NA, NA, NA, "Colony # 7 is an example of a coral that started in the size range in TimeStep 1 and then remained in the range for TimeStep 2. In this case I only want the first measurement in the size range (TimeStep 1) and the subsequent measurement (TimeStep 2)", 
    NA, NA, NA, NA, NA, "Colony # 8 is an example of a coral that grew to the size range in TimeStep 3, stayed in the range (10 => 9) in TimeStep 4, then shrank below the desired range then for TimeStep 6 grew back to the range. For this colony, again I want the FIRST measurement inside the range (10 mm at TimeStep 3) and the proceeding measurement in TimeStep 4 included for this coral", 
    NA, NA, NA, NA, NA, NA, NA, NA, NA)), class = c("spec_tbl_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -52L), spec = structure(list(
    cols = list(Site = structure(list(), class = c("collector_character", 
    "collector")), `Module #` = structure(list(), class = c("collector_double", 
    "collector")), Side = structure(list(), class = c("collector_character", 
    "collector")), TimeStep = structure(list(), class = c("collector_double", 
    "collector")), Settlement_Area = structure(list(), class = c("collector_double", 
    "collector")), `Colony #` = structure(list(), class = c("collector_double", 
    "collector")), Location = structure(list(), class = c("collector_character", 
    "collector")), `Taxonomic Code` = structure(list(), class = c("collector_character", 
    "collector")), `Cover Code` = structure(list(), class = c("collector_double", 
    "collector")), `Max Diameter (cm)` = structure(list(), class = c("collector_double", 
    "collector")), `Status Code` = structure(list(), class = c("collector_character", 
    "collector")), Notes = structure(list(), class = c("collector_character", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), skip = 1), class = "col_spec"))

Желаемая база данных

data_final <- structure(list(Site = c("WAI", "WAI", "WAI", "WAI", "WAI", "WAI", 
"WAI", "WAI", "WAI", "WAI", "WAI", "WAI"), `Module #` = c(116, 
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116), Side = c("N", 
"N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N"), TimeStep = c(3, 
4, 2, 3, 1, 2, 1, 2, 3, 4, 3, 4), Settlement_Area = c(0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336, 
0.75902336, 0.75902336, 0.75902336, 0.75902336, 0.75902336), 
    `Colony #` = c(3, 3, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9), Location = c("A1", 
    "A1", "D1", "D1", "A2", "A2", "A4", "A4", "B3", "B3", "B2", 
    "B2"), `Taxonomic Code` = c("PC", "PC", "PC", "PC", "PC", 
    "PC", "PC", "PC", "PC", "PC", "PC", "PC"), `Cover Code` = c(1, 
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, NA), `Max Diameter (cm)` = c(9, 
    12, 9, 14, 11, 14, 9, 11, 10, 9, 9, NA), `Status Code` = c(NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "NF")), class = c("spec_tbl_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -12L), spec = structure(list(
    cols = list(Site = structure(list(), class = c("collector_character", 
    "collector")), `Module #` = structure(list(), class = c("collector_double", 
    "collector")), Side = structure(list(), class = c("collector_character", 
    "collector")), TimeStep = structure(list(), class = c("collector_double", 
    "collector")), Settlement_Area = structure(list(), class = c("collector_double", 
    "collector")), `Colony #` = structure(list(), class = c("collector_double", 
    "collector")), Location = structure(list(), class = c("collector_character", 
    "collector")), `Taxonomic Code` = structure(list(), class = c("collector_character", 
    "collector")), `Cover Code` = structure(list(), class = c("collector_double", 
    "collector")), `Max Diameter (cm)` = structure(list(), class = c("collector_double", 
    "collector")), `Status Code` = structure(list(), class = c("collector_character", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), skip = 1), class = "col_spec"))

До сих пор мне удавалось получить кораллы, которые никогда не были в диапазоне размеров, создав вектор уникальных чисел колоний, которые упали в 8-12 мм:

size_vect <- seq(from = 8, to = 12, by = 1)
# a vector containing the range of diameter measurements we want to filter for

ID_vect <- data %>% group_by(`Colony #`) %>% 
filter(`Max Diameter (cm)` > min(size_vect) & `Max Diameter (cm)` < max(size_vect)) %>% 
# select all measures where the coral fell within the size range
distinct(`Colony #`) %>% 
# remove duplicate colony numbers
pull(`Colony #`)
# make the column `Colony #` in the dataframe ID_vect into a vector

Тогда Я отфильтровал всю примерную базу данных, чтобы включить только колонки кораллов из ID_vect:

data_new <- data %>% group_by(`Colony #`) %>%
filter(`Colony #` %in% ID_vect) 
# filter for all corals that contain the same colony number as those in the ID_vect

Я не знаю, как теперь фильтровать базу данных на основе следующего условия: если коралл попал в диапазон размеров в какой-то точка, но предыдущее измерение было БОЛЬШЕ, чем максимальное значение желаемого диапазона размеров (12 мм), этот коралл должен быть полностью удален. Например, Coral # 2 должен быть удален, потому что до того, как значение попало в диапазон в TimeStep 3, было 15 мм в TimeStep 1, что превышает диапазон.

Кроме того, я не знаю, как учитывать, если было никаких измерений в следующем измерении TimeStep, например, с Coral # 9, где оно было измерено как 9 мм в TimeStep 3 и не было найдено (NF в коде состояния) в TimeStep 4. Мне нужно сохранить измерение TimeStep 4 для расчета выживаемости. Я не знаю, как кодировать этот условный фильтр, и здесь мне нужна помощь. Любой совет кода приветствуется!

1 Ответ

1 голос
/ 12 апреля 2020

Мы можем использовать кодирование длин серий, чтобы не отставать от переходов из диапазона в диапазон. С data.table::rleid так намного проще, что я рекомендую его использовать.

Вот пример RLE в действии на коралле 8.

 `Colony #` `Max Diameter (cm)` InRange RLE
          8                   3   FALSE   1
          8                   6   FALSE   1
          8                  10    TRUE   2
          8                   9    TRUE   2
          8                   7   FALSE   3
          8                  10    TRUE   4

Как только RLE закодирован, мы фильтруем строки, которые имеют минимальную RLE в диапазоне, которая ниже минимума выше RLE Если такие строки существуют, мы ищем первую временную точку, которая находится в диапазоне, а также фильтруем следующую временную точку.

library(dplyr)
library(data.table)
data %>% 
  select(-Notes) %>%
  mutate(InRange = case_when(`Max Diameter (cm)` >= 8 & `Max Diameter (cm)` <= 12 ~ TRUE,
                             TRUE ~ FALSE)) %>% 
  mutate(AboveRange = case_when(`Max Diameter (cm)` > 12 ~ TRUE,
                                TRUE ~ FALSE)) %>% 
  group_by(`Colony #`) %>%
  mutate(RLE = data.table::rleid(InRange)) %>% 
  mutate(MinIn = min(RLE[InRange]), MinAbove = min(RLE[AboveRange]), MinInTime = min(TimeStep[InRange])) %>%
  filter(MinIn < MinAbove & (TimeStep == MinInTime | (TimeStep == MinInTime + 1))) %>% 
  select(-InRange,-AboveRange,-RLE,-MinIn,-MinAbove,-MinInTime)
## A tibble: 12 x 11
## Groups:   Colony # [6]
#   Site  `Module #` Side  TimeStep Settlement_Area `Colony #` Location `Taxonomic Code` `Cover Code` `Max Diameter (cm)` `Status Code`
#   <chr>      <dbl> <chr>    <dbl>           <dbl>      <dbl> <chr>    <chr>                   <dbl>               <dbl> <chr>        
# 1 WAI          116 N            3           0.759          3 A1       PC                          1                   9 NA           
# 2 WAI          116 N            4           0.759          3 A1       PC                          1                  12 NA           
# 3 WAI          116 N            2           0.759          5 D1       PC                          1                   9 NA           
# 4 WAI          116 N            3           0.759          5 D1       PC                          1                  14 NA           
# 5 WAI          116 N            1           0.759          6 A2       PC                          1                  11 NA           
# 6 WAI          116 N            2           0.759          6 A2       PC                          1                  14 NA           
# 7 WAI          116 N            1           0.759          7 A4       PC                          1                   9 NA           
# 8 WAI          116 N            2           0.759          7 A4       PC                          1                  11 NA           
# 9 WAI          116 N            3           0.759          8 B3       PC                          1                  10 NA           
#10 WAI          116 N            4           0.759          8 B3       PC                          1                   9 NA           
#11 WAI          116 N            3           0.759          9 A3       PC                          1                   9 NA           
#12 WAI          116 N            4           0.759          9 A3       PC                         NA                  NA NF  
...