Как рассчитать общие значения в разных группах? - PullRequest
0 голосов
/ 13 декабря 2018

Я пытаюсь создать фрейм данных для создания сетевых диаграмм с использованием пакета igraph .У меня есть пример данных «mydata_data», и я хочу создать «Ожидаемые_данные».

Я могу легко рассчитать количество клиентов, посетивших конкретный магазин, но как рассчитать общий набор клиентов, которые идут в магазин x1 и магазинx2 и т. д.

У меня более 500 магазинов, поэтому я не хочу создавать столбцы вручную.Пример данных для воспроизводимой цели приведен ниже:

mydata_data<-data.frame(
  Customer_Name=c("A","A","C","D","D","B"),
  Store_Name=c("x1","x2","x2","x2","x3","x1"))

expected_data<-data.frame(
 Store_Name=c("x1","x2","x3","x1_x2","x2_x3","x1_x3"), 
 Customers_Visited=c(2,3,1,1,1,0))

Ответы [ 5 ]

0 голосов
/ 13 декабря 2018

Использование dplyr : самостоятельно присоединиться, затем создать группу и получить уникальный счет.Это должно быть намного быстрее по сравнению с другими ответами, где рассматриваются все комбинации.

Примечание: не показывает несуществующие пары.Кроме того, здесь x1_x1 означает, конечно, x1.

left_join(mydata_data, mydata_data, by = "Customer_Name")  %>%
  transmute(Customer_Name,
            grp = paste(pmin(Store_Name.x, Store_Name.y),
                        pmax(Store_Name.x, Store_Name.y), sep = "_")) %>% 
  group_by(grp) %>% 
  summarise(n = n_distinct(Customer_Name))

# # A tibble: 5 x 2
#   grp       n
#   <chr> <int>
# 1 x1_x1     2
# 2 x1_x2     1
# 3 x2_x2     3
# 4 x2_x3     1
# 5 x3_x3     1

Данные без факторов:

mydata_data<-data.frame(
  Customer_Name=c("A","A","C","D","D","B"),
  Store_Name=c("x1","x2","x2","x2","x3","x1"),
  stringsAsFactors = FALSE)
0 голосов
/ 13 декабря 2018

Вот подход igraph:

A <- as.matrix(as_adj(graph_from_edgelist(as.matrix(mydata_data), directed = FALSE)))
stores <- as.character(unique(mydata_data$Store_Name))
storeCombs <- t(combn(stores, 2))

data.frame(Store_Name = c(stores, apply(storeCombs, 1, paste, collapse = "_")),
           Customers_Visited = c(colSums(A)[stores], (A %*% A)[storeCombs]))
#   Store_Name Customers_Visited
# 1         x1                 2
# 2         x2                 3
# 3         x3                 1
# 4      x1_x2                 1
# 5      x1_x3                 0
# 6      x2_x3                 1

Объяснение: A - матрица смежности соответствующего ненаправленного графа.stores это просто

stores
# [1] "x1" "x2" "x3"

, тогда как

storeCombs
#      [,1] [,2]
# [1,] "x1" "x2"
# [2,] "x1" "x3"
# [3,] "x2" "x3"

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

0 голосов
/ 13 декабря 2018

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

library(tidyverse)

df %>%
    group_by(Customer_Name) %>%
    summarise(combos = list(unique(c(unique(Store_Name), paste(unique(Store_Name), collapse = '_'))))) %>%
    unnest() %>%
    group_by(combos) %>%
    count() %>%
    right_join(data.frame(combos = c(unique(df$Store_Name), combn(unique(df$Store_Name), 2, paste, collapse = '_'))))

, которыйдает,

# A tibble: 6 x 2
# Groups:   combos [?]
  combos     n
  <chr>  <int>
1 x1         2
2 x2         3
3 x3         1
4 x1_x2      1
5 x1_x3     NA
6 x2_x3      1

ПРИМЕЧАНИЕ: Убедитесь, что ваша Store_Name переменная является символом НЕ , в противном случае combn()потерпит неудачу

0 голосов
/ 13 декабря 2018

Другой вариант, с base R:

Получить список всех возможных магазинов

all_stores <- as.character(unique(mydata_data$Store_Name))

Найти различные комбинации 1 или 2 магазинов:

all_comb_store <- lapply(1:2, function(n) combn(all_stores, n))

Для каждого количества магазинов, взятых вместе, получите количество клиентов, которые посетили оба, а затем объедините это значение в data.frame с названиями магазинов:

do.call(rbind, 
        lapply(all_comb_store, 
               function(nb_comb) {
                 data.frame(Store_Name=if (nrow(nb_comb)==1) as.character(nb_comb) else apply(nb_comb, 2, paste, collapse="_"), 
                            Customers_Visited=apply(nb_comb, 2, 
                                                    function(vec_stores) {
                                                       length(Reduce(intersect, 
                                                              lapply(vec_stores, 
                                                                     function(store) mydata_data$Customer_Name[mydata_data$Store_Name %in% store])))}))}))
#  Store_Name Customers_Visited
#1         x1                 2
#2         x2                 3
#3         x3                 1
#4      x1_x2                 1
#5      x1_x3                 0
#6      x2_x3                 1
0 голосов
/ 13 декабря 2018

Вот один из возможных способов получения данных

Вот адаптированная форма вспомогательной функции: Генерация всех комбинаций всех длин в R из вектора

comball <- function(x) do.call("c", lapply(seq_along(x), function(i) combn(as.character(x), i, FUN = list)))

Тогда вы можете использовать это с некоторыми функциями стихотворения

library(dplyr)
library(purrr)
library(tidyr)

mydata_data %>% 
  group_by(Customer_Name) %>% 
  summarize(visits = list(comball(Store_Name))) %>% 
  mutate(visits = map(visits, ~map_chr(., ~paste(., collapse="_")))) %>% 
  unnest(visits) %>% 
  count(visits)
...