直接生成Numpy/Pandas中所有平行对角线之和的方法?

2024-10-03 23:18:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个矩形(不能假设是正方形)熊猫数据帧的数字。假设我选择一个对角线方向(从左上到右下或从右上到下左)。我想计算一个序列,它的条目是原始数据帧沿着所选的一组平行对角线的值的和。要完全指定目标,您需要确定对角线是“锚定”在左侧还是“锚定”在右侧。对于下面的,我假设它们是“锚定”在左边。在

我可以毫不费力地做到:

import numpy as np
import pandas as pd

rectdf = pd.DataFrame(np.arange(15).reshape(5,3))

# result:
    0   1   2
0   0   1   2
1   3   4   5
2   6   7   8
3   9  10  11
4  12  13  14

我可以计算“从左上到右下”的对角线和,如下所示:

^{pr2}$

我可以通过将shift(-i)翻转到{}来计算“从右上到左下”的对角线和:

urllsums = pd.concat([rectdf.iloc[:, i].shift(i) for i in range(rectdf.shape[1])], axis=1)\
    .sum(axis=1, fillna=0)

# result:
0     0
1     4
2    12
3    21
4    30

这些结果都是正确的(也就是说,这段代码做了我想要的)。有没有更直接的方法来计算熊猫和纽比的总和?在


Tags: 数据importshiftasnp数字result方向
3条回答

您可能正在寻找numpy.trace()(文档中的here)来直接获得跟踪,或者{}来获得对角线向量documented here

首先,使用rectdf.as_matrix()将数据帧转换为numpy矩阵

然后:

np.trace(matrix, offset)

偏移量可以是正的也可以是负的,可以满足您所需的偏移量。在

例如,如果我们这样做:

^{pr2}$

我们得到输出:

12
22
30
21
12
6
2

对于一般矩阵,我们需要从-(rows - 1)到{},也就是说,如果我们有一个变量rows和一个变量columns

a = np.arange(rows * columns).reshape(rows, columns)
for x in range(-(rows - 1), columns): print np.trace(a, x)

简短回答

请看最后快速但复杂的函数。在

发展

trace进行迭代是很好的,但我不确定它是否比pandas解决方案更好。这两种方法都涉及对角线或列上的迭代。从概念上讲,它更简单或更干净,但我不确定速度,尤其是在大型阵列上。在

每条对角线有不同的长度,[[12],[9,13],...]。这是一个巨大的危险信号,警告我们块数组操作即使不是不可能的话也是困难的。在

使用scipy.sparse我可以构造一个二维数组,该数组可以求和得到这些轨迹:

In [295]: from scipy import sparse
In [296]: xs=sparse.dia_matrix(x)
In [297]: xs.data
Out[297]: 
array([[12,  0,  0],
       [ 9, 13,  0],
       [ 6, 10, 14],
       [ 3,  7, 11],
       [ 0,  4,  8],
       [ 0,  1,  5],
       [ 0,  0,  2]])
In [298]: np.sum(xs.data,axis=1)
Out[298]: array([12, 22, 30, 21, 12,  6,  2])

这种稀疏格式将其data存储在2d数组中,并进行必要的移位。事实上,你的pd.concat产生了类似的结果:

^{pr2}$

看起来sparse创建了这个data数组,方法是从np.zeros开始,并用适当的索引填充它:

 data[row_indices, col_indices] = x.ravel()

比如:

In [344]: i=[4,5,6,3,4,5,2,3,4,1,2,3,0,1,2]
In [345]: j=[0,1,2,0,1,2,0,1,2,0,1,2,0,1,2]
In [346]: z=np.zeros((7,3),int)
In [347]: z[i,j]=x.ravel()[:len(i)]
In [348]: z
Out[348]: 
array([[12,  0,  0],
       [ 9, 13,  0],
       [ 6, 10, 14],
       [ 3,  7, 11],
       [ 0,  4,  8],
       [ 0,  1,  5],
       [ 0,  0,  2]])

尽管我仍然需要一种为任何形状创建i,j的方法。对于j来说,这很简单:

j=np.tile(np.arange(3),5)
j=np.tile(np.arange(x.shape[1]),x.shape[0])

重塑i

In [363]: np.array(i).reshape(-1,3)
Out[363]: 
array([[4, 5, 6],
       [3, 4, 5],
       [2, 3, 4],
       [1, 2, 3],
       [0, 1, 2]])

让我用以下方法重现:

In [371]: ii=(np.arange(3)+np.arange(5)[::-1,None]).ravel()
In [372]: ii
Out[372]: array([4, 5, 6, 3, 4, 5, 2, 3, 4, 1, 2, 3, 0, 1, 2])

所以一起:

def all_traces(x):
    jj = np.tile(np.arange(x.shape[1]),x.shape[0])
    ii = (np.arange(x.shape[1])+np.arange(x.shape[0])[::-1,None]).ravel()
    z = np.zeros(((x.shape[0]+x.shape[1]-1),x.shape[1]),int)
    z[ii,jj] = x.ravel()
    return z.sum(axis=1)

它需要对各种形状进行更多的测试。在

此函数比跟踪上的迭代更快,即使使用这个小尺寸的数组:

In [387]: timeit all_traces(x)
10000 loops, best of 3: 70.5 µs per loop
In [388]: timeit [np.trace(x,i) for i in range(-(x.shape[0]-1),x.shape[1])]
10000 loops, best of 3: 106 µs per loop

对于2D numpy数组A这可能是(?)对角线求和的最短代码:

np.bincount(sum(np.indices(A.shape)).flat, A.flat)

要求对角的和,可以np.fliplr数组。在

相关问题 更多 >