выбрать две случайные и последовательные строки из сгруппированных данных - PullRequest
0 голосов
/ 28 сентября 2018

В приведенных ниже данных (включены с dput), у меня есть повторные наблюдения (широта и долгота) для трех человек (IndIDII).Обратите внимание, что для каждого человека существует разное количество местоположений, и они располагаются по IndYear.

  IndIDII      IndYear  WintLat  WintLong
1 BHS_265 BHS_265-2015 47.61025 -112.7210
2 BHS_265 BHS_265-2016 47.59884 -112.7089
3 BHS_770 BHS_770-2016 42.97379 -109.0400
4 BHS_770 BHS_770-2017 42.97129 -109.0367
5 BHS_770 BHS_770-2018 42.97244 -109.0509
6 BHS_377 BHS_377-2015 43.34744 -109.4821
7 BHS_377 BHS_377-2016 43.35559 -109.4445
8 BHS_377 BHS_377-2017 43.35195 -109.4566
9 BHS_377 BHS_377-2018 43.34765 -109.4892

Я хотел бы filter и создать новый df, который состоит из двух последовательных строкза каждый IndIDII.В моем большом наборе данных все люди имеют как минимум 2 наблюдения (то есть строки), с диапазоном от 2 до 4 наблюдений на человека.Очевидно, что для людей, имеющих только 2 строки, код возвратит только 2 доступные строки.При большем количестве данных строки 1 и 2, или 2 и 3, или 3 и 4 будут выбраны случайным образом.Порядок строк не важен, если они последовательны (то есть могут возвращать 3 и 4 или 4 и 3).

Как всегда, большое спасибо!

Dat <- structure(list(IndIDII = c("BHS_265", "BHS_265", "BHS_770", "BHS_770", 
"BHS_770", "BHS_377", "BHS_377", "BHS_377", "BHS_377"), IndYear = c("BHS_265-2015", 
"BHS_265-2016", "BHS_770-2016", "BHS_770-2017", "BHS_770-2018", 
"BHS_377-2015", "BHS_377-2016", "BHS_377-2017", "BHS_377-2018"
), WintLat = c(47.6102519805014, 47.5988417247191, 42.9737859090909, 
42.9712914772727, 42.9724390816327, 43.3474354347826, 43.3555934579439, 
43.3519543396226, 43.3476466990291), WintLong = c(-112.720994832869, 
-112.708887595506, -109.039964727273, -109.036693522727, -109.050923061224, 
-109.482114456522, -109.444522149533, -109.45659254717, -109.489241553398
)), class = "data.frame", row.names = c(NA, -9L))

Ответы [ 3 ]

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

Вот немного неуклюжий тидевальный способ.Определенно может быть улучшено (что, если вы хотите более 1 подряд?), Но работает для этого приложения.Вы также можете удалить столбец строки с помощью select() в конце функции.

Dat <- structure(list(IndIDII = c("BHS_265", "BHS_265", "BHS_770", "BHS_770", "BHS_770", "BHS_377", "BHS_377", "BHS_377", "BHS_377"), IndYear = c("BHS_265-2015", "BHS_265-2016", "BHS_770-2016", "BHS_770-2017", "BHS_770-2018", "BHS_377-2015", "BHS_377-2016", "BHS_377-2017", "BHS_377-2018"), WintLat = c(47.6102519805014, 47.5988417247191, 42.9737859090909, 42.9712914772727, 42.9724390816327, 43.3474354347826, 43.3555934579439, 43.3519543396226, 43.3476466990291), WintLong = c(-112.720994832869, -112.708887595506, -109.039964727273, -109.036693522727, -109.050923061224, -109.482114456522, -109.444522149533, -109.45659254717, -109.489241553398)), class = "data.frame", row.names = c(NA, -9L))

library(tidyverse)
set.seed(123)
sample_2_consecutive <- function(tbl, group_col){
  group_col <- enquo(group_col)
  with_rownums <- tbl %>%
    group_by(!!group_col) %>%
    mutate(row = row_number())
  rows_to_keep <- with_rownums %>%
    filter(row != max(row)) %>%
    sample_n(1) %>%
    mutate(row2 = row + 1) %>%
    gather(key, row, row, row2)
  with_rownums %>%
    semi_join(rows_to_keep, by = c(quo_name(quo(!!group_col)), "row")) %>%
    arrange(!!group_col, row) %>%
    ungroup() # %>%
  # select(-row)
}
sample_2_consecutive(Dat, IndIDII)
#> # A tibble: 6 x 5
#>   IndIDII IndYear      WintLat WintLong   row
#>   <chr>   <chr>          <dbl>    <dbl> <int>
#> 1 BHS_265 BHS_265-2015    47.6    -113.     1
#> 2 BHS_265 BHS_265-2016    47.6    -113.     2
#> 3 BHS_377 BHS_377-2017    43.4    -109.     3
#> 4 BHS_377 BHS_377-2018    43.3    -109.     4
#> 5 BHS_770 BHS_770-2016    43.0    -109.     1
#> 6 BHS_770 BHS_770-2017    43.0    -109.     2

Создано в 2018-09-27 пакетом представлением (v0.2.0).

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

Вы можете использовать ave.Внутри каждой группы создайте индекс строки (i <- seq_along(x)).Чтобы получить первый индекс строк для сохранения, выберите одну строку из всех, кроме индекса последней строки (sample(head(i, -1), 1). Включите также следующую строку (+ 0:1). Проверьте, какие индексы строк находятся в выборочных строках (i %in% ...)Приведите результат обратно к логическому подмножеству данных.

Dat[as.logical(ave(Dat$IndIDII, Dat$IndIDII, FUN = function(x){
  i <- seq_along(x)
  i %in% (sample(head(i, -1), 1) + 0:1)
})), ]

#   IndIDII      IndYear  WintLat  WintLong
# 1 BHS_265 BHS_265-2015 47.61025 -112.7210
# 2 BHS_265 BHS_265-2016 47.59884 -112.7089
# 4 BHS_770 BHS_770-2017 42.97129 -109.0367
# 5 BHS_770 BHS_770-2018 42.97244 -109.0509
# 7 BHS_377 BHS_377-2016 43.35559 -109.4445
# 8 BHS_377 BHS_377-2017 43.35195 -109.4566

Аналогичным образом, но более кратким, с data.table и встроенным индексом строк (.I) и количеством строк в группе (.N)

library(data.table)
setDT(Dat)
Dat[Dat[ , (sample(.I[-.N], 1)) + 0:1, by = IndIDII]$V1]
0 голосов
/ 28 сентября 2018

Вот решение с использованием базовых функций R

> set.seed(505) # you can set whatever seed you want, I set 505 for reproducibility
> lapply(split(Dat, Dat$IndIDII), function(x) {
  ind <- sample(nrow(x))
  cons <- if(ind[1] < max(ind)){
    c(ind[1], ind[1]+1)
  } else {
    c(ind[1], ind[1]-1)
    }
  x[cons, ]
})

$`BHS_265`
  IndIDII      IndYear  WintLat  WintLong
1 BHS_265 BHS_265-2015 47.61025 -112.7210
2 BHS_265 BHS_265-2016 47.59884 -112.7089

$BHS_377
  IndIDII      IndYear  WintLat  WintLong
6 BHS_377 BHS_377-2015 43.34744 -109.4821
7 BHS_377 BHS_377-2016 43.35559 -109.4445

$BHS_770
  IndIDII      IndYear  WintLat  WintLong
3 BHS_770 BHS_770-2016 42.97379 -109.0400
4 BHS_770 BHS_770-2017 42.97129 -109.0367
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...