Таблица сопряженности со строками

У меня есть этот фрейм данных glimpse(df)

Observations: 2,211
Variables: 3
$ city       <chr> "Las Vegas", "Pittsburgh", "Las Vegas", "Phoenix", "Las Vegas", "Las Veg...
$ categories <chr> "c(\"Korean\", \"Sushi Bars\")", "c(\"Japanese\", \"Sushi Bars\")", "Tha...
$ is_open    <chr> "0", "0", "1", "0", "1", "1", "0", "1", "0", "1", "1", "1", "0", "1", "1...

Вот маленький dput()

structure(list(city = c("Las Vegas", "Pittsburgh", "Las Vegas", 
"Phoenix", "Las Vegas"), categories = c("c(\"Korean\", \"Sushi Bars\")", 
"c(\"Japanese\", \"Sushi Bars\")", "Thai", "c(\"Sushi Bars\", \"Japanese\")", 
"Korean"), is_open = c("0", "0", "1", "0", "1")), .Names = c("city", 
"categories", "is_open"), row.names = c(NA, 5L), class = "data.frame")

Данные состоят из разных городов city с разными кухнями categories, Я хочу составить таблицу непредвиденных расходов, чтобы визуализировать, какие кухни связаны с закрытием (is_opem = 0) или отверстия (is_open = 1),

Я хочу сделать это с таблицей непредвиденных обстоятельств. Для этого я попробовал это, но я получил эту ошибку:

xtabs(is_open ~., data = df)

Error in FUN(X[[i]], ...) : invalid 'type' (character) of argument

Когда я конвертирую переменные as.factor() Я получаю много столов, а не один. Есть ли способ сделать это так, как показано ниже?

Categorie/City          Las Vegas     Pittsburgh
           Korean       50/50         30/70
           Sushi Bars   40/60         40/60

Числа в столбцах - это частоты закрытия (is_opem = 0) и отверстия (is_open = 1) для каждой категории на город (например, для корейцев в Лас-Вегасе распределение для закрытий (0) и открытий (1) составляет 50/50).

1 ответ

Решение

Здесь решение с использованием data.table в cast ваши данные с помощью функции подсчета на основе stri_count от stringi пакет. Последнее также может быть достигнуто через table или же sum(grepl()) с ifelse конструкции (в зависимости от требуемой гибкости в отношении структуры данных, требований к скорости и т. д.). Обратите внимание, что с помощью этого ответа я также переформатировал ваши данные в более чистый "длинный формат". Это переформатирование может быть пропущено, если вы форматируете данные таким образом с самого начала. Я надеюсь, что это то, что вы ищете.

#your data
df <- structure(list(city = c("Las Vegas", "Pittsburgh", "Las Vegas", "Phoenix", "Las Vegas")
                       ,categories = c("c(\"Korean\", \"Sushi Bars\")", 
                                     "c(\"Japanese\", \"Sushi Bars\")", "Thai", "c(\"Sushi Bars\", \"Japanese\")", 
                                     "Korean")
                       ,is_open = c("0", "0", "1", "0", "1"))
                       ,.Names = c("city",  "categories", "is_open"), row.names = c(NA, 5L), class = "data.frame")

library(data.table)
library(stringi)                                  

#format data to correct "long format"
DT <- as.data.table(df)
DT[, categories := gsub("c\\(\"|\"|\"\\)", "", categories)]
DT <- DT[, .(categories = unlist(strsplit(as.character(categories), ", ", fixed = TRUE))), 
         by = .(city, is_open)]
#           city is_open categories
# 1:  Las Vegas       0     Korean
# 2:  Las Vegas       0 Sushi Bars
# 3: Pittsburgh       0   Japanese
# 4: Pittsburgh       0 Sushi Bars
# 5:  Las Vegas       1       Thai
# 6:  Las Vegas       1     Korean
# 7:    Phoenix       0 Sushi Bars
# 8:    Phoenix       0   Japanese

#specify all_unique_count_items to also cover items that are not present in x
calc_count_distr <-  function(x, all_unique_count_items) {

    count_distribution <- sapply(all_unique_count_items, function(y) {
                                     100*round(sum(stri_count_fixed(x, y))/length(x), d =2)
                                })
    paste(count_distribution, collapse = "/")
}

dcast.data.table(DT, categories ~ city, value.var = "is_open"
                 ,fun.aggregate = function(x) calc_count_distr(x, all_unique_count_items = unique(DT$is_open))
                 ,fill = NA)
#   categories Las Vegas Phoenix Pittsburgh
#1:   Japanese        NA   100/0      100/0
#2:     Korean     50/50      NA         NA
#3: Sushi Bars     100/0   100/0      100/0
#4:       Thai     0/100      NA         NA
Другие вопросы по тегам