简体   繁体   中英

Finding the best combinations

I'm looking for the approach to solve the following problem.

Suppose I've this product grid.

table = [{'Products': 'Prod1', 'Unit1': 32, 'Unit2': 32, 'Unit3': 27, 'Unit4': 15 },
         {'Products': 'Prod2', 'Unit1': 35, 'Unit2': 12, 'Unit3': 19, 'Unit4': 29 },
         {'Products': 'Prod3', 'Unit1': 37, 'Unit2': 36, 'Unit3': 36, 'Unit4': 19 },
         {'Products': 'Prod4', 'Unit1': 16, 'Unit2': 15, 'Unit3': 18, 'Unit4': 31 },
         {'Products': 'Prod5', 'Unit1': 14, 'Unit2': 32, 'Unit3': 20, 'Unit4': 33 },
         {'Products': 'Prod6', 'Unit1': 10, 'Unit2': 33, 'Unit3': 28, 'Unit4': 36 },
         {'Products': 'Prod7', 'Unit1': 18, 'Unit2': 22, 'Unit3': 27, 'Unit4': 30 },
         {'Products': 'Prod8', 'Unit1': 11, 'Unit2': 13, 'Unit3': 20, 'Unit4': 26 }]

df = pd.DataFrame(table)

Each value reflects the maximum revenue I'll get by selling this product. Eg Selling 2 units of prod1 , I'll get $32. For each product I can sell maximum of 4 units. And total I can sell maximum of 16 units (4*4). My objective is to maximize the total revenue. In the example given I'll sell the following combinations to maximize my revenue:

{prod1: 2 units (32),
 prod2: 1 unit  (35),
 prod3: 1 unit  (37),
 prod4: 4 units (31),
 prod5: 4 units (33),
 prod6: 4 units (36)}

My question is, how I can formulate it algorithmically?

The trivial solution would be to test all options and determine the option that gives the maximum revenue.

All options can be generated using itertools.product :

from itertools import product
options = product(range(5), repeat=8)

One could either sell 0, 1, 2, 3, or 4 units of each product so I use range(5) as first argument and there are 8 products so I used repeat=8 .

However we don't want to maximize the number of units sold but the revenue when 16 or less units are sold. In this case I use max with a key function. The key-function returns a negative value if there are more than 16 units sold otherwise it checks what revenue is made based on the list of dicts and the number of sold units:

def total_revenue(sales):
    if sum(sales) > 16:  # discard the revenue if more than 16 units are sold.
        return -1
    else: 
        # Sum the revenue based on the sales and the values in the table.
        sum_ = 0
        for idx, num in enumerate(sales):
            if num:
                sum_ += table[idx]['Unit{}'.format(num)]
        return sum_

maximized_revenue = max(options, key=total_revenue)
print(maximized_revenue)
# (1, 1, 1, 4, 2, 2, 1, 4)

This is a tuple, that still needs to be transformed to the desired dictionary:

{'prod{}'.format(idx+1): num for idx, num in enumerate(maximized_revenue)}
# {'prod1': 1,
#  'prod2': 1,
#  'prod3': 1,
#  'prod4': 4,
#  'prod5': 2,
#  'prod6': 2,
#  'prod7': 1,
#  'prod8': 4}

There is still room for improvement because product generates lots of unneccessary values (more than 16 items sold). You could create a custom generator that works like product with the repeat argument but doesn't generate solutions when more than 16 units are already sold.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM