Назначьте интервалы / ячейки по группам в data.table - PullRequest
1 голос
/ 07 мая 2019

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

#require(data.table)
#fake data
set.seed(12345)
df1 <- data.frame(id_f=c(rep("a a",100),rep("b b",100),rep("c c",100)), 
                   L=c(abs(rnorm(100,50,20)),abs(rnorm(100,90,20)),abs(rnorm(100,220,20))), 
                   w=abs(rnorm(300,6,3))) 
dt2 = as.data.table(df1)

#the offending data.table function
dt2[,"bins":= findInterval(L, c((max(L)-min(L))/10*c(1:9)),left.open=T)+1, by=id_f]

РЕДАКТИРОВАТЬ:

В столбце "aa" будет 10 одинаково разнесенных интервалов по всему диапазону "aa", и номер ячейки будет назначен дляКаждое из исходных наблюдений, так как реальные данные имеют 6000 наблюдений, в каждой ячейке есть несколько членов.Таким образом, результат будет примерно таким: (ради краткости это пример с тремя интервалами)

id_f  L    w     bins
a a   1    1.0   1
a a   2    1.1   2
a a   3    5.0   3
b b   3    2.0   1
b b   6    3.5   2
b b   9    7.0   3
c c   10   1.0   1
c c   15   1.5   2
c c   20   6.0   3

Я бы подумал, что мой вызов findInterval достиг бы этого, но ясно, что этовзятие min и max из глобального набора данных, а не только из группы.Как заставить его получить min и max из группы, а затем использовать его для вычисления интервала, используемого для этой группы?

Ответы [ 2 ]

1 голос
/ 07 мая 2019

Я думаю, что использовать cut было бы намного проще, указав число breaks, которое мы хотим

library(data.table)
setDT(dt2)[,"bins":= cut(L, breaks = 10, labels = 1:10), by=id_f]

dt2
#     id_f     L     w bins
#  1:  a a  71.5  2.96    8
#  2:  a a  49.5  3.63    5
#  3:  a a  49.3  6.90    5
#  4:  a a  19.7 10.92    2
#  5:  a a  65.8  9.25    7
# ---                      
#296:  c c 206.0  6.50    4
#297:  c c 224.8  4.04    6
#298:  c c 213.0 10.36    5
#299:  c c 227.4  3.58    6
#300:  c c 224.9  7.12    6

Мы можем сделать это также в dplyr или базе R

library(dplyr)

dt2 %>%
  group_by(id_f) %>%
  mutate(bins = cut(L, breaks = 10, labels = 1:10))

ИЛИ

with(dt2, ave(L, id_f, FUN = function(x) cut(x, breaks = 10, labels = 1:10)))
0 голосов
/ 07 мая 2019

Вам нужно будет запустить табличные функции, чтобы продемонстрировать проблему.by -операция, кажется, "работает"

    > dt2[ , list(mn=min(L), mx=max(L) ), by=id_f]
   id_f         mn       mx
1:  a a   5.462025 104.2456
2:  b b  43.824476 138.4843
3:  c c 168.075002 276.5598
> dt2[ , table(id_f, bins)]
     bins
id_f    1   2   3   4   5   6   7   8   9  10
  a a   3   5  10  10  19  13  21  10   4   5
  b b   0   0   0   0   1   3  10   8  19  59
  c c   0   0   0   0   0   0   0   0   0 100

Очевидно, что ваши результаты будут отличаться, так как вы не использовали set.seed()

png(); par(mfrow=c(3,1)); tapply(df1$L, df1$id_f, hist); dev.off()

enter image description here

...