根据字典替换笨拙数组中的值的有效方法?
Efficient method to replace values in awkward array according to a dictionary?
我有一本包含整数键和浮点值的字典。
我还有一个带有整数条目的二维笨拙数组(我使用的是笨拙的 1)。
我想根据字典将这些整数替换为相应的浮点数,保持尴尬的数组格式。
假设键 运行 从 0 到 999,到目前为止我的解决方案是这样的:
resultArray = ak.where(myArray == 0, myDict.get(0), 0)
for key in range(1,1000):
resultArray = resultArray + ak.where(myArray == key, myDict.get(key), 0)
有更快的方法吗?
更新
我的工作代码的最小可重现示例:
import awkward as ak # Awkward 1
myArray = ak.from_iter([[0, 1], [2, 1, 0]]) # Creating example array
myDict = {0: 19.5, 1: 34.1, 2: 10.9}
resultArray = ak.where(myArray == 0, myDict.get(0), 0)
for key in range(1,3):
resultArray = resultArray + ak.where(myArray == key, myDict.get(key), 0)
我的数组:
<Array [[0, 1], [2, 1, 0]] type='2 * var * int64'>
结果数组:
<Array [[19.5, 34.1], [10.9, 34.1, 19.5]] type='2 * var * float64'>
当我在评论中提到 np.searchsorted 是您应该查看的位置时,我没有注意到 myDict
包含每个连续的整数作为键。像这样进行密集查找 table 将允许更快的算法,这在 Awkward Array 中也恰好更简单。
因此,假设从 0
到某个值的每个整数在 myDict
中都有一个键,您同样可以将查找 table 表示为
>>> lookup = ak.Array([myDict[i] for i in range(len(myDict))])
>>> lookup
<Array [19.5, 34.1, 10.9] type='3 * float64'>
在 0
、1
和 2
处选取值的问题变成了一个数组切片。 (这个数组切片是数组长度 n 的 O(n) 算法,不像 np.searchsorted
,后者是 O(n log n)。这是使用稀疏查找键的代价。)
但是,问题是 myArray
是嵌套的,而 lookup
不是。我们可以通过将 lookup
切片来提供与 myArray
相同的深度:
>>> multilookup = lookup[np.newaxis][np.zeros(len(myArray), np.int64)]
>>> multilookup
<Array [[19.5, 34.1, 10.9, ... 34.1, 10.9]] type='2 * 3 * float64'>
>>> multilookup.tolist()
[[19.5, 34.1, 10.9], [19.5, 34.1, 10.9]]
然后multilookup[myArray]
正是你想要的:
>>> multilookup[myArray]
<Array [[19.5, 34.1], [10.9, 34.1, 19.5]] type='2 * var * float64'>
必须重复查找,因为 myArray
中的每个列表都使用整个 lookup
中的全局索引。如果创建 multilookup
所涉及的内存过高,您可以改为分解 myArray
以匹配它:
>>> flattened, num = ak.flatten(myArray), ak.num(myArray)
>>> flattened
<Array [0, 1, 2, 1, 0] type='5 * int64'>
>>> num
<Array [2, 3] type='2 * int64'>
>>> lookup[flattened]
<Array [19.5, 34.1, 10.9, 34.1, 19.5] type='5 * float64'>
>>> ak.unflatten(lookup[flattened], nums)
<Array [[19.5, 34.1], [10.9, 34.1, 19.5]] type='2 * var * float64'>
如果您的密钥从 0
到某个整数不密集,那么您将不得不使用 np.searchsorted
:
>>> keys = ak.Array(myDict.keys())
>>> values = ak.Array([myDict[key] for key in keys])
>>> keys
<Array [0, 1, 2] type='3 * int64'>
>>> values
<Array [19.5, 34.1, 10.9] type='3 * float64'>
在这种情况下,keys
是微不足道的,因为它 是 密集的。使用 np.searchsorted
时,您必须将扁平的 Awkward Arrays 显式转换为 NumPy(目前;我们正在寻求修复)。
>>> lookup_index = np.searchsorted(np.asarray(keys), np.asarray(flattened), side="left")
>>> lookup_index
array([0, 1, 2, 1, 0])
然后我们通过简单的 keys
传递它(在这种情况下不会改变它),然后再传递给 values
.
>>> keys[lookup_index]
<Array [0, 1, 2, 1, 0] type='5 * int64'>
>>> values[keys[lookup_index]]
<Array [19.5, 34.1, 10.9, 34.1, 19.5] type='5 * float64'>
>>> ak.unflatten(values[keys[lookup_index]], num)
<Array [[19.5, 34.1], [10.9, 34.1, 19.5]] type='2 * var * float64'>
但我在昨天的评论中胡说八道的是,你必须在 myArray
(flattened
) 的扁平化形式上执行此操作,并在稍后重新引入结构 ak.unflatten,如上。但也许我们至少应该将 np.searchsorted
包装为 ak.searchsorted
以识别 second 参数中的完全结构化的尴尬数组。 (它必须是非结构化的才能出现在第一个参数中。)
我有一本包含整数键和浮点值的字典。 我还有一个带有整数条目的二维笨拙数组(我使用的是笨拙的 1)。 我想根据字典将这些整数替换为相应的浮点数,保持尴尬的数组格式。
假设键 运行 从 0 到 999,到目前为止我的解决方案是这样的:
resultArray = ak.where(myArray == 0, myDict.get(0), 0)
for key in range(1,1000):
resultArray = resultArray + ak.where(myArray == key, myDict.get(key), 0)
有更快的方法吗?
更新
我的工作代码的最小可重现示例:
import awkward as ak # Awkward 1
myArray = ak.from_iter([[0, 1], [2, 1, 0]]) # Creating example array
myDict = {0: 19.5, 1: 34.1, 2: 10.9}
resultArray = ak.where(myArray == 0, myDict.get(0), 0)
for key in range(1,3):
resultArray = resultArray + ak.where(myArray == key, myDict.get(key), 0)
我的数组:
<Array [[0, 1], [2, 1, 0]] type='2 * var * int64'>
结果数组:
<Array [[19.5, 34.1], [10.9, 34.1, 19.5]] type='2 * var * float64'>
当我在评论中提到 np.searchsorted 是您应该查看的位置时,我没有注意到 myDict
包含每个连续的整数作为键。像这样进行密集查找 table 将允许更快的算法,这在 Awkward Array 中也恰好更简单。
因此,假设从 0
到某个值的每个整数在 myDict
中都有一个键,您同样可以将查找 table 表示为
>>> lookup = ak.Array([myDict[i] for i in range(len(myDict))])
>>> lookup
<Array [19.5, 34.1, 10.9] type='3 * float64'>
在 0
、1
和 2
处选取值的问题变成了一个数组切片。 (这个数组切片是数组长度 n 的 O(n) 算法,不像 np.searchsorted
,后者是 O(n log n)。这是使用稀疏查找键的代价。)
但是,问题是 myArray
是嵌套的,而 lookup
不是。我们可以通过将 lookup
切片来提供与 myArray
相同的深度:
>>> multilookup = lookup[np.newaxis][np.zeros(len(myArray), np.int64)]
>>> multilookup
<Array [[19.5, 34.1, 10.9, ... 34.1, 10.9]] type='2 * 3 * float64'>
>>> multilookup.tolist()
[[19.5, 34.1, 10.9], [19.5, 34.1, 10.9]]
然后multilookup[myArray]
正是你想要的:
>>> multilookup[myArray]
<Array [[19.5, 34.1], [10.9, 34.1, 19.5]] type='2 * var * float64'>
必须重复查找,因为 myArray
中的每个列表都使用整个 lookup
中的全局索引。如果创建 multilookup
所涉及的内存过高,您可以改为分解 myArray
以匹配它:
>>> flattened, num = ak.flatten(myArray), ak.num(myArray)
>>> flattened
<Array [0, 1, 2, 1, 0] type='5 * int64'>
>>> num
<Array [2, 3] type='2 * int64'>
>>> lookup[flattened]
<Array [19.5, 34.1, 10.9, 34.1, 19.5] type='5 * float64'>
>>> ak.unflatten(lookup[flattened], nums)
<Array [[19.5, 34.1], [10.9, 34.1, 19.5]] type='2 * var * float64'>
如果您的密钥从 0
到某个整数不密集,那么您将不得不使用 np.searchsorted
:
>>> keys = ak.Array(myDict.keys())
>>> values = ak.Array([myDict[key] for key in keys])
>>> keys
<Array [0, 1, 2] type='3 * int64'>
>>> values
<Array [19.5, 34.1, 10.9] type='3 * float64'>
在这种情况下,keys
是微不足道的,因为它 是 密集的。使用 np.searchsorted
时,您必须将扁平的 Awkward Arrays 显式转换为 NumPy(目前;我们正在寻求修复)。
>>> lookup_index = np.searchsorted(np.asarray(keys), np.asarray(flattened), side="left")
>>> lookup_index
array([0, 1, 2, 1, 0])
然后我们通过简单的 keys
传递它(在这种情况下不会改变它),然后再传递给 values
.
>>> keys[lookup_index]
<Array [0, 1, 2, 1, 0] type='5 * int64'>
>>> values[keys[lookup_index]]
<Array [19.5, 34.1, 10.9, 34.1, 19.5] type='5 * float64'>
>>> ak.unflatten(values[keys[lookup_index]], num)
<Array [[19.5, 34.1], [10.9, 34.1, 19.5]] type='2 * var * float64'>
但我在昨天的评论中胡说八道的是,你必须在 myArray
(flattened
) 的扁平化形式上执行此操作,并在稍后重新引入结构 ak.unflatten,如上。但也许我们至少应该将 np.searchsorted
包装为 ak.searchsorted
以识别 second 参数中的完全结构化的尴尬数组。 (它必须是非结构化的才能出现在第一个参数中。)