在R中创建等和群

在R中创建等和群,r,bin-packing,R,Bin Packing,我正在尝试将data.frame/data.table的一列分为三组,所有组的总和相等 数据首先从最小到最大排序,这样第一组将由大量具有小值的行组成,第三组将由少量具有大值的行组成。这在精神上是通过以下方式实现的: test <- data.frame(x = as.numeric(1:100000)) store <- 0 total <- sum(test$x) for(i in 1:100000){ store <- store + test$x[i]

我正在尝试将data.frame/data.table的一列分为三组,所有组的总和相等

数据首先从最小到最大排序,这样第一组将由大量具有小值的行组成,第三组将由少量具有大值的行组成。这在精神上是通过以下方式实现的:

test <- data.frame(x = as.numeric(1:100000))
store <- 0
total <- sum(test$x)

for(i in 1:100000){

  store <- store + test$x[i]

  if(store < total/3){

    test$y[i] <- 1

  } else {

      if(store < 2*total/3){

        test$y[i] <- 2

      } else { 

        test$y[i] <- 3

      }     
  }    
}
测试可能使用cumsum:

test$z <- cumsum(test$x) %/% (ceiling(sum(test$x) / 3)) + 1

test$z我认为求和/模除方法非常优雅,但它确实运行了一个有点不规则的分配:

> tapply(test$x, test$z, sum)
         1          2          3 
1666636245 1666684180 1666729575 
> sum(test)/3
[1] 1666683333
所以我想我会先创建一个随机排列,并提供类似的东西:

 test$x <- sample(test$x)
 test$z2 <- cumsum(test$x)[ findInterval(cumsum(test$x), 
                                        c(0, 1666683333*(1:2), sum(test$x)+1))]
> tapply(test$x, test$z2, sum)
     91099     116379     129539 
1666676164 1666686837 1666686999 
我必须承认,我对
z2

中条目的命名感到困惑,这或多或少是个问题

使用
BBmisc
软件包中的
binPack
功能:

library(BBmisc)
test$bins <- binPack(test$x, sum(test$x)/3+1)
您可以使用groupdata2中的fold()并在每个组中获得几乎相同数量的元素:

# Create data frame
test <- data.frame(x = as.numeric(1:100000)) 

# Use fold() to create 3 numerically balanced groups  
test <- groupdata2::fold(k = 3, num_col = "x")

# Watch first 10 rows
head(test, 10)

## # A tibble: 10 x 2
## # Groups:   .folds [3]
##        x .folds
##    <dbl> <fct> 
##  1     1 1     
##  2     2 3     
##  3     3 2     
##  4     4 1     
##  5     5 2     
##  6     6 2     
##  7     7 1     
##  8     8 3     
##  9     9 2     
## 10    10 3 

# Check the sum and number of elements per group
test %>% 
  dplyr::group_by(.folds) %>% 
  dplyr::summarize(sum_ = sum(x),
                   n_members = dplyr::n())

## # A tibble: 3 x 3
##   .folds       sum_ n_members
##   <fct>       <dbl>     <int>
## 1 1      1666690952     33333
## 2 2      1666716667     33334
## 3 3      1666642381     33333
#创建数据帧
测试%
dplyr::summary(sum)=sum(x),
n_members=dplyr::n()
###tibble:3 x 3
##.folds sum_un_u成员
##               
## 1 1      1666690952     33333
## 2 2      1666716667     33334
## 3 3      1666642381     33333

或者您只需在cumsum上进行
剪切

test$z <- cut(cumsum(test$x), breaks = 3, labels = 1:3) 

我认为预购实际上会破坏平等分配,因为当你达到更高的价值时,大尺寸的商品就是你的全部。BondedDust-fair point,但这正是你想要的。我想要一个等额分配,将最小值、中等值和最大值分组在一起
# Create data frame
test <- data.frame(x = as.numeric(1:100000)) 

# Use fold() to create 3 numerically balanced groups  
test <- groupdata2::fold(k = 3, num_col = "x")

# Watch first 10 rows
head(test, 10)

## # A tibble: 10 x 2
## # Groups:   .folds [3]
##        x .folds
##    <dbl> <fct> 
##  1     1 1     
##  2     2 3     
##  3     3 2     
##  4     4 1     
##  5     5 2     
##  6     6 2     
##  7     7 1     
##  8     8 3     
##  9     9 2     
## 10    10 3 

# Check the sum and number of elements per group
test %>% 
  dplyr::group_by(.folds) %>% 
  dplyr::summarize(sum_ = sum(x),
                   n_members = dplyr::n())

## # A tibble: 3 x 3
##   .folds       sum_ n_members
##   <fct>       <dbl>     <int>
## 1 1      1666690952     33333
## 2 2      1666716667     33334
## 3 3      1666642381     33333
test$z <- cut(cumsum(test$x), breaks = 3, labels = 1:3) 
test$z <- cut_interval(cumsum(test$x), n = 3, labels = 1:3)