Reputation: 23
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
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