Разделение фрейма данных на границе непрерывной переменной и выполнение вычислений с обеих сторон - PullRequest
1 голос
/ 30 мая 2011

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

set.seed(1)
tdata <- data.frame(a1=rnorm(100, mean=5, sd=2), a2=rep(0:1, length.out=100))
tall <- sapply(1:9, function(x) {
  d <- split(tdata, tdata$a1 <= x)
  sapply(d, function (y) {
    1 - max(table(y$a2)/nrow(y))
  })
})

Мой результат:

> allErr
           [,1]      [,2]      [,3]      [,4]      [,5]      [,6]      [,7]
FALSE 0.4949495 0.4895833 0.4943820 0.4933333 0.4444444 0.4411765 0.3333333
TRUE  0.0000000 0.2500000 0.4545455 0.4800000 0.4347826 0.4696970 0.4705882
      [,8] [,9]
FALSE  0.5  0.5
TRUE   0.5  0.5

Моя непрерывная переменная tdata$a1, и я хочу каждый раз разбивать фрейм данных на 2, используя граничное значение из 1:9, выполните вычисление a2 для каждой части разбиения и верните его обратно.

Мой вопрос здесь: каков наилучший способ сделать это с точки зрения элегантности (смотрел на решение plyr, но не могу избежать использования первого sapply) и, что более важно, правильно использовал другие функции R, которые яможет не знатьЯ также боюсь, что мое решение не будет так хорошо масштабироваться с гораздо большими фреймами данных, чем те, что у меня есть в настоящее время (~ 10000 строк).

Ответы [ 2 ]

3 голосов
/ 30 мая 2011

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

set.seed(1)
tdata <- data.frame(a1=rnorm(100, mean=5, sd=2), a2=rep(0:1, length.out=100))
tall <- sapply(1:9, function(x) {
         d <- split(seq_along(tdata$a2), tdata$a1 <= x)
         sapply(d, function (y) {
          1 - max(table(tdata$a2[y])/length(y))
         })
        })

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

1 голос
/ 30 мая 2011

Также не уверен насчет элегантности, но выделите внутреннюю функцию как fun0a и шаблон 'split-lapply' как tsplit, и тогда вся итерация будет

fun0a <- function(x, ...)
    1 - max(table(x) / length(x))
tsplit <- function(thresh, x, splt, fun, ...)
    lapply(split(x, splt <= thresh), fun, ...)
sapply(1:9, tsplit, data$a2, tdata$a1, fun0a)

Это используетвнутренний lapply вместо sapply и разделяет один столбец данных напрямую, а не через индекс или весь фрейм данных.tsplit и внешнее саппло может быть повторно использовано в аналогичных ситуациях, например, когда внутренняя функция фактически зависит от фрейма данных, передайте индексы (вычисленные один раз во внешнем саппли) вместо значений

fun0b <- function(i, df, ...)
    1 - max(table(df[i,"a2"]) / length(i))
with(tdata,
     sapply(1:9, tsplit, seq_along(a1), a1, fun0b, tdata))

tsplit является tapply, поэтому может быть реализовано как

tsplit <- function(thresh, x, splt, fun, ...)
    tapply(x, splt <= thresh, fun, ...)
...