Подсчитайте, сколько раз комбинация значений присутствует в каждой строке

У меня есть база данных значений символов.

df = data.frame(col1 = c("value_1","value_3","value_3","value_2"),
                col1 = c("value_1","value_1","value_4","value_2"),
                col1 = c("value_1","value_2","value_1","value_2"),
                col1 = c("value_3","value_3","value_3","value_2"),
                col1 = c("value_2","value_3","value_4","value_2"))

Я хочу подсчитать, сколько раз комбинация значений присутствует подряд. Комбинация не точная, например, если мне нужна комбинация значения_1 и значения_2, это комбинация наличия обоих значений ПО МИНИМУМ один раз. Комбинация является входными данными, и количество элементов во входных данных может быть разным.

Вход:

comb = c("value_1","value_2")

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

out = 2

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

Но мне интересно, есть ли более элегантное решение?


2
51
3

Ответы:

Решено

Вот быстрый способ:

df <- data.frame(col1 = c("value_1","value_3","value_3","value_2"),
                col1 = c("value_1","value_1","value_4","value_2"),
                col1 = c("value_1","value_2","value_1","value_2"),
                col1 = c("value_3","value_3","value_3","value_2"),
                col1 = c("value_2","value_3","value_4","value_2"))

comb <- c("value_1","value_2")

apply(df, 1, function(x) all(comb %in% x)) |>
  sum()

Обратите внимание, что это приведет к внутреннему преобразованию df в матрицу, чтобы apply мог обрабатывать каждую строку. Могут быть более быстрые/эффективные способы сделать это (возможно, используя одну из функций map из пакета purrr).


Использование rowSums дважды:

> sum(rowSums(combn[1L]==df) * rowSums(combn[2L]==df) > 0L)
[1] 2

Завершение в функцию f:

f = \(df, combn) {
  stopifnot(is.data.frame(df), is.character(combn), length(combn)==2L)
  sum(rowSums(combn[1L]==df) * rowSums(combn[2L]==df) > 0L)
}
f(df, combn)
# [1] 2

Если ваш comb всегда состоит из 2 элементов, вы можете попробовать match + rowMeans, как показано ниже.

sum(
  !rowMeans(
    `dim<-`(match(as.matrix(df), comb), dim(df)),
    TRUE
  ) %in% seq_along(comb)
)

Или, для общей длины comb, вы можете использовать

sum(
  rowMeans(
    apply(
      outer(as.matrix(df), comb, `==`),
      3,
      rowSums
    ) > 0
  ) == 1
)