Присоединяйтесь к таблицам данных, используя имена столбцов, хранящиеся в переменных

У меня есть 2 data.tables:

library(data.table)
dt1 <- data.table(id = 1:5, value1 = 11:15, value2 = 21:25, value3 = 36:40)
dt2 <- data.table(name = c("value1", "value1", "value1", "value1", 
                            "value2", "value2", "value2", "value3", "value3"), 
              valueMin = c(10, 13, 14, 18, 21, 24, 25, 36, 38), 
              valueMax = c(13, 14, 18, 20, 24, 25, 27, 38, 42), 
              label = c(101:104, 201:203, 301:302))
> dt1
   id value1 value2 value3
1:  1     11     21     36
2:  2     12     22     37
3:  3     13     23     38
4:  4     14     24     39
5:  5     15     25     40
> dt2
     name valueMin valueMax label
1: value1       10       13   101
2: value1       13       14   102
3: value1       14       18   103
4: value1       18       20   104
5: value2       21       24   201
6: value2       24       25   202
7: value2       25       27   203
8: value3       36       38   301
9: value3       38       42   302

Результат, который я ожидаю, будет следующим: присоединение метки от dt2 к dt1 в силу того факта, что value1 в dt1 находится между valueMin и valueMax в dt2, а dt2$name совпадает с value1). Вот решение, которое у меня есть (дает правильный результат):

varName <- "value1"
dt2_temp <- dt2[name == varName,]
dt1[dt2_temp, on = .(value1 > valueMin, value1 <= valueMax), nomatch = 0] %>%
select(id, label)
   id label
   1:  1   101
   2:  2   101
   3:  3   101
   4:  4   102
   5:  5   103

Я хотел бы сделать то же самое (получить столбцы label) для всех остальных столбцов (value2, value3) в dt1 (используя цикл), поэтому необходимо заменить ссылку на имя столбца value1 в соединении с его именем, хранящимся в varName, примерно так:

dt1[dt2_temp, on = .(varName > valueMin, varName <= valueMax), nomatch = 0]

К сожалению, у меня не получилось использовать: просто varName, eval(varName), as.name(varName). У тебя есть идеи, как это решить?

Сообщение об ошибке похоже на:

Error in `[.data.table`(dt1, dt2_temp, on = .(varName > valueMin, varName <= valueMax),  : 
  Column(s) [varName,varName] not found in x
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
14
0
977
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

Почему бы не сделать все сразу без цикла?

Возможное решение:

melt(dt1, id = 1)[dt2, on = .(variable = name, value > valueMin, value <= valueMax), lbl := i.label
                  ][, dcast(.SD, id ~ variable, value.var = c("value","lbl"))]

который дает:

   id value_value1 value_value2 value_value3 lbl_value1 lbl_value2 lbl_value3
1:  1           11           21           36        101         NA         NA
2:  2           12           22           37        101        201        301
3:  3           13           23           38        101        201        301
4:  4           14           24           39        102        201        302
5:  5           15           25           40        103        202        302
melt(dt1,1)[dt2, on = .(value> valueMin, value <= valueMax,variable=name), nomatch = 0]

   id variable value value.1 label
 1:  1   value1    10      13   101
 2:  2   value1    10      13   101
 3:  3   value1    10      13   101
 4:  4   value1    13      14   102
 5:  5   value1    14      18   103
 6:  2   value2    21      24   201
 7:  3   value2    21      24   201
 8:  4   value2    21      24   201
 9:  5   value2    24      25   202
10:  2   value3    36      38   301
11:  3   value3    36      38   301
12:  4   value3    38      42   302
13:  5   value3    38      42   302

вы не присоединяетесь правильно, вам также необходимо принять во внимание ценность ...

Jaap 05.07.2018 11:02

@Jaap конечно уверен. Спасибо

Onyambu 05.07.2018 11:04

Один из подходов мог бы быть

library(data.table)

dcast(dt2[melt(dt1, id.vars = 1),    #left join of long form of dt1 and original dt2
          .( id, variable, label),   #only keep concerned columns from merged table
          on = .(name = variable,  valueMax >= value, valueMin < value)],  #join conditions
      id ~ variable, 
      value.var = "label")           #long to wide format using dcast to get the final result

который дает

   id value1 value2 value3
1:  1    101     NA     NA
2:  2    101    201    301
3:  3    101    201    301
4:  4    102    201    302
5:  5    103    202    302

вам нужен valueMax >= value вместо valueMax > value

Jaap 05.07.2018 10:57

О да! Спасибо @Jaap за его выделение.

1.618 05.07.2018 12:17

Публикация другого метода, который программно создает строку on (см. Аргумент on в ?data.table)

dt1[dt2_temp, 
    on=c(paste0(varName, ">valueMin"), paste0(varName, "<=valueMax")),
    nomatch=0L]

Обратите внимание, что вокруг имен переменных не должно быть пробелов.

Со смесью tidyverse и fuzzyjoin:

library(tidyverse)
library(fuzzyjoin)

dt2 %>% fuzzy_inner_join(
  gather(dt1,name, value,-1),
  by=c("name",valueMin = "value",valueMax = "value"),
  list(function(x,y) x == y,
       function(x,y) x < y,
       function(x,y) x >= y)) %>%
  select(id,name.x,label) %>%
  distinct %>%
  spread(name.x,label)

#    id value1 value2 value3
# 1:  1    101     NA     NA
# 2:  2    101    201    301
# 3:  3    101    201    301
# 4:  4    102    201    302
# 5:  5    103    202    302

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