Минус значения из столбцов относительно года

#r

#r

Вопрос:

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

Вот пример набора данных и то, что я ожидаю от результата:

 #dataset example

# A tibble: 30 x 18
      id year  pland_00_water pland_01_evergr~ pland_02_evergr~ pland_03_decidu~ pland_04_decidu~ pland_05_mixed_~ pland_06_closed~
   <int> <chr>          <dbl>            <dbl>            <dbl>            <dbl>            <dbl>            <dbl>            <dbl>
 1   267 2019          0.0833                0                0                0                0                0                0
 2   268 2019          0.2                   0                0                0                0                0                0
 3   362 2019          0.1                   0                0                0                0                0                0
 4   420 2019          0.0556                0                0                0                0                0                0
 5   421 2019          0.0667                0                0                0                0                0                0
 6   484 2019          0.125                 0                0                0                0                0                0
 7   492 2010          0.1                   0                0                0                0                0                0
 8   492 2019          0.1                   0                0                0                0                0                0
 9   719 2010          0.0769                0                0                0                0                0                0
10   719 2019          0.0769                0                0                0                0                0                0


#output example

# A tibble: 30 x 18
      id year  pland_00_water pland_01_evergr~ pland_02_evergr~ pland_03_decidu~ pland_04_decidu~ pland_05_mixed_~ pland_06_closed~
   <int> <chr>          <dbl>            <dbl>            <dbl>            <dbl>            <dbl>            <dbl>            <dbl>
 1   267 2019          0.0833                0                0                0                0                0                0
 2   268 2019          0.2                   0                0                0                0                0                0
 3   362 2019          0.1                   0                0                0                0                0                0
 4   420 2019          0.0556                0                0                0                0                0                0
 5   421 2019          0.0667                0                0                0                0                0                0
 6   484 2019          0.125                 0                0                0                0                0                0
 7   492 changed        0                     0                0                0                0                0                0

 9   719 changed        0                     0                0                0                0                0                0

 

Я могу представить, что это работает с функцией и логическими операторами таким образом, что, если year 2010 и 2019 совпадают к id тому времени, следующая строка минус предыдущая (при условии, что они упорядочены к id тому времени, это должно сработать), в противном случае, если они не совпадают по идентификатору, оставьте их как есть.

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

Вот воспроизводимый код:

 structure(list(id = c(267L, 268L, 362L, 420L, 421L, 484L, 492L, 
492L, 719L, 719L, 986L, 986L, 1071L, 1071L, 1303L, 1303L, 1306L, 
1399L, 1399L, 1400L, 1400L, 2007L, 2083L, 2083L, 2134L, 2135L, 
2136L, 2213L, 2213L, 2214L), year = c(2019, 2019, 2019, 2019, 
2019, 2019, 2010, 2019, 2010, 2019, 2010, 2019, 2010, 2019, 2010, 
2019, 2010, 2010, 2019, 2010, 2019, 2019, 2010, 2019, 2019, 2019, 
2019, 2010, 2019, 2010), pland_00_water = c(0.0833333333333333, 
0.2, 0.1, 0.0555555555555556, 0.0666666666666667, 0.125, 0.1, 
0.1, 0.0769230769230769, 0.0769230769230769, 0.0588235294117647, 
0.0588235294117647, 0.0714285714285714, 0.0714285714285714, 0.0769230769230769, 
0.0769230769230769, 0.0588235294117647, 0.05, 0.05, 0.111111111111111, 
0.111111111111111, 0.0526315789473684, 0.142857142857143, 0.142857142857143, 
0.0666666666666667, 0.0588235294117647, 0.1, 0.142857142857143, 
0.142857142857143, 0.25), pland_01_evergreen_needleleaf = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0588235294117647, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), pland_02_evergreen_broadleaf = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0), pland_03_deciduous_needleleaf = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0714285714285714, 0, 0, 
0, 0, 0.05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), pland_04_deciduous_broadleaf = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0714285714285714, 0.0714285714285714, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), pland_05_mixed_forest = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0), pland_06_closed_shrubland = c(0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0), pland_07_open_shrubland = c(0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0), pland_08_woody_savanna = c(0, 0, 0, 0, 0, 0, 
0, 0, 0.0769230769230769, 0.0769230769230769, 0.0588235294117647, 
0.0588235294117647, 0.0714285714285714, 0.0714285714285714, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), pland_09_savanna = c(0, 
0, 0, 0, 0, 0, 0, 0, 0.0769230769230769, 0.0769230769230769, 
0.0588235294117647, 0.0588235294117647, 0, 0, 0, 0.0769230769230769, 
0.0588235294117647, 0.05, 0.05, 0.111111111111111, 0.111111111111111, 
0, 0, 0, 0, 0, 0, 0, 0, 0), pland_10_grassland = c(0.0833333333333333, 
0.2, 0.1, 0.0555555555555556, 0.0666666666666667, 0.125, 0.1, 
0.1, 0.0769230769230769, 0.0769230769230769, 0.0588235294117647, 
0.0588235294117647, 0.0714285714285714, 0.0714285714285714, 0.0769230769230769, 
0.0769230769230769, 0.0588235294117647, 0.05, 0.05, 0.111111111111111, 
0.111111111111111, 0.0526315789473684, 0.142857142857143, 0.142857142857143, 
0.0666666666666667, 0.0588235294117647, 0.1, 0.142857142857143, 
0.142857142857143, 0.25), pland_11_wetland = c(0.0833333333333333, 
0.2, 0.1, 0.0555555555555556, 0, 0, 0.1, 0.1, 0.0769230769230769, 
0.0769230769230769, 0.0588235294117647, 0.0588235294117647, 0.0714285714285714, 
0.0714285714285714, 0.0769230769230769, 0.0769230769230769, 0.0588235294117647, 
0.05, 0.05, 0.111111111111111, 0, 0.0526315789473684, 0.142857142857143, 
0.142857142857143, 0.0666666666666667, 0.0588235294117647, 0.1, 
0.142857142857143, 0.142857142857143, 0), pland_12_cropland = c(0.0833333333333333, 
0.2, 0.1, 0.0555555555555556, 0.0666666666666667, 0.125, 0.1, 
0.1, 0.0769230769230769, 0.0769230769230769, 0.0588235294117647, 
0, 0, 0, 0.0769230769230769, 0.0769230769230769, 0.0588235294117647, 
0.05, 0.05, 0.111111111111111, 0.111111111111111, 0.0526315789473684, 
0.142857142857143, 0.142857142857143, 0.0666666666666667, 0, 
0, 0.142857142857143, 0.142857142857143, 0.25), pland_13_urban = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0), pland_14_mosiac = c(0, 0, 0, 0, 0, 0, 
0, 0, 0.0769230769230769, 0.0769230769230769, 0, 0.0588235294117647, 
0, 0, 0, 0, 0, 0.05, 0.05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 
    pland_15_barren = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), row.names = c(NA, 
-30L), class = c("tbl_df", "tbl", "data.frame"))
 

Ответ №1:

Вот версия tidyverse:

 library(dplyr)

x %>%
  arrange(year) %>%
      # can add 'id' if desired, minimum 'year' required for below
  group_by(id) %>%
  filter(
    all(c("2010", "2019") %in% year),
    year %in% c("2010", "2019")
  ) %>%
  summarize_at(vars(-year), diff) %>%
  mutate(year = "changed") %>%
  ungroup() %>%
  bind_rows(x, .) %>%
  arrange(id, year)           # just to show id=492
# # A tibble: 39 x 18
#       id year  pland_00_water pland_01_evergr~ pland_02_evergr~ pland_03_decidu~ pland_04_decidu~ pland_05_mixed_~
#    <int> <chr>          <dbl>            <dbl>            <dbl>            <dbl>            <dbl>            <dbl>
#  1   267 2019          0.0833                0                0                0                0                0
#  2   268 2019          0.2                   0                0                0                0                0
#  3   362 2019          0.1                   0                0                0                0                0
#  4   420 2019          0.0556                0                0                0                0                0
#  5   421 2019          0.0667                0                0                0                0                0
#  6   484 2019          0.125                 0                0                0                0                0
#  7   492 2010          0.1                   0                0                0                0                0
#  8   492 2019          0.1                   0                0                0                0                0
#  9   492 chan~         0                     0                0                0                0                0
# 10   719 2010          0.0769                0                0                0                0                0
# # ... with 29 more rows, and 10 more variables: pland_06_closed_shrubland <dbl>, pland_07_open_shrubland <dbl>,
# #   pland_08_woody_savanna <dbl>, pland_09_savanna <dbl>, pland_10_grassland <dbl>, pland_11_wetland <dbl>,
# #   pland_12_cropland <dbl>, pland_13_urban <dbl>, pland_14_mosiac <dbl>, pland_15_barren <dbl>
 

Объяснение:

  • первый arrange(year) заключается в том, что diff более поздние будут иметь значения в ожидаемом порядке (при условии, что все годы являются подобными годам, которые сортируются лексикографически так же, как числовая сортировка);
  • filter первый удаляет все идентификаторы, у которых нет обоих лет, а затем гарантирует, что у нас есть только эти два года; в то время как ваши данные содержат только "2010" и "2019" , я не хотел этого предполагать… это безвредный фильтр, если это все, что у вас есть, удалите year %in% c("2010","2019") его при желании и безопасно;
  • Я предполагаю, что столбцы, отличные от id и year , являются числовыми / целочисленными, поэтому summarize_at(vars(-year), diff) безопасны ( id не рассматриваются, поскольку это группирующая переменная); если есть нечисловые значения, вы можете использовать summarize_if(is.numeric, diff) , что также работает здесь… но будет автоматически NA удалять нечисловые поля, если они присутствуют;
  • bind_rows(x, .) необходим, потому filter что удалено много строк, которые мы хотим / должны сохранить; и
  • последнее arrange(id,year) является исключительно демонстративным для этого ответа.

Комментарии:

1. Когда я добираюсь до bind_rows(x, .) него, он возвращает мне эту ошибку: Error: Can't combine `..1$year` <double> and `..2$year` <character>.

2. Это потому, что вы изменили свои примерные данные со "year" строковых (которые я использовал) на числовые. Вы выбираете: если вам нужны числа, затем измените одну строку на mutate(year = NA_real_) . Если вы хотите "changed" , то не пытайтесь использовать числа.

3. Спасибо, я только что заметил это перед вашим ответом. Я всего лишь пытался привести пример, используя character: changed , однако, мне следовало бы продумать его более кратко. Тем не менее, вы дали be хорошую основу для дальнейшего продвижения этого кода. Спасибо.

4. Рад, что это помогает, в любом случае работает. Я думал о том, чтобы прокомментировать использование строк для "year" (поскольку оно отражает непрерывную или порядковую переменную), но подумал, что ваша потребность в литерале "changed" вытеснила это предпочтение. Я предпочитаю integer character , и numeric это достаточно близко для большинства вещей. С учетом этого я рекомендую перейти year=NA_real_ к различиям. Если вам нужна метка «изменено» где-нибудь, вы можете добавить еще один столбец, содержащий "raw" "diff" метки и … или похожие.