#r #data.table #non-equi-join
#r #данные.таблица #неравнозначное соединение
Вопрос:
У меня есть некоторые данные в таблице, и я хотел бы выполнить неравномерное объединение (я думаю, это правильная терминология) и отфильтровать их по разным диапазонам для разных групп. В приведенном ниже примере я хотел бы отфильтровать группу «а», чтобы она возвращала значения только от 1 до 20 (включительно), и группу «в», чтобы она возвращала значения только от 80 до 100 (включительно). Мое чтение предполагает, что inrange
это должен быть предмет для использования. Я понимаю, как использовать его в общем случае, но я не уверен, как заставить его работать с разными диапазонами по группам. (пример кода, адаптированного из ?inrange
)
создание образцов данных
set.seed(1234) Y = data.table(a=sample(1:100,100), val=runif(100), group=c(rep("a",50),rep("b",50))) range = data.table(group=c("a","b"),start = c(1,80), end = c(20,100))
Попробуйте отфильтровать
Y[inrange(a, range$start, range$end),,by=group]
Это, очевидно, не работает и вместо этого применяет эти диапазоны ко всему набору данных и выдает сообщение об ошибке Ignoring by= because j= is not supplied
. Я думаю, мне ясно, что это не работает, потому что я не создал «соединение» между таблицей диапазонов и Y, но я не вижу, как заставить две таблицы взаимодействовать группировкой через inrange
.
Примечание: На самом деле значениями в a будут даты posixct, но для простоты я здесь это не использую.
Комментарии:
1. Вы понимаете, что
runif
это взято из[0,1]
иrange
, похоже, включено[0,100]
?2.
val
это просто дополнительный столбец для аппроксимации реальных данных (есть дополнительные столбцы, которые есть в пути). Фильтрация должна быть включенаa
. Я не вижу в этом проблемы.3. О, я пропустил вступление
a
, это кажется ясным (и очевидным), моя ошибка 🙂
Ответ №1:
Возможно:
Y[range, K := TRUE, on = .(group, a gt;= start, a lt;= end)][!is.na(K),] # a val group K # lt;intgt; lt;numgt; lt;chargt; lt;lgclgt; # 1: 9 0.60189755 a TRUE # 2: 5 0.99874081 a TRUE # 3: 16 0.55512663 a TRUE # 4: 4 0.42944396 a TRUE # 5: 14 0.43101637 a TRUE # 6: 3 0.47880269 a TRUE # 7: 2 0.02220682 a TRUE # 8: 6 0.63891131 a TRUE # 9: 8 0.83470266 a TRUE # 10: 17 0.98304402 a TRUE # 11: 98 0.76785547 b TRUE # 12: 94 0.30766574 b TRUE # 13: 88 0.25814665 b TRUE # 14: 89 0.49954639 b TRUE # 15: 83 0.50892062 b TRUE # 16: 95 0.49443856 b TRUE # 17: 97 0.56695890 b TRUE # 18: 87 0.98970989 b TRUE # 19: 82 0.53190509 b TRUE # 20: 100 0.59662376 b TRUE # a val group K
Есть и другие способы сделать это, но они включают переименование или потерю информации. Например,
- влево-присоединяйтесь
range
, иY
мы проиграемa
:Y[range, on = .(group, a gt;= start, a lt;= end)] # a val group a.1 # lt;intgt; lt;numgt; lt;chargt; lt;intgt; # 1: 1 0.60189755 a 20 # 2: 1 0.99874081 a 20 # 3: 1 0.55512663 a 20 # ... # 18: 80 0.98970989 b 100 # 19: 80 0.53190509 b 100 # 20: 80 0.59662376 b 100 # a val group a.1
Исправление состоит в том, чтобы скопировать
Y$a
в новую переменную и вместо этого присоединиться к ней:Y[,a1 := a][range, on = .(group, a1 gt;= start, a1 lt;= end)] # a val group a1 a1.1 # lt;intgt; lt;numgt; lt;chargt; lt;intgt; lt;intgt; # 1: 9 0.60189755 a 1 20 # 2: 5 0.99874081 a 1 20 # 3: 16 0.55512663 a 1 20 # ... # 18: 87 0.98970989 b 80 100 # 19: 82 0.53190509 b 80 100 # 20: 100 0.59662376 b 80 100 # a val group a1 a1.1
- левое соединение
Y
иrange
, мыa
дублируемся вstart
иend
, но нет четкого индикатора для фильтрации:range[Y, on = .(group, start lt;= a, end gt;= a)] # group start end val # lt;chargt; lt;intgt; lt;intgt; lt;numgt; # 1: a 28 28 0.85026492 # 2: a 80 80 0.23466126 # 3: a 22 22 0.98816745 # ... # 98: b 82 82 0.53190509 # 99: b 100 100 0.59662376 # 100: b 30 30 0.26388647 # group start end val
Решением было бы скопировать в другое поле, которое дало бы нам индикатор слияния, который нам нужно отфильтровать. Но даже при этом мы должны переименовать, чтобы восстановить
a
данные:range[, K := TRUE][Y, on = .(group, start lt;= a, end gt;= a)][ !is.na(K), ] # group start end K val # lt;chargt; lt;intgt; lt;intgt; lt;lgclgt; lt;numgt; # 1: a 9 9 TRUE 0.60189755 # 2: a 5 5 TRUE 0.99874081 # 3: a 16 16 TRUE 0.55512663 # ... # 18: b 87 87 TRUE 0.98970989 # 19: b 82 82 TRUE 0.53190509 # 20: b 100 100 TRUE 0.59662376 # group start end K val
Комментарии:
1. Мне это нравится. Необходимость добавлять K кажется как-то неэлегантной, но это работает, мне просто нужно будет удалить ее позже. Я оставлю это открытым до завтра, чтобы посмотреть, есть ли какие-либо другие решения data.table для этого. Спасибо!
2. Я согласен с кажущейся неэлегантностью этого, но внутренние предположения о том, какие столбцы следует сохранить, а какие переименовать, не всегда очевидны для меня. (Очевидно , просто добавьте
[, K := NULL]
в конец, чтобы избавиться отK
этого, я тоже хотел бы, чтобы в этом не было необходимости.) Потребность аналогичнаY[,a1 := a][range, on = .(group, a1 gt;= start, a1 lt;= end)]
той , для которой требуется очистка[, c("a1","a1.1"):=NULL]
. В любом случае… уборка.