重新排列列表中元素的更好方法

时间:2016-01-14 23:08:10

标签: python algorithm numpy

假设我们有像这样的表格CPD(条件概率分布)

| 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 |

然后应该有一个方法来切换表格内的元组(例如,如果用户想要在表格中切换BA,那么B是最快的改变价值)。

请记住,值也会相应变化。在表格中切换AB后,它应该看起来像这样。

| 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 |

所以问题归结为:

  

根据每个标题的新排序查找新值   标题可以有不同的基数(它可以的值的数量   取)。

为此我写了下面的方法来完成工作,但我找不到优雅或pythonic。此方法目前针对单行编写,可以很容易地扩展到上面给出的许多列表的示例。

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]

我所实施的理念背后的理念可以从任何基础中的数字(整个列表被视为数字)表示中获取。所以基本上我只是重新排列新号码中的位置。这只是为了直观地理解上面的代码。这种解释非常模糊,不应该被认为过于严肃。

所以,我想问一下是否有其他方法可以做到这一点?

我正在考虑使用numpy的reshape()方法(list或numpy数组都是我可以接受的,尽管对哪个选择更快的任何建议都会有很大的帮助)。即使重新塑造了我能想到的最好的方法,也就是旧排序和new_ordering之间的一对一映射。所以我用谷歌搜索,我能找到的最好的答案是thisthis,但这些答案还不足以回答我的问题。

编辑:

我要求的要求更严格一些。一对一映射是不可接受的。如果numpy或python中有一些方法可以通过一次切割多个列来整齐地重新排序它以创建新的排序,那就更好了。

P.S:我找到了一种我认为符合要求的方法,它简短明了,并且使用已有的方法来完成这项工作,我已将其添加为以下答案。

1 个答案:

答案 0 :(得分:1)

我在另一个SO问题中找到了一种方法,我没有删除它,因为找到另一个question可能有点困难,而且在我的情况下需要一些小技巧。事实上,如果我们提供新的排序,转置方法本身就会这样做。 以下是根据链接的简短实现:

def change_order2(new_order, old_order, old_card, old_list):
    import numpy as np
    new_ord = [~old_order.index(letter) for letter in new_order]     
    old_list = np.array(old_list).reshape(old_card[::-1])
    new_list = np.transpose(old_list, new_ord[::-1]).flatten()
    return new_list