R, dplyr: построение наборов с одним ненулевым элементом на столбец

#r #dplyr

#r #dplyr

Вопрос:

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

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

Конечным результатом должен быть набор SKU, комбинация которых должна приводить к получению как можно меньшего количества столбцов с нулевым значением.

Для иллюстрации приведем игрушечный фрейм данных (код внизу):

   sku   p1_prop   p2_prop   p3_prop   p4_prop   p5_prop         rowTally
1   1   0         0         0         0.1634774 0                1
2   2   0.1617101 0.1700415 0         0         0                2
3   3   0         0         0         0         0.1385715        1
4   4   0         0         0.1785431 0         0.1399401        2
5   5   0.1682469 0         0         0         0                1
  totalDollarSales totalUnitSales dollarsPerRobot
1        386175.48       482131.9      0.80097474
2         13488.99       599605.9      0.02249643
3        382449.72       493592.0      0.77482973
4        869703.88       186299.0      4.66832335
5        340414.96       827390.6      0.41143200
  

Мне нужна функция, которая принимает первый артикул в наборе в качестве входных данных и находит все дополнительные элементы к набору.

Например, мне нужна функция f :

 f(df=A, sku=1, rowTallyThreshold)
  

Процесс итеративно добавляет артикул, который дополняет существующий набор. Если rowTallyThreshold = 3, то все строки, где rowTally<=3 могут быть добавлены к набору:

 [1] -> [1, 2] -> [1, 2, 3]
[1] -> [1, 2] -> [1, 2, 4]
  

Если ‘rowTallyThreshold` = 1, то все строки, где rowTally<=1, или строки 1, 3 и 5, потенциально могут быть добавлены в набор:

 [1] -> [1, 3] -> [1, 3, 5]
  

Результирующий результат должен содержать все возможные наборы.

Код для генерации MWE:

 set.seed(1)
a = runif(n=25, min=0, max=0.18); a[a<0.13] = 0
A = as.data.frame(matrix(a, nrow=5, ncol=5, byrow = TRUE))
A$rowTally <- rowSums(A != 0); 
A$sku <- seq(from = 1, to = 5)
A$totalDollarSales <- runif(n=5, min=1*10^2, max=1*10^6)
A$totalUnitSales <- runif(n=5, min=1*10^2, max=1*10^6)
names(A) <- c("p1_prop", "p2_prop", "p3_prop", "p4_prop", "p5_prop", "rowTally", "sku", "totalDollarSales", "totalUnitSales")
A <- A[c("sku", "p1_prop", "p2_prop", "p3_prop", "p4_prop", "p5_prop", "rowTally", "totalDollarSales", "totalUnitSales")]
A$dollarsPerRobot <- A$totalDollarSales/A$totalUnitSales
  

Комментарии:

1. Я не понимаю, что rowTallyThreshold означает. Почему при значении 3 можно добавлять только строки <=3 или строки 1, 3 и 5 при значении 1? Я предполагаю, что в этом есть логика, но я еще не догадался об этом.

2. Для целей этого конкретного вопроса вас интересуют какие-либо столбцы, кроме p1_prop p2_prop p3_prop p4_prop p5_prop rowTally ?

3. @JonSpring rowTallyThreshold — это то, с чем следует сравнивать rowTally столбец во фрейме данных. Если rowTally <= rowTallyThreshold , то эта строка является жизнеспособным кандидатом для добавления в набор, предполагая, что она имеет неперекрывающиеся значения для столбцов

4. @JonSpring для этого вопроса меня интересуют только эти столбцы

Ответ №1:

Как насчет этого:

 library(tidyverse)

## y matches to x iff y is zero when x is not zero
is_match <- function(x, y) {
  all((x != 0 amp; y == 0) | (x == 0))
}

## Find complement skus of sku
find_matches <- function(df, sku, rowTallyThreshold, vars) {
  ## Vector of main sku
  main_sku <- as.numeric(df[df$sku == sku, vars])
  ## Potential candidates
  potential <- df %>%
    filter(rowTally <= rowTallyThreshold)
  ## Indices of matches
  match_idx <- apply(potential[vars], 1, function(y){is_match(main_sku, y)})
  ## Skus of matches
  potential$sku[match_idx]
}

find_matches(A, 1, 3, c("p1_prop", "p2_prop", "p3_prop", "p4_prop", "p5_prop"))
  

Комментарии:

1. Спасибо, это приближает меня. Фактический результат должен быть: [2,3]; [3]; [4] поскольку существует 3 возможных комбинации артикулов / строк, включая артикул / строку 1. Результатом должен быть фрейм данных

2. Извините, что ваша запись не ясна. Не могли бы вы уточнить, чего вы хотите, пожалуйста? Моя функция возвращает артикулы, как вы задали в вопросе.