Suppose if we have a tabular CPD (conditional probability distribution) like this
| C | C_0 | C_0 | C_0 | C_0 | C_1 | C_1 | C_1 | C_1 |
| B | B_0 | B_0 | B_1 | B_1 | B_0 | B_0 | B_1 | B_1 |
| A | A_0 | A_1 | A_0 | A_1 | A_0 | A_1 | A_0 | A_1 |
| J_0 | 0.9 | 0.3 | 0.9 | 0.3 | 0.8 | 0.8 | 0.4 | 0.4 |
| J_1 | 0.1 | 0.7 | 0.1 | 0.7 | 0.2 | 0.2 | 0.6 | 0.6 |
then there should be a method to switch the tuples inside the tables (for example if the user wants to switch B
and A
inside the table such that B
is the most rapidly changing value).
Keep in mind the values also change accordingly. After switching A
and B
inside the table it should look something like this.
| C | C_0 | C_0 | C_0 | C_0 | C_1 | C_1 | C_1 | C_1 |
| A | A_0 | A_0 | A_1 | A_1 | A_0 | A_0 | A_1 | A_1 |
| B | B_0 | B_1 | B_0 | B_1 | B_0 | B_1 | B_0 | B_1 |
| J_0 | 0.9 | 0.9 | 0.3 | 0.3 | 0.8 | 0.4 | 0.8 | 0.4 |
| J_1 | 0.1 | 0.1 | 0.7 | 0.7 | 0.2 | 0.6 | 0.2 | 0.6 |
So the problem boils down to:
Find new values according to new ordering of the headings where each heading can have a different cardinality(number of values it can take).
For this I have written the below method that gets the job done but that I don't find elegant or pythonic. This method is currently written for a single row which can be easily extended to the example given above of many lists.
def change_order(new_order, old_order, old_card, old_list):
if (set(new_order) - set(old_order)) or (set(old_order) - set(new_order)):
raise ValueError("New order either has missing or extra arguments")
else:
res = [-1]*len(old_list)
for i in range(len(old_list)):
d = {}
idx = i
for card, var in zip(old_card, old_order):
#prod *= card
d[var] = idx%card,card
idx //= card
new_index = 0
prod = 1
for var in new_order:
new_index += d[var][0]*prod
prod *= d[var][1]
res[new_index] = old_list[i]
return res
old_order = ['A','B','C']
old_card = [2,2,2]
new_order = ['B', 'A','C']
old_list = [0.9,0.3,0.9,0.3,0.8,0.8,0.4,0.4]
print(change_order(new_order, old_order, old_card, old_list))
[0.9, 0.9, 0.3, 0.3, 0.8, 0.4, 0.8, 0.4]
Idea behind what I have implemented can be taken from number (whole list is viewed as a number) representation in any base. So basically I am just rearranging the places in the new number. This is just to give an intuitive understanding of the code above. This explanation is very vague and should not be considered too seriously.
So, I want to ask if there is any other way to do this?
I was thinking of using reshape() method of numpy (list or numpy array both are acceptable to me, although any suggestions on which choice would be faster would be of great help). Even with reshape the best way I could come up with is one-to-one mapping between old ordering and new_ordering. So I googled and the best close answers I could find are this and this, but these don't sufficiently answer my question.
Edit:
I am making the requirements a little more stringent. One to one mapping is not acceptable. If there are some methods available in numpy or python that can reorder it neatly by slicing multiple columns at once to create new ordering it would be better.
P.S: I have found a way that I think meets the requirements, it is short, clear and uses already available methods to do the job and I have added it as answer below.