python - Numpy:用 numpy 数组替换 numpy 数组中的零

标签 python numpy matrix

处理我想要旋转的数据。请注意,我仅限于 numpy,无法使用 pandas。原始数据如下所示:

data = [
  [ 1, a, [<metric1>, <metric2>] ],
  [ 1, b, [<metric1>, <metric2>] ],
  [ 2, b, [<metric1>, <metric2>] ],
  [ 2, c, [<metric1>, <metric2>] ],
  [ 3, a, [<metric1>, <metric2>] ],
  [ 3, c, [<metric1>, <metric2>] ],
  ...etc
]

使用 numpy 旋转我的数据:

rows, row_pos = np.unique(data[:, row_index], return_inverse=True)
cols, col_pos = np.unique(data[:, col_index], return_inverse=True)
pivot_table = np.zeros((len(rows), len(cols)), dtype=object)
pivot_table[row_pos, col_pos] = data[:, pivot_index]

结果格式为:

cols = [a, b, c, ...]
rows = [1, 2, 3, ...]
pivot_table = [
  [ [<metric1>, <metric2>], [<metric1>, <metric2>], 0, ... ],
  [ 0, [<metric1>, <metric2>], [<metric1>, <metric2>], ... ],
  [ [<metric1>, <metric2>], 0, [<metric1>, <metric2>], ... ],
  ...
]

最终呈现透视表,它会在其中记录零的位置,并将创建正确数量的单元格,以便表的格式正确。

这只是一个临时解决方法,因为最初我尝试用 numpy 数组替换零(即 [0,0])

pivot_table[pivot_table == 0] = [0,0]

但我收到以下错误:

TypeError: NumPy boolean array indexing assignment requires a 0 or 1-dimensional input, input has 2 dimensions

我的临时修复已经足够了,但是当我想做一些事情(例如获得一行列总和)时,我的临时修复会受到限制。我有很多方法,但不知道如何执行:

  1. 如上所述,用零列表替换事实后的零
  2. 最初使用 np.unique 中的索引创建表时,有一个默认值来填充表格,而不是零。
  3. 将指标从列表中提取到数组中,即 [ 1, a, <metric1>, <metric2> ] 。这可能是简化聚合函数的最佳解决方案。

对于上述任何一种方法有什么解决方案吗?

最佳答案

尝试重新创建您的案例:

In [182]: a,b,c = 0,1,2
In [183]: metric1, metric2 = 100,200
In [186]: data = [
     ...:   [ 1, a, [metric1, metric2] ],
     ...:   [ 1, b, [metric1, metric2] ],
     ...:   [ 2, b, [metric1, metric2] ],
     ...:   [ 2, c, [metric1, metric2] ],
     ...:   [ 3, a, [metric1, metric2] ],
     ...:   [ 3, c, [metric1, metric2] ],
     ...: ]
In [187]: 
In [187]: data
Out[187]: 
[[1, 0, [100, 200]],
 [1, 1, [100, 200]],
 [2, 1, [100, 200]],
 [2, 2, [100, 200]],
 [3, 0, [100, 200]],
 [3, 2, [100, 200]]]

In [189]: data = np.array(data,object)
In [190]: rows, row_pos = np.unique(data[:, 0], return_inverse=True)
     ...: cols, col_pos = np.unique(data[:, 1], return_inverse=True)
     ...: pivot_table = np.zeros((len(rows), len(cols)), dtype=object)

In [191]: pivot_table
Out[191]: 
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]], dtype=object)
In [192]: pivot_table[row_pos, col_pos] = data[:, 2]
In [193]: pivot_table
Out[193]: 
array([[list([100, 200]), list([100, 200]), 0],
       [0, list([100, 200]), list([100, 200])],
       [list([100, 200]), 0, list([100, 200])]], dtype=object)
In [194]: pivot_table[row_pos, col_pos]
Out[194]: 
array([list([100, 200]), list([100, 200]), list([100, 200]),
       list([100, 200]), list([100, 200]), list([100, 200])], dtype=object)
In [195]: _.shape
Out[195]: (6,)
In [196]: data[:,2].shape
Out[196]: (6,)

此分配在源形状(和数据类型)与目标形状 (6,) 匹配之间起作用。

In [197]: mask = pivot_table==0
In [198]: mask
Out[198]: 
array([[False, False,  True],
       [ True, False, False],
       [False,  True, False]])
In [199]: pivot_table[mask]
Out[199]: array([0, 0, 0], dtype=object)
In [200]: pivot_table[mask] = [0,0]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-200-83e0a7422802> in <module>()
----> 1 pivot_table[mask] = [0,0]

ValueError: NumPy boolean array indexing assignment cannot assign 2 input values to the 3 output values where the mask is true

不同的错误消息(不同的 numpy 版本?),但这表示我正在尝试将 2 个值放入 3 个槽中。它不处理 [0,0]作为单个项目,但作为 2。

分配标量元素没有问题:

In [203]: pivot_table[mask] = None
In [204]: pivot_table
Out[204]: 
array([[list([100, 200]), list([100, 200]), None],
       [None, list([100, 200]), list([100, 200])],
       [list([100, 200]), None, list([100, 200])]], dtype=object)

过去我使用 frompyfunc 取得了成功创建对象数据类型数组。定义一个小函数。我本来可以测试 0 或 type,但由于我已经插入了 None,所以让我们测试一下:

In [205]: def fun(x):
     ...:     if x is None: return [0,0]
     ...:     return x

将其应用于 pivot_table 的每个元素,生成一个新数组。

In [230]: arr1 = np.frompyfunc(fun,1,1)(pivot_table)
In [231]: arr1
Out[231]: 
array([[list([100, 200]), list([100, 200]), list([0, 0])],
       [list([0, 0]), list([100, 200]), list([100, 200])],
       [list([100, 200]), list([0, 0]), list([100, 200])]], dtype=object)

另一种方法,让我们尝试分配列表的列表:

In [240]: pivot_table[mask] = [[0,0] for _ in range(3)]    
TypeError: NumPy boolean array indexing assignment requires a 0 or 1-dimensional input, input has 2 dimensions

但是如果我尝试用 where 做同样的事情,它有效:

In [241]: pivot_table[np.where(mask)] = [[0,0] for _ in range(3)]
In [242]: pivot_table
Out[242]: 
array([[list([100, 200]), list([100, 200]), list([0, 0])],
       [list([0, 0]), list([100, 200]), list([100, 200])],
       [list([100, 200]), list([0, 0]), list([100, 200])]], dtype=object)

where它更像是您对 pivot_table 的原始分配.

In [243]: np.where(mask)
Out[243]: (array([0, 1, 2]), array([2, 0, 1]))

此数组索引在广播方面仍然可能存在问题,

In [244]: pivot_table[np.where(mask)] = [0,0]
ValueError: cannot copy sequence with size 2 to array axis with dimension 3

通常 bool 掩码索引的行为类似于 np.where(mask)索引,但显然这里对象数据类型和广播的相互作用与 bool 索引困惑。


Out[231]仍然是一个 (3,3) 数组,即使 a len 2 列出了所有元素。要将其转换为数值数组,我们必须执行以下操作:

In [248]: p = np.stack(pivot_table.ravel()).reshape(3,3,2)
In [249]: p
Out[249]: 
array([[[100, 200],
        [100, 200],
        [  0,   0]],

       [[  0,   0],
        [100, 200],
        [100, 200]],

       [[100, 200],
        [  0,   0],
        [100, 200]]])

np.concatenate (和*stack版本)可以将列表连接到数组中,但它必须以列表或平面数组开头,因此需要ravel和reshape。

np.array(pivot_table.tolist())也有效。


如果您构建了一个结构化数据数组(假设 metric 值是数字):

In [265]: data1 = np.array([tuple(x.tolist()) for x in data],'i,i,2i')
In [266]: data1
Out[266]: 
array([(1, 0, [100, 200]), (1, 1, [100, 200]), (2, 1, [100, 200]),
       (2, 2, [100, 200]), (3, 0, [100, 200]), (3, 2, [100, 200])],
      dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4', (2,))])
In [267]: data1['f2']
Out[267]: 
array([[100, 200],
       [100, 200],
       [100, 200],
       [100, 200],
       [100, 200],
       [100, 200]], dtype=int32)

这些值可以分配给 3d 数据透视表:

In [268]: p = np.zeros((len(rows), len(cols),2),int)
In [269]: p[row_pos, col_pos]=data1['f2']

fillvalue Paul Panzer 定义的数组,您的初始屏蔽赋值有效:

In [322]: fillvalue = np.empty((), 'O')
     ...: fillvalue[()] = [0, 0]
     ...: 
In [323]: fillvalue
Out[323]: array(list([0, 0]), dtype=object)
In [324]: mask
Out[324]: 
array([[False, False,  True],
       [ True, False, False],
       [False,  True, False]])
In [325]: pivot_table[mask] = fillvalue

他的fullnp.copyto(a, fill_value, casting='unsafe') , 我们的屏蔽作业可以写成:np.copyto(pivot_table, fillvalue, where=mask)

关于python - Numpy:用 numpy 数组替换 numpy 数组中的零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53450669/

相关文章:

python - 有效地生成所有排列

python - 排序方法 : The truth value of an array with more than one element is ambiguous. 使用 a.any() 或 a.all()

r - 计算 R 中矩阵行的总和

java - 给定网格的一些节点,查找飞机在网格上的位置

mysql - 如何存储和查询大量的矩阵?

python - 为什么我在 python moviepy 中使用 CompositeAudioClip 时没有声音?

python - 如何将连续变量转换为分类变量?

python - 在 Python 中处理字节和二进制数据

python - 在 Python 中用空格替换 nan

python - 如何有效地向量化超几何 CDF 计算?