Python 在嵌套字典的锯齿状列表中使用
我有一个很大的嵌套字典,其中有锯齿状列表“c”:Python 在嵌套字典的锯齿状列表中使用,python,dictionary,jagged-arrays,awkward-array,Python,Dictionary,Jagged Arrays,Awkward Array,我有一个很大的嵌套字典,其中有锯齿状列表“c”: x = {'first_block': {'unit1': {'a': (3,5,4), 'b': 23, 'c': [10]}, 'unit2': {'a': (5,8,7), 'b': 15, 'c': [20,10]}, 'unit10k': {'a': (2,4,9), 'b': 10, 'c': [6,10,20,5]}}, 'second_block':
x = {'first_block':
{'unit1': {'a': (3,5,4), 'b': 23, 'c': [10]},
'unit2': {'a': (5,8,7), 'b': 15, 'c': [20,10]},
'unit10k': {'a': (2,4,9), 'b': 10, 'c': [6,10,20,5]}},
'second_block':
{'unit1' : {'a': (8,20,14), 'b': 10, 'c': [17,12,9]},
'unit2' : {'a': (9,25,50), 'b': 15, 'c': [17,15,9,4,12]},
'unit12k': {'a': (12,24,9), 'b': 23, 'c': [12,22,15,4]}},
'millionth_block':
{'unit1': {'a': (35,64,85), 'b': 64, 'c': [50]},
'unit2': {'a': (56,23,34), 'b': 55, 'c': [89,59,77]},
'unit5k': {'a': (90,28,12), 'b': 85, 'c': [48,90,27,59]}}}
“c”的元素是点标签
对于“c”中的每个唯一点标签,我希望生成“b”中相应值的过滤列表
例如,“first_block”在“c”中有唯一的元素:5,6,10,20
我想获得/提取每个“块”的以下列表,以列出与“c”中特定值相关的“b”的每个值,例如
first_block:
5: [10]
6: [10]
10: [10,15,23]
20: [10,15]
second_block:
4: [15,23]
9: [10,15]
12: [10,15,23]
15: [15,23]
17: [10,15]
22: [23]
etc.
考虑到“c”是参差不齐的,你对如何创造这种结果有什么想法吗
我们一直试图通过转换为笨拙的数组来实现这一点,但目前文档很少,而且真的不知道如何在笨拙的数组中实现这一点
也可以接受不涉及尴尬的pythonic建议。试试这个,它可以完全复制您想要的内容(包括排序) 输出:
first_block
5 [10]
6 [10]
10 [23, 15, 10]
20 [15, 10]
second_block
4 [15, 23]
9 [10, 15]
12 [10, 15, 23]
15 [15, 23]
17 [10, 15]
22 [23]
millionth_block
27 [85]
48 [85]
50 [64]
59 [55, 85]
77 [55]
89 [55]
90 [85]
试试这个,它会完全复制您想要的内容(包括排序) 输出:
first_block
5 [10]
6 [10]
10 [23, 15, 10]
20 [15, 10]
second_block
4 [15, 23]
9 [10, 15]
12 [10, 15, 23]
15 [15, 23]
17 [10, 15]
22 [23]
millionth_block
27 [85]
48 [85]
50 [64]
59 [55, 85]
77 [55]
89 [55]
90 [85]
我将尝试给出一个笨拙的数组解决方案 首先,我们需要知道数据集中的哪些内容是真正的扩展。我知道您可能有数百万个块,但这意味着您不应该使用具有唯一字符串值键的dict来表示它们。创建字符串、比较字符串和按字符串查找内容的成本(尽管dict的哈希表对这一点有很大帮助)不是一种扩展的好方法,尤其是当这些字符串中的唯一信息是排序时 在我看来,单位的数量也是可变的(因为最后一个单位被命名为“unit10k”、“unit12k”和“unit5k”) 最后,我重新阅读了您的问题陈述,但似乎名为“a”的字段没有进入问题。我不理它 因此,我认为您的数据结构会更好:
as_python=[
#第一街区
[
#第一单元
{“b”:23,“c”:[10]},
#第二单元
{“b”:15,“c”:[20,10]},
# ...
#第10k单元
{“b”:10,“c”:[6,10,20,5]},
],
#第二街区
[
#第一单元
{“b”:10,“c”:[17,12,9]},
#第二单元
{“b”:15,“c”:[17,15,9,4,12]},
# ...
#第12k单元
{“b”:23,“c”:[12,22,15,4]},
],
# ...
#第百万块
[
#第一单元
{“b”:64,“c”:[50]},
#第二单元
{“b”:55,“c”:[89,59,77]},
# ...
#第15k单元
{“b”:85,“c”:[48,90,27,59]},
],
]
解决这个问题的一个办法是
results=[]
对于as_python中的块:
块_结果={}
对于块中的单元:
b=单位[“b”]#只查找b一次
对于单位[“c”]中的c:
如果c不在块_结果中:
块_结果[c]=[]
块结果[c]。追加(b)
results.append(block_result)
导致
[
{10: [23, 15, 10], 20: [15, 10], 6: [10], 5: [10]},
{17: [10, 15], 12: [10, 15, 23], 9: [10, 15], 15: [15, 23], 4: [15, 23], 22: [23]},
{50: [64], 89: [55], 59: [55, 85], 77: [55], 48: [85], 90: [85], 27: [85]},
]
这应该很快。(对于未编译、动态类型的虚拟机,仅使用内置Python类型的短循环速度惊人。根据我的经验,仅使用内置Python类型是关键。)
至于笨拙的数组,在调用Numba(JIT compiledfor
loops)之前,我只能使用向量化(即“NumPy-like”)操作完成一半,这表明库需要一个“groupby”函数
当然,您可以在Numba中完成全部工作,这通常是最快的解决方案,但这个问题主要取决于分组和唯一性,在Python中,分组和唯一性最自然地由dict或set完成,但是很难让Numba推断出除纯数字和数组之外的任何类型。(为了JIT编译代码并使之快速,Numba必须知道它们的类型,但是Python类型注释是最新的,它们仍然被合并到Numba中。)
因此,让我们先把上面的数据结构变成一个笨拙的数组。根据您的数据源,有不同的方法来实现这一点(已完成),但我将让ak.Array
迭代上述Python数据结构
>>作为ak导入
>>>as_笨拙=ak.Array(as_python)
通常,如果我们有一个“X和Y的所有组合”问题,我们希望使用。我们不能马上使用它,因为“b”数据和“c”数据有不同的深度:
>>as_ouk=ak.Array(as_python)
>>>b.很尴尬
并记录在案。我们最终希望将这些b-c对按c分组,我们至少可以对它们进行排序:
排序=展平[ak.argsort(flatted.c,axis=-1)]
>>>分类
所以在这一点上,我们切换到Numba。这个问题比原来的问题简单得多,因为要分组的数据已经被排序了:我们只需要查看值何时更改为插入边界。笨拙的数组可以作为参数传递给Numba,但它们是不可变的。要创建新阵列,请使用。注意:在开发这样的函数时,请分小步进行,并删除@nb.njit
,以便在不进行JIT编译的情况下进行尝试(确保在尝试解决类型错误之前所做的操作是正确的)
将numba作为nb导入
@nb.njit
def分组依据(输入、输出):
对于输入中的块:
output.begin_list()
output.begin_list()
last=block[0]。c#注意:假设len(block)>=1
对于块中的单元:
如果单位为c!=最后:
output.end_list()
output.begin_list()
输出追加(单位)
最后=单位c
output.end_list()
output.end_list()
返回输出
input
是我们刚刚创建的数组(sorted
),而output
是一个数组生成器,它可以转换为int
x = {'first_block':
{'unit1': {'a': (3,5,4), 'b': 23, 'c': [10]},
'unit2': {'a': (5,8,7), 'b': 15, 'c': [20,10]},
'unit10k': {'a': (2,4,9), 'b': 10, 'c': [6,10,20,5]}},
'second_block':
{'unit1' : {'a': (8,20,14), 'b': 10, 'c': [17,12,9]},
'unit2' : {'a': (9,25,50), 'b': 15, 'c': [17,15,9,4,12]},
'unit12k': {'a': (12,24,9), 'b': 23, 'c': [12,22,15,4]}},
'millionth_block':
{'unit1': {'a': (35,64,85), 'b': 64, 'c': [50]},
'unit2': {'a': (56,23,34), 'b': 55, 'c': [89,59,77]},
'unit5k': {'a': (90,28,12), 'b': 85, 'c': [48,90,27,59]}}}
result = {};
for blocks in x.keys():
cs = {};
for unit in x[blocks].keys():
for c in x[blocks][unit]['c']:
#retrieve array of b value for the c key or take [], then concat the b value, then apply set function to remove double, then convert to list
cs[str(c)] = list(set(((cs.get(str(c)) or []) + [x[blocks][unit]['b']])))
result[blocks] = cs;
print(result);