根据(多个)条件分为几组?

时间:2019-09-04 23:40:36

标签: r dplyr tidyverse

我有一套不同颜色和重量的大理石,我想根据它们的重量和颜色将它们分成几组。

条件是:

  1. 一个小组的体重不能超过100个单位
  2. 一个小组不能拥有超过5种不同颜色的弹珠。

可复制的示例:

marbles <- data.frame(color=sample(1:20, 20), weight=sample(1:40, 20, replace=T))

   color weight
1      1     22
2     15     33
3     13     35
4     11     13
5      6     26
6      8     15
7     10      3
8     16     22
9     14     21
10     3     16
11     4     26
12    20     30
13     9     31
14     2     16
15     7     12
16    17     13
17    19     19
18     5     17
19    12     12
20    18     40

我想要的是此组列:

   color weight group
1      1     22     1
2     15     33     1
3     13     35     1
4     11     13     2
5      6     26     2
6      8     15     2
7     10      3     2
8     16     22     2
9     14     21     3
10     3     16     3
11     4     26     3
12    20     30     3
13     9     31     4
14     2     16     4
15     7     12     4
16    17     13     4
17    19     19     4
18     5     17     5
19    12     12     5
20    18     40     5

TIA。

2 个答案:

答案 0 :(得分:1)

以下不是对组的最优分配,它只是在数据帧中按顺序进行。它使用rowwise,可能不是最有效的方法,因为它不是vectorized的方法。

library(dplyr)

marbles <- data.frame(color=sample(1:20, 20), weight=sample(1:40, 20, replace=T))

下面,我创建一个rowwise函数,可以使用dplyr

应用
assign_group <- function(color, weight) {
  # Conditions
  clists = append(color_list, color)
  sum_val = group_sum + weight
  num_colors = length(unique(color_list))

  assign_condition = (sum_val <= 100 & num_colors <= 5)
  #assign globals
  cval <- if(assign_condition) clists else c(color)
  sval <- ifelse(assign_condition, sum_val, weight)
  gval <- ifelse(assign_condition, group_number, group_number + 1)
  assign("color_list", cval, envir = .GlobalEnv)
  assign("group_sum", sval, envir = .GlobalEnv)
  assign("group_number", gval, envir = .GlobalEnv)
  res = group_number
  return(res)
}

然后,我设置了几个global变量来跟踪弹子在每个组中的分配。

# globals
color_list <<- c()
group_sum <<- 0
group_number <<- 1

最后使用mutate

运行此功能
test <- marbles %>% rowwise() %>% mutate(group = assign_group(color,weight)) %>% data.frame() 

结果如下

 color weight group
1      6     27     1
2     12     16     1
3     15     32     1
4     20     25     1
5     19      5     2
6      2     21     2
7     16     39     2
8     17      4     2
9     11     16     2
10     7      7     3
11    10      5     3
12     1     30     3
13    13      7     3
14     9     39     3
15    14      7     4
16     8     17     4
17    18      9     4
18     4     36     4
19     3      1     4
20     5      3     5

似乎符合约束条件

test %>% group_by(group) %>% summarise(tot_w = sum(weight), n_c = length(unique(color)) )

  group tot_w   n_c
  <dbl> <int> <int>
1     1   100     4
2     2    85     5
3     3    88     5
4     4    70     5
5     5     3     1

答案 1 :(得分:0)

在基本R中,您可以编写如下所示的递归函数:

create_group = function(df,a){
  if(missing(a)) a = cumsum(df$weight)%/%100
  b = !ave(df$color,a,FUN=seq_along)%%6
  d = ave(df$weight,a+b,FUN=cumsum)>100
  a = a+b+d
  if (any(b|d)) create_group(df,a) else cbind(df,group = a+1)
}

create_group(df)
   color weight group
1      1     22     1
2     15     33     1
3     13     35     1
4     11     13     2
5      6     26     2
6      8     15     2
7     10      3     2
8     16     22     2
9     14     21     3
10     3     16     3
11     4     26     3
12    20     30     3
13     9     31     4
14     2     16     4
15     7     12     4
16    17     13     4
17    19     19     4
18     5     17     5
19    12     12     5
20    18     40     5