Как быстро подсчитать количество уникальных записей после объединения таблиц

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

У меня есть две таблицы, и я хотел бы объединить их на основе type, class и того, находится ли number между min_number и max_number. Затем я хотел бы создать новую переменную nMatch, в которой будет храниться количество уникальных id2, соответствующих каждому id1.

setindexv(table2, c("type", "class"))
for (t1_row in seq_len(nrow(table1))) {
  print(t1_row)
  set(
    table1, t1_row, "matches",
    table2[table1[t1_row], on = c("type", "class", "max_number >= number", "min_number <= number"), .(list(id2))]
  )
}
> table1[, .(nMatch = uniqueN(unlist(matches), na.rm = TRUE)), by = .(id1)]
    id1 nMatch
1: 1324      2
2: 2324      3
3:   29      1
4: 1010      3

Вышеприведенный подход — построчный, как предложено здесь, но в моем реальном наборе данных миллионы строк. Какой другой способ сделать это быстрее?

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
69
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете попробовать data.table с on = .(...) объединить две таблицы данных.

table1[
  table2,
  .(id1, id2),
  on = .(type, class, number >= min_number, number <= max_number),
  nomatch = NULL
][
  ,
  .(nMatch = uniqueN(id2)),
  id1
]

и получит

    id1 nMatch
1: 1324      2
2: 1010      3
3: 2324      3
4:   29      1

@Henrik Спасибо за ваш отзыв! Да, ты прав. Кажется, я переусердствовал с вопросом. Ответ обновлен!

ThomasIsCoding 13.11.2022 20:34

Вариант с tidyverse

library(dplyr)
library(tidyr)
left_join(table1, table2, by = 
   join_by(type, class, number >= min_number, number <= max_number)) %>% 
  distinct(id1, id2) %>%
  drop_na %>%
  count(id1, name = "nMatch")

-вывод

     id1 nMatch
   <num>  <int>
1:    29      1
2:  1010      3
3:  1324      2
4:  2324      3

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