【问题标题】:Shuffle in one dimension of a matrix(effeciently)?在矩阵的一维中洗牌(有效地)?
【发布时间】:2013-11-05 01:09:09
【问题描述】:

我试图编写一个函数来获取二维点矩阵和概率p,并以概率p 更改或交换每个点的坐标

所以我问了question,我试图使用二进制序列作为特定矩阵swap_matrix=[[0,1],[1,0]] 的幂的数组来随机(以特定比例)交换给定的一组二维点的坐标.但是我意识到幂函数只接受整数值而不接受数组。并且 shuffle 是我可以理解的整个矩阵,你不能指定一个特定的维度。

拥有这两个功能中的任何一个都可以。

例如:

swap(a=[[1,2],[2,3],[3,4],[3,5],[5,6]],b=[0,0,0,1,1])

应该返回[[1,2],[2,3],[3,4],[5,3],[6,5]]

刚刚冒出来现在我正在编辑的想法是:

def swap(mat,K,N):
    #where K/N is the proportion and K and N are natural numbers
    #mat is a N*2 matrix that I am planning to randomly changes 
    #it coordinates of each row or keep it as it is
    a=[[[0,1],[1,0]]]
    b=[[[1,0],[0,1]]]
    a=np.repeat(a,K,axis=0)
    b=np.repeat(b,N-K,axis=0)
    out=np.append(a,b,axis=0)
    np.random.shuffle(out)
    return np.multiply(mat,out.T)

我得到一个错误,因为我不能只展平一次以使矩阵可乘!

我再次在寻找一种有效的方法(在 Matlab 上下文中矢量化)。

附:在我的特殊情况下,矩阵的形状为(N,2),如果有帮助的话,第二列就是所有的。

【问题讨论】:

    标签: python random numpy swap shuffle


    【解决方案1】:

    也许这对您的目的来说已经足够了。在快速测试中,它似乎比直接的 for 循环方法快 13 倍(@Naji,发布您的“低效”代码有助于进行比较)。

    根据 Jaime 的评论编辑了我的代码

    def swap(a, b):
        a = np.copy(a)
        b = np.asarray(b, dtype=np.bool)
        a[b] = a[b, ::-1]  # equivalent to: a[b] = np.fliplr(a[b])
        return a
    
    # the following is faster, but modifies the original array
    def swap_inplace(a, b):
        b = np.asarray(b, dtype=np.bool)
        a[b] = a[b, ::-1]
    
    
    print swap(a=[[1,2],[2,3],[3,4],[3,5],[5,6]],b=[0,0,0,1,1])
    

    输出:

    [[1 2]
     [2 3]
     [3 4]
     [5 3]
     [6 5]]
    

    编辑以包含更详细的时间安排

    我想知道我是否仍然可以使用 Cython 加快速度,所以我对效率进行了更多调查 :-) 我认为结果值得一提(因为效率是实际问题的一部分),但我确实道歉预付额外代码的数量。

    首先是结果。“cython”函数显然是最快的,比上面提出的 Numpy 解决方案快 10 倍。我提到的“钝循环方法”是由名为“循环”的函数给出的,但事实证明还有更快的方法可以想象。我的纯 Python 解决方案只比上面的矢量化 Numpy 代码慢 3 倍!另一件需要注意的是,“swap_inplace”大多数时候只比“swap”快一点。此外,随着随机矩阵 ab 的不同,时间也会有所不同......所以现在你知道了 :-)

    function     | milisec | normalized
    -------------+---------+-----------
    loop         | 184     | 10.
    double_loop  |  84     |  4.7
    pure_python  |  51     |  2.8
    swap         |  18     |  1
    swap_inplace |  17     |  0.95
    cython       | 1.9     |  0.11
    

    以及我使用的其余代码(似乎我认真对待了这种方式:P):

    def loop(a, b):
        a_c = np.copy(a)
        for i in xrange(a.shape[0]):
            if b[i]:
                a_c[i,:] = a[i, ::-1]
    
    def double_loop(a, b):
        a_c = np.copy(a)
        n, m = a_c.shape
        for i in xrange(n):
            if b[i]:
                for j in xrange(m):
                    a_c[i, j] = a[i, m-j-1]
        return a_c
    
    from copy import copy
    def pure_python(a, b):
        a_c = copy(a)
        n, m = len(a), len(a[0])
        for i in xrange(n):
            if b[i]:
                for j in xrange(m):
                    a_c[i][j] = a[i][m-j-1]
        return a_c
    
    import pyximport; pyximport.install()
    import testcy
    def cython(a, b):
        return testcy.swap(a, np.asarray(b, dtype=np.uint8))
    
    def rand_bin_array(K, N):
        arr = np.zeros(N, dtype=np.bool)
        arr[:K]  = 1
        np.random.shuffle(arr)
        return arr
    
    N = 100000
    a = np.random.randint(0, N, (N, 2))
    b = rand_bin_array(0.33*N, N)
    
    # before timing the pure python solution I first did:
    a = a.tolist()
    b = b.tolist()
    
    
    ######### In the file testcy.pyx #########
    
    #cython: boundscheck=False
    #cython: wraparound=False
    
    import numpy as np
    cimport numpy as np
    
    def swap(np.ndarray[np.int_t, ndim=2] a, np.ndarray[np.uint8_t, ndim=1] b):
        cdef np.ndarray[np.int_t, ndim=2] a_c
        cdef int n, m, i, j
        a_c = a.copy()
        n = a_c.shape[0]
        m = a_c.shape[1]
        for i in range(n):
            if b[i]:
                for j in range(m):
                    a_c[i, j] = a[i, m-j-1]
        return a_c
    

    【讨论】:

    • 你的太棒了。我发布了我的,但它有一个我需要解决的问题!
    • +1 我怀疑是否有更快的方法。但是您正在进行就地交换,即覆盖输入数组,最好先复制数组,修改副本并返回它。最好强制第二个数组在函数内部是布尔值,例如b = np.asarray(b, dtype=np.bool).
    • 我会一直不回答这个问题,看看是否有更好的建议,然后接受它。再次感谢。
    • @Jaime,感谢您的反馈,我相应地修改了代码。
    • @moarningsun,谢谢分享。但现在我的问题更严重了,因为我不需要交换元素,我需要根据相同大小的数组应用 90 度旋转,数字从 0 到 3 以显示旋转 90 度的次数。为此,我认为没有任何直接的方法,我必须在这里使用我自己的代码!
    猜你喜欢
    • 2015-01-14
    • 1970-01-01
    • 2015-12-02
    • 2021-03-13
    • 1970-01-01
    • 2021-06-28
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多