Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 交换numpy矩阵中的零_Python_Pandas_Numpy_Matrix_Scikit Learn - Fatal编程技术网

Python 交换numpy矩阵中的零

Python 交换numpy矩阵中的零,python,pandas,numpy,matrix,scikit-learn,Python,Pandas,Numpy,Matrix,Scikit Learn,我有这样一个numpy矩阵: array([[2, 1, 23, 32], [34, 3, 3, 0], [3, 33, 0, 0], [32, 0, 0, 0]], dtype=int32) 现在我想将所有数字向右移动,并将零向左移动,如下所示: array([[2, 1, 23, 32], [0, 34, 3, 3], [0, 0, 3, 33], [0, 0, 0, 32]], dtype=

我有这样一个numpy矩阵:

array([[2,  1, 23, 32],
       [34, 3, 3, 0],
       [3, 33, 0, 0],
       [32, 0, 0, 0]], dtype=int32)
现在我想将所有数字向右移动,并将零向左移动,如下所示:

array([[2, 1,  23, 32],
       [0, 34, 3,  3],
       [0, 0,  3,  33],
       [0, 0,  0,  32]], dtype=int32)

有没有一种简单的python方法可以做到这一点,也许是使用numpy、pandas或scikit learn的api方法?

以下是一种矢量化的方法-

样本运行-

In [90]: a
Out[90]: 
array([[ 2,  1, 23, 32],
       [34,  0,  3,  0],  # <== Added a zero in between for variety
       [ 3, 33,  0,  0],
       [32,  0,  0,  0]])

# After code run -

In [92]: a
Out[92]: 
array([[ 2,  1, 23, 32],
       [ 0,  0, 34,  3],
       [ 0,  0,  3, 33],
       [ 0,  0,  0, 32]])
In [94]: a
Out[94]: 
array([[1, 1, 2, 3, 1, 0, 3, 0, 2, 1],
       [2, 1, 0, 1, 2, 0, 1, 3, 1, 1],
       [1, 2, 0, 3, 0, 3, 2, 0, 2, 2]])

# After code run -

In [96]: a
Out[96]: 
array([[0, 0, 1, 1, 2, 3, 1, 3, 2, 1],
       [0, 0, 2, 1, 1, 2, 1, 3, 1, 1],
       [0, 0, 0, 1, 2, 3, 3, 2, 2, 2]])
运行时测试

适用于一般案例的方法-

# Proposed in this post
def masking_based(a):
    valid_mask = a!=0
    flipped_mask = valid_mask.sum(1,keepdims=1) > np.arange(a.shape[1]-1,-1,-1)
    a[flipped_mask] = a[valid_mask]
    a[~flipped_mask] = 0
    return a

# @Psidom's soln            
def sort_based(a):
    return a[np.arange(a.shape[0])[:, None], (a != 0).argsort(1, kind="mergesort")]
时间安排-

In [205]: a = np.random.randint(0,4,(1000,1000))

In [206]: %timeit sort_based(a)
10 loops, best of 3: 30.8 ms per loop

In [207]: %timeit masking_based(a)
100 loops, best of 3: 6.46 ms per loop

In [208]: a = np.random.randint(0,4,(5000,5000))

In [209]: %timeit sort_based(a)
1 loops, best of 3: 961 ms per loop

In [210]: %timeit masking_based(a)
1 loops, best of 3: 151 ms per loop
方法:

In [181]:
# construct df from array
df = pd.DataFrame(a)
# call apply and call np.roll rowise and roll by the number of zeroes
df.apply(lambda x: np.roll(x, (x == 0).sum()), axis=1).values

Out[181]:
array([[ 2,  1, 23, 32],
       [ 0, 34,  3,  3],
       [ 0,  0,  3, 33],
       [ 0,  0,  0, 32]])

这使用了
apply
,因此我们可以调用
np。在非基于numpython的python中,通过每行中的零数来滚动
-

>>> arr = [[2,  1, 23, 32],
...        [34, 3, 3, 0],
...        [3, 33, 0, 0],
...        [32, 0, 0, 0]]
... 
>>> t_arr = [[0 for _ in range(cur_list.count(0))]\
            + [i for i in cur_list if i!=0]\
            for cur_list in arr]
>>> t_arr
[[2, 1, 23, 32], [0, 34, 3, 3], [0, 0, 3, 33], [0, 0, 0, 32]]

您还可以将
numpy.argsort
用于:


您还可以在蒙版数组上执行排序,该方法将数组沿最后一个轴进行排序,
axis=-1
,如图所示:

np.ma.array(a, mask=a!=0).sort()
现在
a
变成:

array([[ 2,  1, 23, 32],
       [ 0, 34,  3,  3],
       [ 0,  0,  3, 33],
       [ 0,  0,  0, 32]])

唯一的缺点是,它的速度不如上面提到的一些方法,但仍然有一个短的单行程序。

一个基于行滚动的解决方案,本着
@EDChum的
熊猫版的精神:

def rowroll(arr):
    for row in arr:
        row[:] = np.roll(row,-np.count_nonzero(row))
    return arr
In [221]: rowroll(arr.copy())
Out[221]: 
array([[ 2,  1, 23, 32],
       [ 0, 34,  3,  3],
       [ 0,  0,  3, 33],
       [ 0,  0,  0, 32]])
np.count\u nonzero
是一种快速编译的查找非零数量的方法。
np.where
使用它来查找其返回大小

但是看看
np.roll
代码,我认为这项任务过于复杂,因为它可以与多个轴一起工作

这看起来更混乱,但我怀疑它即使不比
滚动快,也同样快:

def rowroll(arr):
    for row in arr:
        n = np.count_nonzero(row)
        temp = np.zeros_like(row)
        temp[-n:] = row[:n]
        row[:] = temp
    return arr

roll
解决方案要求原始0中有尾随的0,而不是零散的0。

这是一种更好的通用方法,因为它完全解决了OP所述的问题,但OP发布的样本数据不一定需要这些,仍然+1关于计时呢?你能比较解决方案吗?谢谢。@jezrael为尝试解决一般情况的解决方案添加了这些解决方案。这不会维持秩序。您需要使用
'mergesort'
来执行此操作。顺便说一句,好主意,问题中提出的简短建议@迪瓦卡,你说得对。没有注意到这一点。
df.apply
只是在行中迭代吗?将相同的
lambda
应用于数组的每一行,而不进行
pd
转换,如何?@hpaulj是的,
np.roll
不接受除标量以外的任何东西,这就是为什么我这样做的原因发布的解决方案中有一个对您有效吗?是的!我正试图决定接受什么样的答案,这很难
def rowroll(arr):
    for row in arr:
        row[:] = np.roll(row,-np.count_nonzero(row))
    return arr
In [221]: rowroll(arr.copy())
Out[221]: 
array([[ 2,  1, 23, 32],
       [ 0, 34,  3,  3],
       [ 0,  0,  3, 33],
       [ 0,  0,  0, 32]])
def rowroll(arr):
    for row in arr:
        n = np.count_nonzero(row)
        temp = np.zeros_like(row)
        temp[-n:] = row[:n]
        row[:] = temp
    return arr