Проверьте, существуют ли значения одного кадра данных в другом кадре данных в точном порядке

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

Ниже представлен набор данных об игрушках.

Dataframe

group   type    value
1       A       Teddy
1       A       William
1       A       Lars
2       B       Dolores
2       B       Elsie
2       C       Maeve
2       C       Charlotte
2       C       Bernard


Reference_A

type    value
A       Teddy
A       William
A       Lars

Reference_B

type    value
B       Elsie
B       Dolores

Reference_C

type    value
C       Maeve
C       Hale
C       Bernard

Например, в наборе данных игрушек группа group1 получит оценку 1,0 (правильность на 100%), потому что все ее значения в A соответствуют значениям и порядку значений An в reference_A. Однако группа group2 получит оценку 0,0, потому что значения в B не в порядке по сравнению с reference_B и 0,66, потому что 2/3 значений в C соответствуют значениям и порядку значений в reference_C.

Желаемый результат

group   type    score
1       A       1.0
2       B       0.0
2       C       0.66

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


Обновление: Спасибо всем, кто предоставил решения! Эти решения отлично подходят для набора данных игрушек, но еще не могут быть адаптированы для наборов данных с большим количеством столбцов. Опять же, как я написал в своем сообщении, столбцы, которые я перечислил выше, очень важны - я бы предпочел не отбрасывать ненужные столбцы, если это необходимо.


person psychcoder    schedule 24.07.2020    source источник
comment
Что делать, если количество строк другое?   -  person r2evans    schedule 24.07.2020


Ответы (3)


Мы также можем сделать это с mget, чтобы вернуть list из data.frames, связать их вместе и выполнить группировку по mean логического вектора.

library(dplyr)
mget(ls(pattern = '^Reference_[A-Z]$')) %>%
    bind_rows() %>% 
    bind_cols(df1) %>% 
    group_by(group, type = type...1) %>% 
    summarise(score = mean(value...2 == value...5))
# Groups:   group [2]
#  group type  score
#  <int> <chr> <dbl>
#1     1 A     1    
#2     2 B     0    
#3     2 C     0.667
person akrun    schedule 24.07.2020
comment
благодарю вас! Что означают value...2 и value...5? Конкретно зачем выбирать числа 2 и 5? То же самое для type..., пожалуйста - person psychcoder; 28.07.2020

Это еще одно tidyverse решение. Здесь я добавляю счетчик (т.е. rowname) как к ссылке, так и к данным. Затем я присоединяюсь к ним на type и rowname. В конце я резюмирую их на type, чтобы получить желаемый результат.

library(dplyr)
library(purrr)
library(tibble)

list(`Reference A`, `Reference B`, `Reference C`) %>% 
  map(., rownames_to_column) %>% 
  bind_rows %>% 
 left_join({Dataframe %>%
             group_split(type) %>% 
             map(., rownames_to_column) %>% 
             bind_rows}, 
             . , by=c("type", "rowname")) %>% 
  group_by(type) %>% 
  dplyr::summarise(group = head(group,1),
            score = sum(value.x == value.y)/n())
#> # A tibble: 3 x 3
#>   type  group score
#>   <chr> <int> <dbl>
#> 1 A         1 1    
#> 2 B         2 0    
#> 3 C         2 0.667
person M--    schedule 24.07.2020

Вот аккуратный метод:

library(dplyr)
# library(purrr) # map2_dbl
Reference <- bind_rows(Reference_A, Reference_B, Reference_C) %>%
  nest_by(type, .key = "ref") %>%
  ungroup()
Reference
# # A tibble: 3 x 2
#   type                 ref
#   <chr> <list<tbl_df[,1]>>
# 1 A                [3 x 1]
# 2 B                [2 x 1]
# 3 C                [3 x 1]

Dataframe %>%
  nest_by(group, type, .key = "data") %>%
  left_join(Reference, by = "type") %>%
  mutate(
    score = purrr::map2_dbl(data, ref, ~ {
      if (length(.x) == 0 || length(.y) == 0) return(numeric(0))
      if (length(.x) != length(.y)) return(0)
      sum((is.na(.x) & is.na(.y)) | .x == .y) / length(.x)
    })
  ) %>%
  select(-data, -ref) %>%
  ungroup()
# # A tibble: 3 x 3
#   group type  score
#   <int> <chr> <dbl>
# 1     1 A     1    
# 2     2 B     0    
# 3     2 C     0.667
person r2evans    schedule 24.07.2020
comment
Спасибо! Это воспроизводимо в моем наборе данных игрушек, но не в моем большом, реальном наборе данных, который имеет намного больше столбцов. У вас есть совет, как я могу адаптировать ваш код? Важные столбцы похожи на мой набор данных игрушек, но я могу игнорировать другие столбцы. Было бы хорошо, если бы мне не нужно было удалять какие-либо столбцы из фактического набора данных и эталонных наборов данных. - person psychcoder; 28.07.2020
comment
Это зависит от данных. Вы пробовали это на своих больших данных? Что-то подключилось неправильно или выдало предупреждения / ошибки? Без репрезентативных данных сложно что-то посоветовать. - person r2evans; 28.07.2020
comment
Я знаю :( Прошу прощения, что не могу передать более репрезентативные данные. Вот мое сообщение об ошибке для большего набора данных: Error: Can't re-group while nesting ℹ Either `ungroup()` first or don't supply arguments to `nest_by(). - person psychcoder; 28.07.2020