Как выбрать n значений в случайном порядке, ближайших к значению y, если данные не являются непрерывными? - PullRequest
2 голосов
/ 17 октября 2010

У меня есть набор данных, который включает в себя список видов, их количество и количество дней с момента начала съемки. Поскольку многие дни не были выбраны, день не является непрерывным. Так, например, в день 5,6,9,10,15,34,39 и т.д. могут быть птицы. Я установил самую раннюю дату на день 0.

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

species     counts      day
Blue tit    234         0
Blue tit    24          5
Blue tit    45          6
Blue tit    32          9
Blue tit    6           10
Blue tit    98          15
Blue tit    40          34
Blue tit    57          39
Blue tit    81          43
..................

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

Пример. Допустим, я случайно выбрал день 5 в качестве дня старта, интервал 30, а количество строк для выборки 2. Это означает, что я начну с 5, добавлю 30 к нему, и буду искать 2 строки около 35 дней (но не сам день 35). В этом случае я возьму два ряда, где день 34 и 39.

Затем я добавляю 30 к 35 и ищу две точки около 65. Промойте, повторяйте, пока я не доберусь до конца набора данных.

Я написал эту функцию для выполнения выборки, но у нее есть недостатки (см. Ниже):

resample <- function(x, ...) x[sample.int(length(x), ...)]
 locate_points<- function(dataz,l,n) #l is the interval, n is # points to sample. This is called by another function that specifies start time among other info.
{
   tlength=0
   i=1
    while(tlength<n)   
    {
        low=l-i
        high=l+i
        if(low<=min(dataz$day)) { low=min(dataz$day) }
        if(high>=max(dataz$day)) { high=max(dataz$day) }
        test=resample(dataz$day[dataz$day>low & dataz$day<high & dataz$day!=l])
          tlength=length(test)
         i=i+1
      } 
  test=sort(test)
  k=test[1:n]
 return (k)
 } 

Две проблемы, с которыми мне нужна помощь:

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

  2. Во-вторых, как мне получить действительные строки? Сейчас у меня есть другая функция, чтобы найти эти строки, используя which, а затем rbind, объединяя эти строки. Кажется, должен быть лучший способ.

спасибо!

Ответы [ 2 ]

3 голосов
/ 17 октября 2010

Понравилось решение Чарльза, которое отлично работает для случая n = 2. Увы, это не распространяется на большие окна. У него все еще есть проблема, описанная OP: при больших окнах выбор не центрируется вокруг значения поиска. Учитывая четность, я придумал следующее решение, в значительной степени основанное на идее Чарльза.

Функция контролирует границы. если есть 100 дней, а следующая средняя точка, скажем, второй последний день, окно 4 будет означать, что вы выберете индекс 101, который дает NA. Эта функция сдвигает окно, поэтому все выбранные индексы лежат в исходных данных. Это также имеет побочный эффект, заключающийся в том, что в зависимости от значений начала (st), длины (l) и оконного (n) значения начала и конца имеют более высокий шанс выбора дважды. Длина всегда должна быть как минимум вдвое больше размера окна.

Выводом функции являются индексы примера начальной загрузки. Его можно использовать как переменную Чарльза pos для векторов и фреймов данных.

bboot <- function(day,st,l,n){
  mid <- seq(st,max(day),by=l)
  x <-sort(setdiff(day,mid))
  lx <- length(x)

  id <- sapply(mid,
          function(y){
            m <- match(T,x>y)
            seq(
              from=min( lx-n, max(1,m+(-n/2)) ),
              to=min( lx, max(n,m+(n/2-1)) )
            )
          }
        )

  pos <- match(x[id],day)
  return(pos)
}

Тогда

>   day <- sample(1:100,50)
> sample.rownr <- bboot(day,10,20,6)
> sort(day)
 [1]  3  4  5  7  9 10 13 15 16 18 19 21 22 24 25 26 27 28 29 
[20] 30 31 32 35 36 38 40 45 49 51 52 54 55 58 59 62 65 69 72 73
[40] 74 80 84 87 88 91 92 94 97 98 99
> day[sample.rownr]
 [1]  5  7  9 13 15 16 27 28 29 31 32 35 40 45 49 51 52 54 62 
[20] 65 69 72 73 74 84 87 88 91 92 94
> 

edit: в отношении начальной загрузки для временных рядов, вы должны просмотреть обзор задач CRAN для временных рядов , особенно раздел о повторной выборке. Для нерегулярных временных рядов пакет zoo также предлагает ряд других функций, которые могут пригодиться.

1 голос
/ 17 октября 2010

Как что-то вроде следующего:

day = 1:1000

search = seq(from=5, to=max(day), by=30)
x = sort(setdiff(day, search))
pos = match(x[unlist(lapply(findInterval(search, x), seq, len=2))], day)

day[pos]

Чтобы получить строки из вашего data.frame, просто поместите его в подмножество:

rows = data[pos, ]

Возможно, это немного чище, чем комбинация unlist / lapply / seq:

pos = match(x[outer(c(0, 1), findInterval(search, x), `+`)], day)

Также обратите внимание, что если вам нужно окно большего размера (например, скажем, 4), достаточно просто вернуться назад:

pos = match(x[outer(-1:2, findInterval(search, x), `+`)], day)
...