Удалить строки из определенного диапазона года без использования цикла for в R - PullRequest
0 голосов
/ 31 августа 2018

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

a <- data.frame(year = c(2000:2002,1999:2002,1999:2002,1999:2001), 
                id=c(4,6,2,1,3,5,7,4,2,0,-1,-3,4,3))

   year id
1  2000  4
2  2001  6
3  2002  2
4  1999  1
5  2000  3
6  2001  5
7  2002  7
8  1999  4
9  2000  2
10 2001  0
11 2002 -1
12 1999 -3
13 2000  4
14 2001  3

Обработанный набор данных должен включать в себя только последовательные строки в период с 1999 по 2002 год. Следующее data.frame именно то, что мне нужно:

  year id
1 1999  1
2 2000  3
3 2001  5
4 2002  7
5 1999  4
6 2000  2
7 2001  0
8 2002 -1

Когда я выполняю следующий цикл for, я без проблем получаю предыдущий data.frame:

for(i in 1:which(a$year == 2002)[length(which(a$year == 2002))]){
  if(a[i,1] == 1999 & a[i+3,1] == 2002){
    b <- a[i:(i+3),]
  }else{next}

  if(!exists("d")){
    d <- b
  }else{
    d <- rbind(d,b)
  }
}

Однако у меня более 1 миллиона строк, и мне нужно выполнить этот процесс без использования цикла for. Есть ли более быстрый способ для этого?

Ответы [ 3 ]

0 голосов
/ 01 сентября 2018

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

library(tidyverse)

df <- data_frame(year = c(2000:2002,1999:2002,1999:2002,1999:2001), 
                id=c(4,6,2,1,3,5,7,4,2,0,-1,-3,4,3))

df %>% 
  mutate(groups = cumsum(c(0,diff(year)!=1))) %>% 
  nest(-groups) %>%
  mutate(data = map(data, .f = ~full_join(.x, data_frame(year = 1999:2002), by = "year")),
         drop = map_lgl(data, ~any(is.na(.x$id)))) %>%
  filter(drop == FALSE) %>% 
  unnest() %>%
  select(-c(groups, drop))
#> # A tibble: 8 x 2
#>    year    id
#>   <int> <dbl>
#> 1  1999     1
#> 2  2000     3
#> 3  2001     5
#> 4  2002     7
#> 5  1999     4
#> 6  2000     2
#> 7  2001     0
#> 8  2002    -1

Создано в 2018-08-31 представ пакет (v0.2.0).

0 голосов
/ 01 сентября 2018

Мы также могли бы сделать это, создав столбец группировки на основе логического выражения, проверяющего 1999 год, затем filter, отметив first 'year' как '1999', last как '2002' и if all промежуточный «год» присутствует для конкретного «grp»

library(dplyr)
a %>% 
  group_by(grp = cumsum(year == 1999)) %>%
  filter(dplyr::first(year) == 1999, 
         dplyr::last(year) == 2002, 
         all(1999:2002 %in% year)) %>%
  ungroup %>% # in case to remove the 'grp'
  select(-grp)
# A tibble: 8 x 2
#   year    id
#  <int> <dbl>
#1  1999     1
#2  2000     3
#3  2001     5
#4  2002     7
#5  1999     4
#6  2000     2
#7  2001     0
#8  2002    -1
0 голосов
/ 01 сентября 2018

Существует функция, которая может делать это автоматически.

Сначала установите пакет с именем dplyr или tidyverse с помощью команды install.packages("dplyr") или install.packages("tidyverse").

Затем загрузите пакет с library(dplyr).

Затем используйте функцию filter: a_filtered = filter(a, year >=1999 & year < 2002).

Это должно быть быстро, даже если есть много строк.

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