Home > OS >  Changing variable names dynamically, evaluating and populating a dictionary
Changing variable names dynamically, evaluating and populating a dictionary

Time:03-03

I use pyomo and gurobi to solve optimization problems. Now I have 5 variables whose names are like model.str where str can be [x, y, z, w, s]. I would like to replace str with each of these strings and evaluate it for 20 iterations. For example I need values for model.x[1], model.x[2] and etc. I have used the following code which is not very nice but almost got my result:

dict = {}
var_names = ["x", "y", "z", "w", "s"]
for i in var_names:
    for t in model.T:
        var_name = "model."   str(i)   "["   str(t)   "]"
        dict[var_name] = pe.value(eval(var_name))

The result of this code is:

{'model.x1': 5000.0, 'model.x[2]': 5000.0, 'model.x[3]': 6000.0, 'model.x[4]': 7000.0, 'model.x[5]': 8000.0, 'model.x[6]': 9000.0, 'model.x[7]': 10000.0, 'model.x[8]': 11000.0, 'model.x[9]': 12000.0, 'model.x[10]': 13000.0, 'model.x[11]': 14000.0, 'model.x[12]': 15000.0, 'model.x[13]': 16000.0, 'model.x[14]': 17000.0, 'model.x[15]': 18000.0, 'model.x[16]': 19000.0, 'model.x[17]': 20000.0, 'model.x[18]': 21000.0, 'model.x[19]': 21000.0, 'model.x[20]': 21000.0, 'model.y1': 0.0, 'model.y[2]': 0.0, 'model.y[3]': 0.0, 'model.y[4]': 0.0, 'model.y[5]': 0.0, 'model.y[6]': 0.0, 'model.y[7]': 0.0, 'model.y[8]': 0.0, 'model.y[9]': 0.0, 'model.y[10]': 0.0, 'model.y[11]': 0.0, 'model.y[12]': 0.0, 'model.y[13]': 0.0, 'model.y[14]': 0.0, 'model.y[15]': 0.0, 'model.y[16]': 0.0, 'model.y[17]': 0.0, 'model.y[18]': 0.0, 'model.y[19]': 0.0, 'model.y[20]': 0.0, 'model.z1': 0.0, 'model.z[2]': 0.0, 'model.z[3]': 1000.0, 'model.z[4]': 1000.0, 'model.z[5]': 1000.0, 'model.z[6]': 1000.0, 'model.z[7]': 1000.0, 'model.z[8]': 1000.0, 'model.z[9]': 1000.0, 'model.z[10]': 1000.0, 'model.z[11]': 1000.0, 'model.z[12]': 1000.0, 'model.z[13]': 1000.0, 'model.z[14]': 1000.0, 'model.z[15]': 1000.0, 'model.z[16]': 1000.0, 'model.z[17]': 1000.0, 'model.z[18]': 1000.0, 'model.z[19]': 0.0, 'model.z[20]': 0.0, 'model.w1': 4000.0, 'model.w[2]': 5000.0, 'model.w[3]': 6000.0, 'model.w[4]': 7000.0, 'model.w[5]': 8000.0, 'model.w[6]': 9000.0, 'model.w[7]': 10000.0, 'model.w[8]': 11000.0, 'model.w[9]': 12000.0, 'model.w[10]': 13000.0, 'model.w[11]': 14000.0, 'model.w[12]': 15000.0, 'model.w[13]': 16000.0, 'model.w[14]': 17000.0, 'model.w[15]': 18000.0, 'model.w[16]': 19000.0, 'model.w[17]': 20000.0, 'model.w[18]': 21000.0, 'model.w[19]': 21000.0, 'model.w[20]': 21000.0, 'model.s1': 0.0, 'model.s[2]': 0.0, 'model.s[3]': 0.0, 'model.s[4]': 0.0, 'model.s[5]': 0.0, 'model.s[6]': 0.0, 'model.s[7]': 0.0, 'model.s[8]': 0.0, 'model.s[9]': 0.0, 'model.s[10]': 0.0, 'model.s[11]': 0.0, 'model.s[12]': 0.0, 'model.s[13]': 0.0, 'model.s[14]': 0.0, 'model.s[15]': 0.0, 'model.s[16]': 0.0, 'model.s[17]': 0.0, 'model.s[18]': 0.0, 'model.s[19]': 1000.0, 'model.s[20]': 2000.0}

However what I need is to put every model.x[i] values for a dictionary key x so that I have a dictionary with x, y, z, w, s as keys and their values as values in a list fore example to create a pandas data frame in the end.

I know for sure there is a better way of doing it, since creating variable names in every iteration is not very efficient and I am fairly new to Python. If necessary I can also provide the rest of the codes for clarity so please just let me know if I need to provide further details.

I appreciate your help in advance.

Updated Solution After receiving some great tips from dear Matthew I came up with the following solution:

var_names = ["x", "y", "z", "w", "s"]
dict = {}

for i in var_names:
    var_name = f"model.{i}"
    for t in model.T:
        var = f"model.{i}[{t}]"
        if str(var_name) in dict:
            dict[str(var_name)].append(pe.value(eval(var)))
        else :
            dict[str(var_name)] = [pe.value(eval(var))]

import pandas as pd
df = pd.DataFrame(dict)
print(df)

The output:

    model.x  model.y  model.z  model.w  model.s
0    5000.0      0.0      0.0   4000.0      0.0
1    5000.0      0.0      0.0   5000.0      0.0
2    6000.0      0.0   1000.0   6000.0      0.0
3    7000.0      0.0   1000.0   7000.0      0.0
4    8000.0      0.0   1000.0   8000.0      0.0
5    9000.0      0.0   1000.0   9000.0      0.0
6   10000.0      0.0   1000.0  10000.0      0.0
7   11000.0      0.0   1000.0  11000.0      0.0
8   12000.0      0.0   1000.0  12000.0      0.0
9   13000.0      0.0   1000.0  13000.0      0.0
10  14000.0      0.0   1000.0  14000.0      0.0
11  15000.0      0.0   1000.0  15000.0      0.0
12  16000.0      0.0   1000.0  16000.0      0.0
13  17000.0      0.0   1000.0  17000.0      0.0
14  18000.0      0.0   1000.0  18000.0      0.0
15  19000.0      0.0   1000.0  19000.0      0.0
16  20000.0      0.0   1000.0  20000.0      0.0
17  21000.0      0.0   1000.0  21000.0      0.0
18  21000.0      0.0      0.0  21000.0   1000.0
19  21000.0      0.0      0.0  21000.0   2000.0

CodePudding user response:

I had to improvise a bit without access to model.T and pe.value(eval(var_name)) but I think this is close to what you want. I used an f-string to clean up your var_name syntax. Next we check to see if a key is already in the_dict with .get() and extend or append as needed. Otherwise, we create a new key. Finally, we can just pass the_dict to the DataFrame constructor.

If this doesn't work for you, post a comment and I'll assist until it does. Providing a sample list for model.T would be a big help.

import random
import pandas as pd

the_dict = {}

var_names = ["x", "y", "z", "w", "s"]
model_t = [1, 2, 3, 1, 2, 3, 1, 2, 3]

for i in var_names:
    for t in model_t:
        var_name = f"model.{i}[{t}]"
        if the_dict.get(var_name, False):
            if isinstance(var_name, list):
                the_dict[var_name].extend(random.randint(3, 9))
            else:
                the_dict[var_name].append(random.randint(3, 9))
        else:
            the_dict[var_name] = [random.randint(3, 9)]

the_dict output:

{'model.x[1]': [3, 8, 5],
 'model.x[2]': [8, 3, 9],
 'model.x[3]': [9, 6, 7],
 'model.y[1]': [7, 4, 5],
 'model.y[2]': [3, 6, 6],
 'model.y[3]': [6, 7, 4],
 'model.z[1]': [6, 9, 9],
 'model.z[2]': [8, 8, 7],
 'model.z[3]': [7, 4, 5],
 'model.w[1]': [4, 9, 3],
 'model.w[2]': [5, 9, 5],
 'model.w[3]': [4, 9, 5],
 'model.s[1]': [4, 8, 5],
 'model.s[2]': [7, 6, 7],
 'model.s[3]': [9, 5, 8]}

Now let's make a pandas df.

df = pd.DataFrame(the_dict)

df ouput:

    model.x[1]  model.x[2]  model.x[3]  model.y[1]  model.y[2]  model.y[3]...
0   3           8           9           7           3           6   
1   8           3           6           4           6           7   
2   5           9           7           5           6           4   
  • Related