Объединить два кадра данных с несовпадением ячеек - PullRequest
0 голосов
/ 09 марта 2019

В данный момент я застрял: у меня есть веб-сайт, который присваивает одному и тому же продукту совершенно разные названия (т. Е. Один и тот же продукт может быть указан как «1», «Номер 1», «Категория 3 - Номер 1»). Каждому из этих значений я хочу назначить другой результат (вырезанный из другого сайта с более хорошими именами).

# Messy code from original website:
df1 <- data.frame(c(1,1,1,1,2,2,2,3,3,3,3,3,4,4,4), c("Number 1", "Number 2", 
                                                      "Category 1", "3", "8",
                                                      "Number 2 - Category 5","1", "Number 4", 
                                                      "Kat 1", "4", "Kat 2", 
                                                      "Number5", "Test", "4","3"))
colnames(df1) <- c("ID", "Category")

> df1
   ID              Category
1   1              Number 1
2   1              Number 2
3   1            Category 1
4   1                     3
5   2                     8
6   2 Number 2 - Category 5
7   2                     1
8   3              Number 4
9   3                 Kat 1
10  3                     4
11  3                 Kat 2
12  3               Number5
13  4                  Test
14  4                     4
15  4                     3

# Code from other site:
df2 <- data.frame(c(1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4), c("1", "2", "3", "Category 1",
                                                      "Category 5", "1", "2", "3", "4",
                                                      "Kat 1", "Kat 2", "Kat 3","5",
                                                      "1","2","3","4","Test"), 
                  c(1,2,3,4,5,6,5,8,9,10,11,12,13,14,15,16,17,18))
colnames(df2) <- c("ID", "Category", "Outcome")

> df2
   ID   Category Outcome
1   1          1       1
2   1          2       2
3   1          3       3
4   1 Category 1       4
5   2 Category 5       5
6   2          1       6
7   2          2       5
8   2          3       8
9   3          4       9
10  3      Kat 1      10
11  3      Kat 2      11
12  3      Kat 3      12
13  3          5      13
14  4          1      14
15  4          2      15
16  4          3      16
17  4          4      17
18  4       Test      18

Я хочу сохранить кадр данных 1, но назначить «Вывод», взятый из df2, соответствующий идентификатору и категории. Это может быть легко достигнуто с помощью левого соединения, но, как вы можете видеть, уровни категорий не одинаковы.

Я думал о переименовании уровней, но, учитывая размер моего набора данных (~ 500 000 строк), это не представляется возможным, и я надеюсь на более простое (grepl, gsub?) Решение.

Мой окончательный результат должен выглядеть так:

> df1
   ID              Category Outcome
1   1              Number 1       1
2   1              Number 2       2
3   1            Category 1       4
4   1                     3       3
5   2                     8      NA
6   2 Number 2 - Category 5       5
7   2                     1       6
8   3              Number 4       9
9   3                 Kat 1      10
10  3                     4       9
11  3                 Kat 2      11
12  3               Number5      13
13  4                  Test      18
14  4                     4      17
15  4                     3      16

Извините за сложный пример, я хотел убедиться, что покрыл все непредвиденные обстоятельства. Вот немного больше объяснений:

Всякий раз, когда у него будет категория, она обычно будет указана полностью и в правильном написании (т. Е. «Kat» всегда будет обозначаться как «Kat», а «Category» всегда будет отображаться как «Category»). Числа могут встречаться со словом «Число» спереди или просто как сама цифра. Если число не встречается, я бы хотел, чтобы он отображал NA - мне придется добавить недостающие номера вручную позже.

Большое спасибо за чтение - я очень ценю вашу помощь!

1 Ответ

0 голосов
/ 09 марта 2019

Это может быть значительно упрощено, но вы можете попробовать:

library(dplyr)

extr_last_digit <- function(x) substring(x, first = regexpr("(\\d+)(?!.*\\d)", x, perl = T))
extr_cat_digit <- function(x) gsub(".*((?<=Category\\s)\\d+).*|.*((?<=Kat\\s)\\d+).*", "\\1\\2", x, perl = T)

df1 %>%
  mutate(
    join = case_when(
      !grepl("Category|Kat", Category) ~ extr_last_digit(Category),
      TRUE ~ paste0("Category ", extr_cat_digit(Category)))
  ) %>%
  left_join(df2 %>%
              mutate(
                join = case_when(
                  !grepl("Category|Kat", Category) ~ extr_last_digit(Category),
                  TRUE ~ paste0("Category ", extr_cat_digit(Category))
                ),
                Category = NULL), 
            by = c("ID", "join")
  ) %>%
  select(-join)

Вывод:

   ID              Category Outcome
1   1              Number 1       1
2   1              Number 2       2
3   1            Category 1       4
4   1                     3       3
5   2                     8      NA
6   2 Number 2 - Category 5       5
7   2                     1       6
8   3              Number 4       9
9   3                 Kat 1      10
10  3                     4       9
11  3                 Kat 2      11
12  3               Number5      13
13  4                  Test      18
14  4                     4      17
15  4                     3      16

По сути, это создает столбец join в обоих df, который имеет ту же структуру - если он не находит упоминаний о Category или Kat, он использует последнюю упомянутую цифру для слияния, в противном случае он вставляет слово Category и цифру, упомянутую после любого из словCategory или Kat.

Это также работает со словом Test, поскольку, если оно не находит цифру, оно просто использует всю строку.

...