Есть ли функция R для определения 'n' совпадений в каждой строке? - PullRequest
1 голос
/ 29 мая 2019

Я пытаюсь объединить свои данные, чтобы найти корреляции / шаблоны, и хочу выяснить, как и где данные могут коррелировать. В частности, я хочу определить, сколько раз идентификатор (здесь называемый «элемент») появляется вместе. Есть ли способ узнать, сколько раз каждый (id) появляется вместе в строке?

Это для более крупного data.frame, который уже был очищен и агрегирован на основе этого конкретного запроса. В прошлом я пытался применить несколько функций агрегации, суммирования и фильтрации из таких пакетов, как «data.table», «dplyr» и «tidyverse», но не могу получить то, что ищу.

В разделе 3 ( Показать код ) я привел минимальный воспроизводимый пример:

set.seed(1234)
random.people<-c("Bob","Tim","Jackie","Angie","Christopher")
number=sample(12345:12350,2000,replace = T)
item=sample(random.people,2000,replace=T)

sample_data <- data.frame(cbind(number,item), stringsAsFactors = FALSE)

Используя примеры здесь , я ожидал, что вывод идентифицирует все комбинации, где имена были объединены в число, и покажет n (значение) - ожидаемые результаты будут напоминать что-то вроде:

Pair       value
Bob, Tim     2
Bob, Jackie  4
Bob, Angie   0

Этот вывод (что я надеюсь получить) скажет мне, что во всем дф есть 2 раза Боб и Тим и 4 раза Боб и Джеки оба иметь тот же номер.

но фактический результат:

Error: Each row of output must be identified by a unique combination of keys.

Keys are shared for 2000 rows:
* 9, 23, 37, 164, 170, 180, 211...

Обновление: я подумал о ... творческом (?) Решении - но надеюсь, что кто-то может помочь с его ускорением. Я могу найти все числа (column1), которые разделены между двумя именами, используя следующее:

x1<-sample_data %>% dplyr::filter(item=="Bob")
x2<-sample_data %>% dplyr::filter(item=="Tim")
Bob<-x1[,1]
Tim<-x2[,1]
Reduce(intersect, list(Bob,Tim))

выход:

[1] "12345" "12348" "12350" "12346" "12349" "12347"

Как я уже сказал, это занимает много времени и потребует создания множества векторов и пересечения каждого (например, 1 вектор для каждого имени) и нескольких комбинаций.

Ответы [ 2 ]

3 голосов
/ 30 мая 2019
set.seed(1234)
random.people<-c("Bob","Tim","Jackie","Angie","Christopher")
number=sample(12345:22350,2000,replace = T) # I edited ur number here.
item=sample(random.people,2000,replace=T)

sample_data <- data.frame(cbind(number,item), stringsAsFactors = FALSE)

library(tidyverse)
sample_data %>%
  # find out unique rows
  distinct() %>%
  # nest the data frame into nested tibble, so now you have
  # a "data" column, which is a list of small data frames.
  group_nest(number) %>%
  # Here we use purrr::map to modify the list column. We want each 
  # combination counts only once despite the order, so we use sort. 
  mutate(data = map_chr(data, ~paste(sort(.x$item), collapse = ", "))) %>%
  # the last two steps just count the numbers
  group_by(data) %>%
  count()

# A tibble: 21 x 2
# Groups:   data [21]
   data                         n
   <chr>                    <int>
 1 Angie                      336
 2 Angie, Bob                   8
 3 Angie, Bob, Christopher      2
 4 Angie, Bob, Jackie           1
 5 Angie, Christopher          16
 6 Angie, Jackie                9
 7 Angie, Tim                  10
 8 Bob                        331
 9 Bob, Christopher            12
10 Bob, Christopher, Jackie     1
# … with 11 more rows

Одно из возможных решений

1 голос
/ 31 мая 2019

Вот базовое решение R, которое опирается на table -> aggregate и потенциально неэффективный способ объединения имен с использованием apply.

tab_data <-  data.frame(unclass(table(unique(sample_data))))
#table results in columns c(Angie.1, Bob.1, ...) - this makes it look better
names(tab_data) = sort(random.people) 

library(network)
plot.network.default(as.network(tab_data))

tab_data$n <- 1

agg_data <- aggregate(n~., data = tab_data, FUN = length)
agg_data$Pair <- apply(agg_data[, -length(agg_data)], 1, function(x) paste(names(x[x!=0]), collapse = ', '))


agg_data[order(agg_data$Pair), c('Pair', 'n') ]

                            Pair   n
1                          Angie 336
3                     Angie, Bob   8
7        Angie, Bob, Christopher   2
11            Angie, Bob, Jackie   1
5             Angie, Christopher  16
9                  Angie, Jackie   9
15                    Angie, Tim  10
2                            Bob 331
6               Bob, Christopher  12
... truncated ...

Что касается производительности, на этомсравнительно небольшой набор данных, это примерно в 9 раз быстрее, чем решение dplyr:

Unit: milliseconds
           expr     min       lq     mean   median       uq      max neval
  base_solution  9.4795  9.65215 10.80984  9.87625 10.32125  46.8230   100
 dplyr_solution 78.6070 81.72155 86.47891 83.96435 86.40495 200.7784   100

Данные

set.seed(1234)
random.people<-c("Bob","Tim","Jackie","Angie","Christopher")
number=sample(12345:22350,2000,replace = T) # I edited ur number here.
item=sample(random.people,2000,replace=T)

sample_data <- data.frame(number,item, n = 1L, stringsAsFactors = FALSE)
...