Python Numpy:用Numpy数组替换Numpy数组中的零
处理我想要透视的数据。请注意,我仅限于numpy,无法使用熊猫。原始数据如下所示:Python Numpy:用Numpy数组替换Numpy数组中的零,python,numpy,matrix,Python,Numpy,Matrix,处理我想要透视的数据。请注意,我仅限于numpy,无法使用熊猫。原始数据如下所示: data = [ [ 1, a, [<metric1>, <metric2>] ], [ 1, b, [<metric1>, <metric2>] ], [ 2, b, [<metric1>, <metric2>] ], [ 2, c, [<metric1>, <metric2>] ], [ 3,
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
]
结果格式为:
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>], ... ],
...
]
但我得到了以下错误:
TypeError: NumPy boolean array indexing assignment requires a 0 or 1-dimensional input, input has 2 dimensions
我的临时修复已经足够了,但是当我想做一些事情时,比如有一行列和时,我的修复是有限的。我有很多方法,但不知道如何执行:
np.unique
中的索引创建表时,使用默认值来填充表,而不是零[1,a,]
。这可能是简化聚合函数的最佳解决方案上述任何一种方法都有解决方案吗?尝试重新创建您的案例:
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,)匹配之间工作
在过去,我成功地使用
frompyfunc
创建对象数据类型数组。定义一个小函数。我本可以测试0或类型,但因为我已经插入了0或类型,所以让我们测试一下:
In [205]: def fun(x):
...: if x is None: return [0,0]
...: return x
将其应用于透视表的每个元素,生成一个新数组
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
但是如果我在中尝试同样的方法,它会起作用:
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\u表的原始分配
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
通常,布尔掩码索引的行为类似于等价的np。其中(mask)
索引,但很明显,在这里,对象数据类型和广播的相互作用会扰乱布尔索引
Out[231]
仍然是一个(3,3)数组,即使列有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
版本)可以将列表连接到一个数组中,但它必须从一个列表或平面数组开始,因此需要展开和重新成形
np.array(pivot\u table.tolist())
也可以工作
相反,如果您构建了结构化数据数组(假设度量值为数值):
使用Paul Panzer定义的fillvalue
数组,您的初始屏蔽分配工作:
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
他的full
执行np.copyto(a,fill\u值,casting='safe')
,
我们的蒙版作业可以写成:np.copyto(pivot\u table,fillvalue,where=mask)
您的输入数据类型不清楚,可能会造成不便。避免对象类型有助于数据结构分析。使用结构化阵列有助于:
原始数据样本:
n=10
data= [ [randint(5),'abcdef'[randint(6)],rand(2)] for _ in range(n)]
手动键入和填写:
dt=np.dtype([('i', 'i4'), ('j', 'U1'), ('val', 'f8', 2)])
arr = ndarray(len(data),dtype=dt)
for k,(a,b,c) in enumerate (data):
arr[k]['i']=a
arr[k]['j']=b
arr[k]['val']=c
现在一切都很简单:
row=arr['i']
col=arr['j']
val=arr['val']
(r,ri),(c,ci) = (np.unique(x,return_inverse=True) for x in (row,col))
res=zeros((len(r),len(c),2)) # the good shape
res[ri,ci]=val
res现在是
[[[ 0.87 0.96]
[ 0.03 0.92]
[ 0.45 0.55]
[ 0. 0. ]
[ 0. 0. ]]
[[ 0.27 0.84]
[ 0. 0. ]
[ 0.41 0.05]
[ 0.47 0.67]
[ 0. 0. ]]
[[ 0.3 0.05]
[ 0. 0. ]
[ 0. 0. ]
[ 0. 0. ]
[ 0.37 0.76]]
[[ 0. 0. ]
[ 0. 0. ]
[ 0. 0. ]
[ 0. 0. ]
[ 0.4 0.07]]]
以下是如何让您的方法2发挥作用:
fillvalue = np.empty((), 'O')
fillvalue[()] = [0, 0]
pivot_table = np.full((len(rows), len(cols)), fillvalue)
etc.
请注意,[0,0]
都是同一个对象,因此,如果要更改其中一个对象,不应通过修改列表对象来完成,而应创建一个新列表并将其指定给数组位置
如果您想要一个3D数字数组而不是列表数组,那么快速修复方法是np.array(pivot\u table.tolist())
查看pivot\u table[pivot\u table==0]
。它可能是一个0的1d数组。将标量或类似None
的对象指定给这些位置应该可以正常工作。但分配一份清单将是一件棘手的事情numpy
将列表转换为ndarray
,然后尝试应用广播。一般来说将列表分配给对象数组的单个元素效果很好,但分配给多个元素却很困难。虽然它不是0的1d数组。它们显示为每个项目的列表([metric1,metric2])
。我试着只使用一个标准的2D数组,但这样我只能旋转其中一个指标。我想一个解决方案是为每个度量创建单独的表,然后将它们合并为一个。任何数组的布尔掩码都会生成一个1d数组。对于对象,原始掩码赋值有效,pivot\u table[pivot\u table==0]=fillvalue
。对就地修改同样要小心。这很有用,但不幸的是,我的前两列具有可变长度,因此它不适用于所有数据用例。错误不同,因为我的错误来自动态生成np.zero((1,len(numMetrics)))
。直接分配[0,0]
时,我会遇到类似的错误,尽管我使用的是早期版本(由于标准的Google应用程序引擎限制)。您的一些初始解决方案在动态大小度量方面存在问题,或者由于数据本身的原因,无法构建数据类型。最后一个使用fillvalue
的解决方案成功了。您没有提供一个解决方案,因此我不得不临时修改,使数据
大致符合您的描述。正如您从答案中看到的,我们更喜欢使用真正的工作代码,而不仅仅是泛型描述。在编写伪代码时很容易出错。这是公平的,我感谢您提供的全面和大量的答案,只是想让您知道什么对我有效,什么对我无效。我确实需要对我的公司数据进行一些概括,但我会确保提供一些能够代表我未来问题的示例(我真的没有料到数据的dtype
会产生如此大的影响)
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
n=10
data= [ [randint(5),'abcdef'[randint(6)],rand(2)] for _ in range(n)]
dt=np.dtype([('i', 'i4'), ('j', 'U1'), ('val', 'f8', 2)])
arr = ndarray(len(data),dtype=dt)
for k,(a,b,c) in enumerate (data):
arr[k]['i']=a
arr[k]['j']=b
arr[k]['val']=c
row=arr['i']
col=arr['j']
val=arr['val']
(r,ri),(c,ci) = (np.unique(x,return_inverse=True) for x in (row,col))
res=zeros((len(r),len(c),2)) # the good shape
res[ri,ci]=val
[[[ 0.87 0.96]
[ 0.03 0.92]
[ 0.45 0.55]
[ 0. 0. ]
[ 0. 0. ]]
[[ 0.27 0.84]
[ 0. 0. ]
[ 0.41 0.05]
[ 0.47 0.67]
[ 0. 0. ]]
[[ 0.3 0.05]
[ 0. 0. ]
[ 0. 0. ]
[ 0. 0. ]
[ 0.37 0.76]]
[[ 0. 0. ]
[ 0. 0. ]
[ 0. 0. ]
[ 0. 0. ]
[ 0.4 0.07]]]
fillvalue = np.empty((), 'O')
fillvalue[()] = [0, 0]
pivot_table = np.full((len(rows), len(cols)), fillvalue)
etc.