Как условно обновить табличку R, используя несколько условий другой таблички

У меня есть две таблицы. Я хотел бы обновить первую таблицу, используя вторую таблицу, используя несколько условий. В базе R я бы использовал конструкции типа if...else для этого, но хотел бы знать, как этого добиться с помощью dplyr.

Таблица, которую нужно обновить (добавить поле), выглядит так:

> Intvs
# A tibble: 12 x 3
   Group  From    To
   <chr> <dbl> <dbl>
 1 A         0     1
 2 A         1     2
 3 A         2     3
 4 A         3     4
 5 A         4     5
 6 A         5     6
 7 B         0     1
 8 B         1     2
 9 B         2     3
10 B         3     4
11 B         4     5
12 B         5     6

Таблица, которую я хотел бы использовать для обновления, выглядит так:

 >Zns
# A tibble: 2 x 4
  Group From     To  Zone
  <chr> <chr> <dbl> <dbl>
1 A     X         1     5
2 B     Y         3     4

Я хотел бы обновить табличку Intvs с помощью таблички Zns, используя поля == Group, >= From и <= To для управления обновлением. Ожидаемый результат должен выглядеть так

> Intvs
# A tibble: 12 x 4
   Group  From    To  Zone
   <chr> <dbl> <dbl> <chr>
 1 A         0     1  NA
 2 A         1     2  X
 3 A         2     3  X
 4 A         3     4  X
 5 A         4     5  X
 6 A         5     6  NA
 7 B         0     1  NA
 8 B         1     2  NA
 9 B         2     3  NA
10 B         3     4  Y
11 B         4     5  NA
12 B         5     6  NA

Каков наиболее эффективный способ сделать это с помощью dplyr?

Приведенный ниже код должен создать фиктивные таблицы Intv и Zns.

# load packages
require(tidyverse)

# Intervals table
a <- c(rep("A", 6), rep("B", 6))
b <- c(seq(0,5,1), seq(0,5,1) )
c <- c(seq(1,6,1), seq(1,6,1))
Intvs <- bind_cols(a, b, c) 
names(Intvs) <- c("Group", "From", "To")

# Zones table
a <- c("A", "B")
b <- c("X", "Y")
c <- c(1, 3)
d <- c(5, 4)
Zns <- bind_cols(a, b, c, d) 
names(Zns) <- c("Group", "From", "To", "Zone")

Я думаю, что данные примера могут быть неверными. Вы хотите сравнить From и To в обоих наборах данных, но From — это число в Intvs и буква в Zns.

DaveArmstrong 23.04.2022 14:26

Дэйв, спасибо, что указали на эту ошибку... Теперь я исправил эту проблему.

Markm0705 24.04.2022 02:00
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
1
2
38
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это самое близкое, что я получаю. Это не дает ожидаемого результата:

library(dplyr)
left_join(Intvs, Zns, by="Group") %>% 
  group_by(Group) %>% 
  mutate(Zone1 = case_when(From.x <= Zone & From.x >= To.y ~ From.y)) %>% 
  select(Group, From=From.x, To=To.x, Zone = Zone1)
   Group  From    To Zone 
   <chr> <dbl> <dbl> <chr>
 1 A         0     1 NA   
 2 A         1     2 X    
 3 A         2     3 X    
 4 A         3     4 X    
 5 A         4     5 X    
 6 A         5     6 X    
 7 B         0     1 NA   
 8 B         1     2 NA   
 9 B         2     3 NA   
10 B         3     4 Y    
11 B         4     5 Y    
12 B         5     6 NA 

Не уверен, почему ваша первая строка не дает NA, так как 0 - 1 не находится в диапазоне 1 - 5.

Сначала left_join два фрейма данных, используя столбец Group. Здесь я присваиваю суффикс «_Zns» значениям из кадра данных Zns. Затем используйте один оператор case_when или (ifelse), чтобы присвоить NA строкам, которые не соответствуют диапазону. Наконец, удалите столбцы, которые заканчиваются на Zns.

library(dplyr)

left_join(Intvs, Zns, by = "Group", suffix = c("", "_Zns")) %>% 
  mutate(Zone = case_when(From >= From_Zns & To <= To_Zns ~ Zone,
                           TRUE ~ NA_character_)) %>% 
  select(-ends_with("Zns"))

# A tibble: 12 × 4
   Group  From    To Zone 
   <chr> <dbl> <dbl> <chr>
 1 A         0     1 NA   
 2 A         1     2 X    
 3 A         2     3 X    
 4 A         3     4 X    
 5 A         4     5 X    
 6 A         5     6 NA   
 7 B         0     1 NA   
 8 B         1     2 NA   
 9 B         2     3 NA   
10 B         3     4 Y    
11 B         4     5 NA   
12 B         5     6 NA   

Данные

Обратите внимание, что я изменил порядок имен столбцов в фрейме данных Zns.

a <- c(rep("A", 6), rep("B", 6))
b <- c(seq(0,5,1), seq(0,5,1) )
c <- c(seq(1,6,1), seq(1,6,1))
Intvs <- bind_cols(a, b, c) 
names(Intvs) <- c("Group", "From", "To")

# Zones table
a <- c("A", "B")
b <- c("X", "Y")
c <- c(1, 3)
d <- c(5, 4)
Zns <- bind_cols(a, b, c, d)
colnames(Zns) <- c("Group", "Zone", "From", "To")

Спасибо, что указали на ошибку в примере вопроса... Я не исправил вопрос, поэтому он согласуется с вашим правильным ответом.

Markm0705 24.04.2022 02:01
Ответ принят как подходящий

Использование неэквивалентного соединения из data.table

library(data.table)
setDT(Intvs)[Zns, Zone := Zone, on = .(Group, From >= From, To <= To)]

-выход

> Intvs
     Group  From    To   Zone
    <char> <num> <num> <char>
 1:      A     0     1   <NA>
 2:      A     1     2      X
 3:      A     2     3      X
 4:      A     3     4      X
 5:      A     4     5      X
 6:      A     5     6   <NA>
 7:      B     0     1   <NA>
 8:      B     1     2   <NA>
 9:      B     2     3   <NA>
10:      B     3     4      Y
11:      B     4     5   <NA>
12:      B     5     6   <NA>

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