Как объединить две таблицы, а затем свести подсчеты за один шаг, используя data.table

library(data.table)
table1 <- data.table(id1 = c(1324, 2324, 29, 29, 1010, 1010),
                     type = c(1, 1, 2, 1, 1, 1),
                     class = c("A",  "A", "B", "D", "D", "A"),
                     number = c(1, 98, 100, 100, 70, 70))
table2 <- data.table(id2 = c(1998, 1998, 2000, 2000, 2000, 2010, 2012, 2012),
                     type = c(1, 1, 3, 1, 1, 5, 1, 1),
                     class = c("D", "A", "D", "D", "A", "B", "A", "A"),
                     min_number = c(34, 0, 20, 45, 5, 23, 1, 1),
                     max_number = c(50, 100, 100, 100, 100, 9, 10, 100))
> table1
    id1 type class number
1: 1324    1     A      1
2: 2324    1     A     98
3:   29    2     B    100
4:   29    1     D    100
5: 1010    1     D     70
6: 1010    1     A     70
> table2
    id2 type class min_number max_number
1: 1998    1     D         34         50
2: 1998    1     A          0        100
3: 2000    3     D         20        100
4: 2000    1     D         45        100
5: 2000    1     A          5        100
6: 2010    5     B         23          9
7: 2012    1     A          1         10
8: 2012    1     A          1        100

Шаг 1. У меня есть две таблицы, и я хочу объединить их на основе type, class и того, находится ли number между min_number и max_number.

merged <- table2[table1, on = c("type", "class", "max_number >= number", "min_number <= number")]
> merged
     id2 type class min_number max_number  id1
 1: 1998    1     A          1          1 1324
 2: 2012    1     A          1          1 1324
 3: 2012    1     A          1          1 1324
 4: 1998    1     A         98         98 2324
 5: 2000    1     A         98         98 2324
 6: 2012    1     A         98         98 2324
 7:   NA    2     B        100        100   29
 8: 2000    1     D        100        100   29
 9: 2000    1     D         70         70 1010
10: 1998    1     A         70         70 1010
11: 2000    1     A         70         70 1010
12: 2012    1     A         70         70 1010

Шаг 2. Затем для каждого class я хотел бы подсчитать, сколько уникальных id1 есть и сколько уникальных id2 есть. Окончательный желаемый результат таков:

library(dplyr)
count_merged <- merged %>% group_by(class) %>% 
  summarise(n_id2 = n_distinct(id2[!is.na(id2)]),
            n_id1 = n_distinct(id1))
> count_merged
# A tibble: 3 × 3
  class n_id2 n_id1
  <chr> <int> <int>
1 A         3     3
2 B         0     1
3 D         1     2

Мой вопрос: есть ли более быстрый способ сделать это? Если table1 и table2 содержат сотни тысяч строк, то объединение двух таблиц на шаге 1 происходит очень медленно. Есть ли способ получить подсчеты без объединения?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

С data.table::uniqueN:

merged[,.(nid2=uniqueN(id2,na.rm=T),nid1=uniqueN(id1)),class]

#    class  nid2  nid1
#   <char> <int> <int>
#1:      A     3     3
#2:      B     0     1
#3:      D     1     2

Сравнение производительности:

Unit: microseconds
  expr    min      lq     mean  median      uq     max neval
 dplyr 5249.1 5955.15 8626.139 6381.50 8118.95 79625.4   100
    dt  675.3  876.75 1122.979  981.65 1297.50  2649.8   100

Спасибо. Есть ли способ избежать объединения двух таблиц и получить подсчет напрямую? У меня проблема в том, что я даже не могу получить таблицу merged, потому что мои table1 и table2 очень большие (много строк).

Adrian 17.11.2022 07:18

Я упустил из виду проблему слияния;). Я не вижу простого пути, кроме запуска с большим объемом оперативной памяти.

Waldi 17.11.2022 07:23
Ответ принят как подходящий

Вот чистый data.table вариант

table2[
  table1,
  on = c("type", "class", "max_number >= number", "min_number <= number"),
  mult = "first"
][,
  lapply(.SD, uniqueN, na.rm = TRUE),
  class,
  .SDcols = patterns("^id")
]

который дает

   class id2 id1
1:     A   1   3
2:     B   0   1
3:     D   1   2

Другие вопросы по теме