Таблица сопряженности со строками
У меня есть этот фрейм данных 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