R: Обновить идентификатор наблюдения, сравнивая его значение с диапазоном значений, заданных двумя другими столбцами - PullRequest
0 голосов
/ 02 мая 2018

Я сравниваю дорожные данные за два года. Информация дает уникальный код для каждой дороги (id.agg), уникальный код для каждого сегмента дороги (id), начальный и конечный километры для каждого сегмента (ini, fin) и год.

Когда я объединил две таблицы, используя их уникальный идентификатор сегмента, я понял, что есть несоответствия из-за строительства дорог. Однако, исходя из километра, пройденного отрезками, протяженность дорог одинакова. Поэтому я хотел бы найти способ исправить старые идентификаторы с помощью обновлений идентификаторов.

Подмножество моих объединенных данных выглядит так:

 >trial
   id.agg         id year.x ini.x fin.x year.y ini.y fin.y
   010BTO 010BTO0318      1 606.1 611.7      2 606.1 611.7
   010BTO 010BTO0320      1 611.7 631.4      2 611.7 631.4
   010BTO 010BTO0325      1 631.4 670.2      2 631.4 670.2
   010BTO 010BTO0330      1 670.2 718.4      2 670.2 718.4
   010BTO 010BTO0335      1 718.4 734.0      2 718.4 786.8
   010BTO 010BTO0340      1 734.0 772.9     NA    NA    NA
   010BTO 010BTO0345      1 772.9 786.8     NA    NA    NA
   010BTO 010BTO0350      1 786.8 794.9      2 786.8 794.9
   010BTO 010BTO0355      1 794.9 828.2      2 794.9 827.2
   010BTO 010BTO0357     NA    NA    NA      2 827.2 828.2
   020BPI 020BPI0370      1   0.0  40.3      2   0.0  54.3
   020BPI 020BPI0375      1  40.3  54.3     NA    NA    NA
   020BPI 020BPI0380      1  54.3  85.3      2  54.3  85.3
   020BPI 020BPI0390      1  85.3 148.3      2  85.3 148.3
  >

Для этих NA в 2-м году я хотел бы обновить идентификатор, чтобы я мог сравнить, какие отрезки дороги в 1-м году отражены в 2-м году. Я подумал сравнить начальные километры в 1-м году (ini.x) с пробегом километров в год 2. Я попробовал следующее:

> trial[is.na(trial$year.y) & trial$ini.x %between% list(trial$ini.y,trial$fin.y) %in% trial$ini.y,]
   id.agg         id year.x ini.x fin.x year.y ini.y fin.y
6  010BTO 010BTO0340      1 734.0 772.9     NA    NA    NA
7  010BTO 010BTO0345      1 772.9 786.8     NA    NA    NA
12 020BPI 020BPI0375      1  40.3  54.3     NA    NA    NA
>   

Это показывает мне те наблюдения, для которых я хотел бы исправить их идентификаторы, но я все еще не нахожу решения двух основных проблем, чтобы решить мою проблему:

1) Как узнать, с каким конкретным идентификатором запрос находит совпадение? 2) Как это можно применить, сравнивая для каждой группы (т.е. id.agg), а не для всего вектора?

Вопрос 1) важно иметь возможность назначить идентификатор обновления старому идентификатору. Вопрос 2) важен, так как в моем реальном фрейме данных содержится более 6000 наблюдений и около 500 групп, поэтому я почти уверен, что без учета групп я найду ложные совпадения (например, файл ini.x будет найден в диапазоне [ini.y, fin) .y] для более чем одной группы)

Я бы хотел иметь такой фрейм данных:

>trial
id.agg         id year.x ini.x fin.x year.y ini.y fin.y corrected.id
010BTO 010BTO0318      1 606.1 611.7      2 606.1 611.7   010BTO0318
010BTO 010BTO0320      1 611.7 631.4      2 611.7 631.4   010BTO0320
010BTO 010BTO0325      1 631.4 670.2      2 631.4 670.2   010BTO0325
010BTO 010BTO0330      1 670.2 718.4      2 670.2 718.4   010BTO0330
010BTO 010BTO0335      1 718.4 734.0      2 718.4 786.8   010BTO0335
010BTO 010BTO0340      1 734.0 772.9     NA    NA    NA   010BTO0335
010BTO 010BTO0345      1 772.9 786.8     NA    NA    NA   010BTO0335
010BTO 010BTO0350      1 786.8 794.9      2 786.8 794.9   010BTO0350
010BTO 010BTO0355      1 794.9 828.2      2 794.9 827.2   010BTO0355
010BTO 010BTO0357     NA    NA    NA      2 827.2 828.2   010BTO0357
020BPI 020BPI0370      1   0.0  40.3      2   0.0  54.3   020BPI0370
020BPI 020BPI0375      1  40.3  54.3     NA    NA    NA   020BPI0370
020BPI 020BPI0380      1  54.3  85.3      2  54.3  85.3   020BPI0380
020BPI 020BPI0390      1  85.3 148.3      2  85.3 148.3   020BPI0390
>

Я искал решения, но не могу найти функцию или код, который помог бы мне обратиться к пункту 1). В пункте 2) я обнаружил, что group_by в сочетании с%>% может помочь, но мне не удается применить его даже к моему запросу, показанному выше. Например:

> trial %>% 
+   group_by(id.agg) %>% 
+   which( is.na(trial$year.y) & trial$ini.x %between% list(trial$ini.y,trial$fin.y) %in% trial$ini.y, 
+          arr.ind=TRUE)
Error in which(., is.na(trial$year.y) & trial$ini.x %between% list(trial$ini.y,  : 
argument to 'which' is not logical
> 

Буду очень признателен за любые мысли или выводы о том, как решить эту проблему.

Заранее большое спасибо!

-----------

В качестве продолжения я использовал предложенное решение. Он хорошо определяет, какие наблюдения попадают в диапазон предыдущих наблюдений non_NA (ini.y, fin.y). Вот подмножество выходных данных, которые я получил:

  id.agg         id year.x ini.x fin.x year.y ini.y fin.y rownum corrected.id
1 424BAL 424BAL0175   2016  39.5  42.7   2017  39.5  42.7      8   424BAL0175
2 424BAL 424BAL0180   2016  42.7  44.3   2017  42.7  50.8      9   424BAL0180
3 424BAL 424BAL0185   2016  44.3  47.1     NA    NA    NA      9   424BAL0180
4 424BAL 424BAL0190   2016  47.1  52.3     NA    NA    NA      9   424BAL0180
5 424BAL 424BAL0195   2016  52.3  55.0     NA    NA    NA     12   424BAL0195
6 424BAL 424BAL0200   2016  55.0  64.4     NA    NA    NA     13   424BAL0200
7 424BAL 424BAL0205   2016  64.4  68.1     NA    NA    NA     14   424BAL0205
8 424BAL 424BAL0210   2016  68.1  70.4   2017  50.8  73.8     15   424BAL0210
9 424BAL 424BAL0230   2016  70.4  77.2   2017  73.8  80.6     16   424BAL0230

Обратите внимание, что наблюдения в строках 4-6 находятся не в диапазоне (изначально, fin.y) наблюдения в строке 2, а в диапазоне наблюдения в строке 8. Ожидаемый результат должен выглядеть следующим образом:

  id.agg         id year.x ini.x fin.x year.y ini.y fin.y rownum corrected.id
1 424BAL 424BAL0175   2016  39.5  42.7   2017  39.5  42.7      8   424BAL0175
2 424BAL 424BAL0180   2016  42.7  44.3   2017  42.7  50.8      9   424BAL0180
3 424BAL 424BAL0185   2016  44.3  47.1     NA    NA    NA      9   424BAL0180
4 424BAL 424BAL0190   2016  47.1  52.3     NA    NA    NA      9   424BAL0180
5 424BAL 424BAL0195   2016  52.3  55.0     NA    NA    NA     12   424BAL0210
6 424BAL 424BAL0200   2016  55.0  64.4     NA    NA    NA     13   424BAL0210
7 424BAL 424BAL0205   2016  64.4  68.1     NA    NA    NA     14   424BAL0210
8 424BAL 424BAL0210   2016  68.1  70.4   2017  50.8  73.8     15   424BAL0210
9 424BAL 424BAL0230   2016  70.4  77.2   2017  73.8  80.6     16   424BAL0230

Искренне благодарен заранее!

1 Ответ

0 голосов
/ 02 мая 2018

Если я правильно понял проблему, то это должно помочь

library(dplyr)
library(zoo)

df %>%
  group_by(id.agg) %>%
  mutate(rownum=ifelse(is.na(year.y) & is.na(ini.y) & is.na(fin.y), NA, row_number())) %>%
  mutate(rownum=ifelse(is.na(rownum) & ini.x >=na.locf(ini.y) & ini.x <= na.locf(fin.y), 
                       na.locf(rownum), 
                       na.locf(rownum, fromLast=T))) %>%
  mutate(corrected.id = id[rownum]) %>%
  select(-rownum)

Вывод:

  id.agg id         year.x ini.x fin.x year.y ini.y fin.y corrected.id
  <chr>  <chr>       <int> <dbl> <dbl>  <int> <dbl> <dbl> <chr>       
1 424BAL 424BAL0175   2016  39.5  42.7   2017  39.5  42.7 424BAL0175  
2 424BAL 424BAL0180   2016  42.7  44.3   2017  42.7  50.8 424BAL0180  
3 424BAL 424BAL0185   2016  44.3  47.1     NA  NA    NA   424BAL0180  
4 424BAL 424BAL0190   2016  47.1  52.3     NA  NA    NA   424BAL0180  
5 424BAL 424BAL0195   2016  52.3  55.0     NA  NA    NA   424BAL0210  
6 424BAL 424BAL0200   2016  55.0  64.4     NA  NA    NA   424BAL0210  
7 424BAL 424BAL0205   2016  64.4  68.1     NA  NA    NA   424BAL0210  
8 424BAL 424BAL0210   2016  68.1  70.4   2017  50.8  73.8 424BAL0210  
9 424BAL 424BAL0230   2016  70.4  77.2   2017  73.8  80.6 424BAL0230

Пример данных:

df <-structure(list(id.agg = c("424BAL", "424BAL", "424BAL", "424BAL", 
"424BAL", "424BAL", "424BAL", "424BAL", "424BAL"), id = c("424BAL0175", 
"424BAL0180", "424BAL0185", "424BAL0190", "424BAL0195", "424BAL0200", 
"424BAL0205", "424BAL0210", "424BAL0230"), year.x = c(2016L, 
2016L, 2016L, 2016L, 2016L, 2016L, 2016L, 2016L, 2016L), ini.x = c(39.5, 
42.7, 44.3, 47.1, 52.3, 55, 64.4, 68.1, 70.4), fin.x = c(42.7, 
44.3, 47.1, 52.3, 55, 64.4, 68.1, 70.4, 77.2), year.y = c(2017L, 
2017L, NA, NA, NA, NA, NA, 2017L, 2017L), ini.y = c(39.5, 42.7, 
NA, NA, NA, NA, NA, 50.8, 73.8), fin.y = c(42.7, 50.8, NA, NA, 
NA, NA, NA, 73.8, 80.6)), .Names = c("id.agg", "id", "year.x", 
"ini.x", "fin.x", "year.y", "ini.y", "fin.y"), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8", "9"))


Редактировать: Обновлен код после получения большей ясности требования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...