dplyr mutate - Как правильно применять пользовательские функции с помощью mutate? - PullRequest
0 голосов
/ 17 октября 2018

Я пытаюсь перенести базу данных и хотел бы использовать R, чтобы помочь в этом процессе.В рамках процесса миграции мне нужно обновить «Идентификаторы элементов» по ​​мере их изменения.Я создал функцию для сопоставления старых идентификаторов с новыми:

old_to_new <- function(id, df) {
  return (df[which(df$Old == id), ]$New)
}

Однако всякий раз, когда я пытаюсь применить его, чтобы добавить новый столбец в моем фрейме данных (загруженный из таблицы базы данных):

library(tidyverse)
library(RODBC)

cn <- odbcDriverConnect(connection="Driver={SQL Server Native Client 11.0};server=xxx;database=xxx;uid=xxx;pwd=xxx;")
df <- sqlQuery(cn, "SELECT * FROM [MaintDB_New].[dbo].[Priority]")
ticket_df <- sqlQuery(cn, "SELECT * FROM [MaintDB_New].[dbo].[Tickets]")
ticket_details_df <- sqlQuery(cn, "SELECT * FROM [MaintDB_New].[dbo].[Ticket_Details]")
new_items <- read_csv("./ticket_itm_export_temp.csv", col_names = c("Old", "Name", "New"))

ticket_df_new <- ticket_df %>% mutate(item_id = old_to_new(itemID, new_items))

Я получаю следующую ошибку:

Error in `[[<-.data.frame`(`*tmp*`, col, value = c(NA_integer_, NA_integer_,  : 
  replacement has 280 rows, data has 69430
In addition: Warning message:
In df$Old == id :
  longer object length is not a multiple of shorter object length

Что я делаю не так и каков правильный подход.Я получил похожую ошибку при попытке использовать ddplyr.

Я новичок в R, поэтому я прошу прощения, если это очевидный вопрос.

EDIT - Добавлена ​​структура данных:

    head(ticket_df)
  ticketID propertyID itemID roomNumber assignedToID isOpen openID latestID
1       11         10      1       <NA>           NA      0     22       23
2       12         17      1       <NA>           NA      0     24      289
3       13         17      1       <NA>           NA      0     25      292
4       14         17     17       <NA>           NA      0     26     4411
5       15         17     68       <NA>           NA      0     27      296
6       16         17     74       <NA>           NA      0     28      294

head(new_items)
           Old Name                    New
      <int> <chr>                 <int>
    1   257 Register Cash Drawers   425
    2   253 Alarm System            426
    3   135 CREDENZA/ ARMOIRE       427
    4    55 Back Office PC          428
    5   183 Backup All Data         429
    6   260 Base Boards             430

Ссылки на вывод dput: ticket_df и new_items

1 Ответ

0 голосов
/ 17 октября 2018

Я (действительно!) Думаю, что замечание Грегора о left_join ing имеет большой смысл.Я заставлю некоторые совпадения, изменив некоторые из ваших значений:

new_items$Old[1:2] <- c(17L,74L)

Теперь объединение:

library(dplyr)

ticket_df %>%
  left_join(select(new_items, Old, New), by=c("itemID" = "Old"))
#   ticketID propertyID itemID roomNumber assignedToID isOpen openID latestID New
# 1       11         10      1         NA           NA      0     22       23  NA
# 2       12         17      1         NA           NA      0     24      289  NA
# 3       13         17      1         NA           NA      0     25      292  NA
# 4       14         17     17         NA           NA      0     26     4411 425
# 5       15         17     68         NA           NA      0     27      296  NA
# 6       16         17     74         NA           NA      0     28      294 426

Если вы удовлетворены тем, что это работает, просто переназначьте:

ticket_df %>%
  left_join(select(new_items, Old, New), by=c("itemID" = "Old")) %>%
  mutate(itemID = if_else(is.na(New), itemID, New)) %>%
  select(-New)
#   ticketID propertyID itemID roomNumber assignedToID isOpen openID latestID
# 1       11         10      1         NA           NA      0     22       23
# 2       12         17      1         NA           NA      0     24      289
# 3       13         17      1         NA           NA      0     25      292
# 4       14         17    425         NA           NA      0     26     4411
# 5       15         17     68         NA           NA      0     27      296
# 6       16         17    426         NA           NA      0     28      294

В качестве альтернативы вы можете использовать mutate(itemID = coalesce(New, itemID)), спасибо @ Gregor.


Однако, если вам нужно использовать функцию (возможно, ваша проблема более сложная или вам нужно что-то более общее)затем примечание:

  • Как правило, функции, используемые в mutate, должны возвращать векторы длины 1 или ту же длину, что и для них;это означает, что подмножество (как вы сделали с df[which(df$Old == id), ]$New) часто не будет работать.(Если вы можете гарантировать , что он всегда будет возвращать длину 1, тогда это не будет ошибкой, но я предполагаю, что это небезопасно.).Точно так же summarize требует (я полагаю), что функции возвращают длину 1.

Вот одна мысль, которая немного поспешна, но дает те же результаты:

myfunc <- function(id, changes) {
  ind <- match(id, changes[["Old"]])
  indnonna <- !is.na(ind)
  id[which(indnonna)] <- changes[["New"]][ind[indnonna]]
  id
}

ticket_df %>%
  mutate(newid = myfunc(itemID, new_items))
#   ticketID propertyID itemID roomNumber assignedToID isOpen openID latestID newid
# 1       11         10      1         NA           NA      0     22       23     1
# 2       12         17      1         NA           NA      0     24      289     1
# 3       13         17      1         NA           NA      0     25      292     1
# 4       14         17     17         NA           NA      0     26     4411   425
# 5       15         17     68         NA           NA      0     27      296    68
# 6       16         17     74         NA           NA      0     28      294   426

Вы можетеочевидно, просто присвойте itemID вместо другого столбца.Я все еще не одобряю это, поскольку (1) объединения гораздо более эффективны;(2) Я бы хотел немного поработать с функцией, чтобы найти более надежный метод;и (3) он жестко кодирует структуру new_items (то есть, конкретные имена столбцов) в функцию, тогда как выполнение объединения позволяет вам указать во время соединения, что происходит, оставляя код непосредственно рядом с элементами, использующими структуру.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...