Matthew Hartwig
Matthew Hartwig

Reputation: 23

All combinations from data frame in R

I'm trying to find all combinations (not permutations, order doesn't matter) from a list with various restrictions on the structure of each combination. I know combn() will do the trick for a simple list and I've tried using sample(), but my need is more complex.

I have a data frame that has three columns, name, type, cost. I want to find all possible combinations of names in sets of 7 (so 7 names) where one is of type 1, three are of type 2 and the rest are of type 3 and the total cost is less than a set variable.

I'm at a total loss for how to do this and I'm not even certain R is the right language to do this in. Should I try a for loop with some nested if statements?

> dput(head(sample))
structure(list(Name = structure(c(6L, 8L, 4L, 9L, 2L, 5L), .Label = c("Amber", 
"Cyndi", "E", "Eric", "Hannah", "Jason", "Jesse", "Jim ", "Lisa", 
"Lucy", "Matt", "Ryan", "Tat"), class = "factor"), Type = c(2L, 
3L, 3L, 1L, 3L, 3L), Cost = c(6000L, 6200L, 9000L, 2000L, 8000L, 
4500L)), .Names = c("Name", "Type", "Cost"), row.names = c(NA, 
6L), class = "data.frame")

and my sessionInfo()

> sessionInfo()
R version 3.1.1 (2014-07-10)
Platform: x86_64-apple-darwin10.8.0 (64-bit)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] plyr_1.8.1    ggplot2_1.0.0 dplyr_0.2    

loaded via a namespace (and not attached):
 [1] assertthat_0.1   colorspace_1.2-4 digest_0.6.4     grid_3.1.1       gtable_0.1.2     MASS_7.3-33     
 [7] munsell_0.4.2    parallel_3.1.1   proto_0.3-10     Rcpp_0.11.2      reshape2_1.4     scales_0.2.4    
[13] stringr_0.6.2    tools_3.1.1     

Example data:

Name    Type    Cost
Jason   2   6000
Jim     3   6200
Eric    3   9000
Lisa    1   2000
Cyndi   3   8000
Hannah  3   4500
E       2   7200
Matt    1   3200
Jesse   3   1200
Tat     3   3200
Ryan    1   5600
Amber   2   5222
Lucy    2   1000

One possible combination if total cost is set to 60k:

Lisa, Jason, Amber, Lucy, Tat, Jesse, Hannah

That's one possible combination, as Lisa is type 1, Jason, Amber and Lucy are type 2 and the remaining three are type 3 and the total cost of all 7 is below 60k. Another possible combination would be:

Ryan, Jason, Amber, Lucy, Tat, Jesse, Hannah

Ryan has replaced Lisa as the type 1 from the first combination. The cost is still below 60k.

I'm trying to get all possible combinations where the conditions above are true.

Upvotes: 1

Views: 2203

Answers (1)

petew
petew

Reputation: 691

One possible solution using loops (maybe not the most efficient):

# Example data
Name <- c('Jason', 'Jim','Eric', 'Lisa', 'Cyndi', 'Hanna','Jon','Matt',
          'Jerry','Emily','Mary','Cynthia')
Type <- c(2, 1, 3, 3, 2, 3, 3, 1, 2, 2, 3, 2)
Cost <- c(9200, 8200, 9000, 8700, 9100, 8900, 9800, 7800, 9600, 
          9300, 8100, 7800)

df <- data.frame(Name, Type,Cost)
v1 <- subset(df, Type==1)
v2 <- subset(df, Type==2)
v3 <- subset(df, Type==3)

# Get all combinations of desired size of subsets
m1 <- v1$Name
m2 <- combn(v2$Name, 3)
m3 <- combn(v3$Name, 3)

n1 <- length(m1)
n2 <- ncol(m2)
n3 <- ncol(m3)

# put combinations of subsets together
all.combs <- as.list(rep(NA, n1*n2*n3))
idx <- 1
for (i in 1:n1) {
  for (j in 1:n2) {
    for (k in 1:n3) {
      all.combs[[idx]] <- c(as.character(m1[i]),
                            as.character(m2[,j]),
                            as.character(m3[,k]))
      idx <- idx + 1
    }
  }
}

# Check for total cost < 60K
cond <- rep(NA, length(all.combs))
for (i in 1:length(all.combs)) {
   sum <- 0
   for (j in 1:7) {
      sum <- sum + df$Cost[df$Name==all.combs[[i]][j]]
   }
   cond[i] <- sum < 60000
}
res <- all.combs[cond]
res

Upvotes: 1

Related Questions