在给定索引 np.argwhere() 的情况下替换 n 维张量中的值
Replacing values in n-dimensional tensor given indices from np.argwhere()
我对 numpy 有点陌生,所以这可能是一个愚蠢的问题,但这里是:
假设我有一个任意形状和大小的张量,例如 (100,5,5)
或 (3,3,10,15,4)
。我有一个随机生成的索引列表,用于要用 np.nan
替换的点。对于 (3,3,3)
测试用例,它将如下所示:
>> data = np.random.randn(3,3,3)
>> data
array([[[ 0.21368315, -1.42814113, 1.23021783],
[ 0.25835315, 0.44775156, -1.20489094],
[ 0.25928972, 0.39486046, -1.79189447]],
[[ 2.24080908, -0.89617961, -0.29550817],
[ 0.21756087, 1.33996913, -1.24418745],
[-0.63617598, 0.56848439, 0.8175564 ]],
[[ 0.61367002, -1.16104071, -0.53488283],
[ 1.0363354 , -0.76888041, 1.24524786],
[-0.84329375, -0.61744489, 1.50502058]]])
>> idxs = np.argwhere(np.isfinite(data))
>> dropidxs = idxs[np.random.choice(idxs.shape[0], 3, replace=False)]
>> dropidxs
array([[1, 1, 1],
[2, 0, 2],
[2, 1, 0]])
如何替换相应的值?以前,当我只处理 3D 案例时,我使用以下方法来完成。
for idx in dropidxs:
i,j,k = dropidxs[idx]
missingCube[i,j,k] = np.nan
但现在,我希望函数能够处理任何大小的张量。
我试过了
for idx in dropidxs:
missingCube[idx] = np.nan
和
missingCube[dropidxs] = np.nan
但两者(不出所料)最终都会沿着 axis=0
删除相应的切片。我应该如何处理这个问题?有没有更简单的方法来实现我想要做的事情?
是不是你要找的:
import numpy as np
x = np.random.randn(10, 3, 3, 3)
new_value = 0
x[x < 0] = new_value
或
x[x == -inf] = 0
您可以选择扁平化索引并转换回 data 索引以将元素设置为 np.nan
。这里有一个种子 (41) 使结果可重现,选择 3 个元素。
import numpy as np
data = np.random.randn(3,3,3)
rng = np.random.default_rng(41)
idx = rng.choice(np.arange(data.size), 3, replace=False)
data[np.unravel_index(idx, data.shape)] = np.nan
data
输出
array([[[ 0.13180452, -0.81228319, -0.04456739],
[ 0.53060077, -0.2246579 , 1.83926463],
[-0.38670047, -0.53703577, 0.49275628]],
[[ 0.36671354, 1.44012848, -0.57209412],
[ 0.53960111, -1.06578638, 1.10669842],
[ 1.1772824 , nan, -0.82792041]],
[[-0.03352594, 0.29351109, 0.57021538],
[-0.33291872, nan, 0.04675677],
[ nan, 2.59450517, -1.9579655 ]]])
In [486]: data = np.random.randn(3,3,3)
有了这个创建,所有项都是有限的,所以 nonzero
returns (27,) 数组的元组:
In [487]: idx = np.nonzero(np.isfinite(data))
In [488]: len(idx)
Out[488]: 3
In [489]: idx[0].shape
Out[489]: (27,)
argwhere
产生相同的数字,但在二维数组中:
In [490]: idxs = np.argwhere(np.isfinite(data))
In [491]: idxs.shape
Out[491]: (27, 3)
所以你 select 一个子集。
In [492]: dropidxs = idxs[np.random.choice(idxs.shape[0], 3, replace=False)]
In [493]: dropidxs.shape
Out[493]: (3, 3)
In [494]: dropidxs
Out[494]:
array([[1, 1, 0],
[2, 1, 2],
[2, 1, 1]])
我们可以通过 x = np.random.choice(...)
生成相同的子集,并将 x
应用于 idxs
中的数组。但在这种情况下,argwhere 数组更易于使用。
但是要将该数组应用于索引,我们仍然需要一个数组元组:
In [495]: tup = tuple([dropidxs[:,i] for i in range(3)])
In [496]: tup
Out[496]: (array([1, 2, 2]), array([1, 1, 1]), array([0, 2, 1]))
In [497]: data[tup]
Out[497]: array([-0.27965058, 1.2981397 , 0.4501406 ])
In [498]: data[tup]=np.nan
In [499]: data
Out[499]:
array([[[-0.4899279 , 0.83352547, -1.03798762],
[-0.91445783, 0.05777183, 0.19494065],
[ 0.6835925 , -0.47846423, 0.13513958]],
[[-0.08790631, 0.30224828, -0.39864576],
[ nan, -0.77424244, 1.4788093 ],
[ 0.41915952, -0.09335664, -0.47359613]],
[[-0.40281937, 1.64866377, -0.40354504],
[ 0.74884493, nan, nan],
[ 0.13097487, -1.63995208, -0.98857852]]])
或者我们可以索引:
In [500]: data[dropidxs[:,0],dropidxs[:,1],dropidxs[:,2]]
Out[500]: array([nan, nan, nan])
实际上,dropidxs
的转置可能更方便:
In [501]: tdrop = dropidxs.T
In [502]: tuple(tdrop)
Out[502]: (array([1, 2, 2]), array([1, 1, 1]), array([0, 2, 1]))
In [503]: data[tuple(tdrop)]
Out[503]: array([nan, nan, nan])
有时候我们可以用*
把一个list/array展开成一个元组,但是在索引的时候不行:
In [504]: data[*tdrop]
File "<ipython-input-504-cb619d907adb>", line 1
data[*tdrop]
^
SyntaxError: invalid syntax
但我们可以创建元组:
In [506]: data[(*tdrop,)]
Out[506]: array([nan, nan, nan])
我对 numpy 有点陌生,所以这可能是一个愚蠢的问题,但这里是:
假设我有一个任意形状和大小的张量,例如 (100,5,5)
或 (3,3,10,15,4)
。我有一个随机生成的索引列表,用于要用 np.nan
替换的点。对于 (3,3,3)
测试用例,它将如下所示:
>> data = np.random.randn(3,3,3)
>> data
array([[[ 0.21368315, -1.42814113, 1.23021783],
[ 0.25835315, 0.44775156, -1.20489094],
[ 0.25928972, 0.39486046, -1.79189447]],
[[ 2.24080908, -0.89617961, -0.29550817],
[ 0.21756087, 1.33996913, -1.24418745],
[-0.63617598, 0.56848439, 0.8175564 ]],
[[ 0.61367002, -1.16104071, -0.53488283],
[ 1.0363354 , -0.76888041, 1.24524786],
[-0.84329375, -0.61744489, 1.50502058]]])
>> idxs = np.argwhere(np.isfinite(data))
>> dropidxs = idxs[np.random.choice(idxs.shape[0], 3, replace=False)]
>> dropidxs
array([[1, 1, 1],
[2, 0, 2],
[2, 1, 0]])
如何替换相应的值?以前,当我只处理 3D 案例时,我使用以下方法来完成。
for idx in dropidxs:
i,j,k = dropidxs[idx]
missingCube[i,j,k] = np.nan
但现在,我希望函数能够处理任何大小的张量。 我试过了
for idx in dropidxs:
missingCube[idx] = np.nan
和
missingCube[dropidxs] = np.nan
但两者(不出所料)最终都会沿着 axis=0
删除相应的切片。我应该如何处理这个问题?有没有更简单的方法来实现我想要做的事情?
是不是你要找的:
import numpy as np
x = np.random.randn(10, 3, 3, 3)
new_value = 0
x[x < 0] = new_value
或
x[x == -inf] = 0
您可以选择扁平化索引并转换回 data 索引以将元素设置为 np.nan
。这里有一个种子 (41) 使结果可重现,选择 3 个元素。
import numpy as np
data = np.random.randn(3,3,3)
rng = np.random.default_rng(41)
idx = rng.choice(np.arange(data.size), 3, replace=False)
data[np.unravel_index(idx, data.shape)] = np.nan
data
输出
array([[[ 0.13180452, -0.81228319, -0.04456739],
[ 0.53060077, -0.2246579 , 1.83926463],
[-0.38670047, -0.53703577, 0.49275628]],
[[ 0.36671354, 1.44012848, -0.57209412],
[ 0.53960111, -1.06578638, 1.10669842],
[ 1.1772824 , nan, -0.82792041]],
[[-0.03352594, 0.29351109, 0.57021538],
[-0.33291872, nan, 0.04675677],
[ nan, 2.59450517, -1.9579655 ]]])
In [486]: data = np.random.randn(3,3,3)
有了这个创建,所有项都是有限的,所以 nonzero
returns (27,) 数组的元组:
In [487]: idx = np.nonzero(np.isfinite(data))
In [488]: len(idx)
Out[488]: 3
In [489]: idx[0].shape
Out[489]: (27,)
argwhere
产生相同的数字,但在二维数组中:
In [490]: idxs = np.argwhere(np.isfinite(data))
In [491]: idxs.shape
Out[491]: (27, 3)
所以你 select 一个子集。
In [492]: dropidxs = idxs[np.random.choice(idxs.shape[0], 3, replace=False)]
In [493]: dropidxs.shape
Out[493]: (3, 3)
In [494]: dropidxs
Out[494]:
array([[1, 1, 0],
[2, 1, 2],
[2, 1, 1]])
我们可以通过 x = np.random.choice(...)
生成相同的子集,并将 x
应用于 idxs
中的数组。但在这种情况下,argwhere 数组更易于使用。
但是要将该数组应用于索引,我们仍然需要一个数组元组:
In [495]: tup = tuple([dropidxs[:,i] for i in range(3)])
In [496]: tup
Out[496]: (array([1, 2, 2]), array([1, 1, 1]), array([0, 2, 1]))
In [497]: data[tup]
Out[497]: array([-0.27965058, 1.2981397 , 0.4501406 ])
In [498]: data[tup]=np.nan
In [499]: data
Out[499]:
array([[[-0.4899279 , 0.83352547, -1.03798762],
[-0.91445783, 0.05777183, 0.19494065],
[ 0.6835925 , -0.47846423, 0.13513958]],
[[-0.08790631, 0.30224828, -0.39864576],
[ nan, -0.77424244, 1.4788093 ],
[ 0.41915952, -0.09335664, -0.47359613]],
[[-0.40281937, 1.64866377, -0.40354504],
[ 0.74884493, nan, nan],
[ 0.13097487, -1.63995208, -0.98857852]]])
或者我们可以索引:
In [500]: data[dropidxs[:,0],dropidxs[:,1],dropidxs[:,2]]
Out[500]: array([nan, nan, nan])
实际上,dropidxs
的转置可能更方便:
In [501]: tdrop = dropidxs.T
In [502]: tuple(tdrop)
Out[502]: (array([1, 2, 2]), array([1, 1, 1]), array([0, 2, 1]))
In [503]: data[tuple(tdrop)]
Out[503]: array([nan, nan, nan])
有时候我们可以用*
把一个list/array展开成一个元组,但是在索引的时候不行:
In [504]: data[*tdrop]
File "<ipython-input-504-cb619d907adb>", line 1
data[*tdrop]
^
SyntaxError: invalid syntax
但我们可以创建元组:
In [506]: data[(*tdrop,)]
Out[506]: array([nan, nan, nan])