общая функция обновления фрейма данных с tidyverse dplyr, например sql-update

Я ищу общую функцию обновления фрейма данных, такую ​​как sql-update, которая обновляет значения в первом фрейме данных, если ключи совпадают с ключами во втором фрейме данных. Есть ли более общий способ, как в моем примере, возможно, также с учетом имен значений? Что-то вроде универсальной функции dplyr :: update (df1, df2, by = "key")?

library(tidyverse)
# example data frame
df1 <- as_data_frame(list(key = c(1,2,3,4,5,6,7,8,9),
                          v1 = c(11,12,13,14,15,16,17,18,19),
                          v2 = c(21,22,23,24,25,26,27,28,29),
                          v3 = c(31,32,33,34,35,36,37,38,39),
                          v4 = c(41,42,43,44,45,46,47,48,49)))
df2 <- as_data_frame(list(key = c(3,5,9),
                          v2 = c(231,252,293),
                          v4 = c(424,455,496)))

# update df1 with values from df2 where key match
org_names <- df1 %>% names()
df1 <- df1 %>% 
  left_join(df2, by = "key") %>% 
  mutate(v2 = ifelse(is.na(v2.y), v2.x, v2.y),
         v4 = ifelse(is.na(v4.y), v4.x, v4.y)) %>% 
  select(org_names)

> df1
# A tibble: 9 x 5
key    v1    v2    v3    v4
<dbl> <dbl> <dbl> <dbl> <dbl>
1     1    11    21    31    41
2     2    12    22    32    42
3     3    13   231    33   424
4     4    14    24    34    44
5     5    15   252    35   455
6     6    16    26    36    46
7     7    17    27    37    47
8     8    18    28    38    48
9     9    19   293    39   496
> 

person Guido Berning    schedule 16.11.2017    source источник
comment
Я ничего не знаю. Однако есть dplyr::db_write_table, у которого есть аргумент для создания временной таблицы, и DBI::dbExecute, который вы можете использовать для выполнения обновления с использованием вновь созданной временной таблицы.   -  person crazybilly    schedule 16.11.2017
comment
Я также нашел похожий вопрос stackoverflow.com/ вопросы / 45217477 / с ответом для использования data.table   -  person Guido Berning    schedule 16.11.2017
comment
Ах, я неправильно понял ваш вопрос о внесении обновлений в базу данных SQL - вы просто хотите отредактировать объект локального фрейма данных, верно?   -  person crazybilly    schedule 16.11.2017


Ответы (1)


1)% ‹>% Magrittr имеет составную трубу назначения:

library(magrittr)

df1 %>% 
    { keys <- intersect(.$key, df2$key)
    .[match(keys, .$key), names(df2)] %<>% { df2[match(keys, df2$key), ] }
    .
}

что для рассматриваемой проблемы упрощается до этого, потому что все ключи в df2 находятся в df1:

df1 %>% { .[match(df2$key, .$key), names(df2)]  %<>% { df2 }; . }

2) ‹- Базовый оператор присваивания R также может использоваться почти таким же образом, и на самом деле его код короче, чем (1):

df1 %>% 
    { keys <- intersect(.$key, df2$key)
    .[match(keys, .$key), names(df2)] <- df2[match(keys, df2$key), ]
    .
}

однако для рассматриваемой проблемы все ключи в df2 находятся в df1, поэтому упрощается:

df1 %>% { .[match(df2$key, .$key), names(df2)] <- df2; . }

3) mutate_cond с использованием mutate_cond, определенного в в этом SO post мы можем написать следующее.

df1 %>% mutate_cond(.$key %in% df2$key, v2 = df2$v2, v4 = df2$v4)

Примечание. Первые два подхода работают, если ключи в df1 и df2 уникальны. Третий дополнительно требует, чтобы ключи были в том же порядке, и каждый ключ в df2 был в df1. Проблема в вопросе их удовлетворяет.

Обновление: несколько обобщили код в (1) и (2).

person G. Grothendieck    schedule 16.11.2017