Функция R для выделения фиксированного ресурса на основе значения единицы - PullRequest
1 голос
/ 26 марта 2019

Я пытаюсь создать функцию в R для выделения фиксированного количества единиц на основе значения, которое предоставляют эти единицы. Я настроил приведенный ниже примерный фрейм данных.

fruit <- c("apple","orange","bannana","cherry")
units_of_mass <- c(9, 11, 16, 7)
health_pts <- c(5, 3, 6, 1)
diet_plan <- data.frame(fruit, units_of_mass, health_pts)
total_units_desired <- 32

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

Я пытался использовать dplyr, но застрял

fruit_detail <- diet_plan %>%

arrange(fruit, health_pts) %>%

mutate(
  cum_units = cumsum(units_of_mass) - units_of_mass,
  can_allocate = total_units_desired - cum_units,
  allocated = ifelse(can_allocate <= 0, 0, ifelse(can_allocate >= 
  cum_units, cum_units))
 )

Простой способ сделать это - распределить по точкам здоровья и вычесть единицы, пока у вас не закончится total_units_desired, что будет выглядеть примерно так:

## iterate on allocations
diet_plan <- setDT(diet_plan)

max <- max(diet_plan$health_pts)

allocation_1 <- subset(diet_plan, health_pts == max)
allocation_1[, units_allocated := ifelse(total_units_desired > 
               units_of_mass, units_of_mass, total_units_desired)]

remaining_units <- ifelse(total_units_desired - allocation_1$units_allocated 
                   > 0, total_units_desired - allocation_1$units_allocated, 
                   0)

diet_plan <- subset(diet_plan, health_pts < max)
max <- max(diet_plan$health_pts)

allocation_2 <- subset(diet_plan, health_pts == max)
allocation_2[, units_allocated := ifelse(remaining_units > units_of_mass, 
                                  units_of_mass, remaining_units)]

remaining_units <- ifelse(remaining_units - allocation_2$units_allocated > 
                   0, remaining_units - allocation_2$units_allocated, 0)

diet_plan <- subset(diet_plan, health_pts < max)
max <- max(diet_plan$health_pts)

allocation_3 <- subset(diet_plan, health_pts == max)
allocation_3[, units_allocated := ifelse(remaining_units > units_of_mass, 
                                  units_of_mass, remaining_units)]

remaining_units <- ifelse(remaining_units - allocation_3$units_allocated > 
                   0, remaining_units - allocation_3$units_allocated, 0)

diet_plan <- subset(diet_plan, health_pts < max)
max <- max(diet_plan$health_pts)

allocation_4 <- subset(diet_plan, health_pts == max)
allocation_4[, units_allocated := ifelse(remaining_units > units_of_mass, 
units_of_mass, remaining_units)]

result <- rbind(allocation_1, allocation_2, allocation_3, allocation_4)

 fruit units_of_mass health_pts units_allocated
bannana        16          6              16
apple           9          5               9
orange         11          3               7
cherry          7          1               0

1 Ответ

0 голосов
/ 26 марта 2019

Как вы представили свою проблему, мы можем просто отсортировать по health_pts, а затем найти кумулятивную сумму units_of_mass, то есть общую сумму units_allocated, если мы возьмем этот предмет и все предметы над ним.Тогда мы можем просто filter элементы, где их брать, не поставят нас за предел total_units_desired.

Тогда оставшиеся строки могут иметь максимальное количество выделенных единиц:

diet_plan_sum %>%
    arrange(desc(health_pts)) %>%                # Sort by health_pts
    mutate(cum_sum = cumsum(units_of_mass)) %>%  # Calculate total cumulative units
    filter(cum_sum < total_units_desired) %>%    # Drop items over allocation limit
    mutate(units_allocated = units_of_mass) %>%  # For remaining rows, allocate max
    select(-cum_sum)                             # Drop cum_sum variable

    fruit units_of_mass health_pts units_allocated
1 bannana            16          6              16
2   apple             9          5               9

Если вы хотите выделить оставшиеся единицы, мы можем внести несколько изменений в вышеприведенное:

Сначала мы находим первую строку, в которой мы переходим порог: этоединственная строка с частичными значениями.Затем мы можем установить значение units_allocated равное total - the proceeding row's value, что является остатком.

Для каждой другой строки мы проверяем, не превышает ли накопленная сумма пороговое значение: если это так, задайте для units_allocated значение0, если нет, установите units_allocated на units_of_mass:

diet_plan_sum %>%
    arrange(desc(health_pts)) %>%
    mutate(cum_sum = cumsum(units_of_mass),
           # Find the first row where we go over the threshold, set it to remainder
           units_allocated = if_else(cum_sum > total_units_desired & lag(cum_sum) < total_units_desired,
                                     total_units_desired - lag(cum_sum),
                                     if_else(cum_sum > total_units_desired,
                                             0,
                                             units_of_mass))) %>%
    select(-cum_sum) # Drop cum_sum variable

    fruit units_of_mass health_pts units_allocated
1 bannana            16          6              16
2   apple             9          5               9
3  orange            11          3               7
4  cherry             7          1               0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...